diff --git a/package.json b/package.json index 6caa9929..33b39435 100644 --- a/package.json +++ b/package.json @@ -84,6 +84,7 @@ "rimraf": "3.0.2", "sinon": "11.1.1", "source-map-resolve": "0.6.0", + "terser": "^5.7.1", "threads": "1.6.5", "ts-loader": "9.2.3", "ts-node": "10.1.0", diff --git a/src/custom-code-helpers/string-array/StringArrayCallsWrapperBase64CodeHelper.ts b/src/custom-code-helpers/string-array/StringArrayCallsWrapperBase64CodeHelper.ts index e1abffc3..80afd3e4 100644 --- a/src/custom-code-helpers/string-array/StringArrayCallsWrapperBase64CodeHelper.ts +++ b/src/custom-code-helpers/string-array/StringArrayCallsWrapperBase64CodeHelper.ts @@ -13,9 +13,12 @@ export class StringArrayCallsWrapperBase64CodeHelper extends StringArrayCallsWra protected override getDecodeStringArrayTemplate (): string { const atobFunctionName: string = this.randomGenerator.getRandomString(6); - const atobPolyfill: string = this.customCodeHelperFormatter.formatTemplate(AtobTemplate(), { - atobFunctionName: atobFunctionName - }); + const atobPolyfill: string = this.customCodeHelperFormatter.formatTemplate( + AtobTemplate(this.options.selfDefending), + { + atobFunctionName: atobFunctionName + } + ); const selfDefendingCode: string = this.getSelfDefendingTemplate(); diff --git a/src/custom-code-helpers/string-array/StringArrayCallsWrapperRc4CodeHelper.ts b/src/custom-code-helpers/string-array/StringArrayCallsWrapperRc4CodeHelper.ts index 6562bcaf..c1ce13a8 100644 --- a/src/custom-code-helpers/string-array/StringArrayCallsWrapperRc4CodeHelper.ts +++ b/src/custom-code-helpers/string-array/StringArrayCallsWrapperRc4CodeHelper.ts @@ -15,13 +15,19 @@ export class StringArrayCallsWrapperRc4CodeHelper extends StringArrayCallsWrappe const atobFunctionName: string = this.randomGenerator.getRandomString(6); const rc4FunctionName: string = this.randomGenerator.getRandomString(6); - const atobPolyfill: string = this.customCodeHelperFormatter.formatTemplate(AtobTemplate(), { - atobFunctionName - }); - const rc4Polyfill: string = this.customCodeHelperFormatter.formatTemplate(Rc4Template(), { - atobFunctionName, - rc4FunctionName - }); + const atobPolyfill: string = this.customCodeHelperFormatter.formatTemplate( + AtobTemplate(this.options.selfDefending), + { + atobFunctionName + } + ); + const rc4Polyfill: string = this.customCodeHelperFormatter.formatTemplate( + Rc4Template(), + { + atobFunctionName, + rc4FunctionName + } + ); const selfDefendingCode: string = this.getSelfDefendingTemplate(); diff --git a/src/custom-code-helpers/string-array/templates/string-array-calls-wrapper/AtobTemplate.ts b/src/custom-code-helpers/string-array/templates/string-array-calls-wrapper/AtobTemplate.ts index 8db429a7..a9c265c8 100644 --- a/src/custom-code-helpers/string-array/templates/string-array-calls-wrapper/AtobTemplate.ts +++ b/src/custom-code-helpers/string-array/templates/string-array-calls-wrapper/AtobTemplate.ts @@ -5,19 +5,27 @@ import { base64alphabetSwapped } from '../../../../constants/Base64AlphabetSwapp * * @returns {string} */ -export function AtobTemplate (): string { +export function AtobTemplate (selfDefending: boolean): string { return ` var {atobFunctionName} = function (input) { const chars = '${base64alphabetSwapped}'; let output = ''; let tempEncodedString = ''; + ${selfDefending ? 'let func = output + {atobFunctionName};' : ''} for ( let bc = 0, bs, buffer, idx = 0; buffer = input.charAt(idx++); - ~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer, - bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0 + ~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer, bc++ % 4) + ? output += ${((): string => { + const basePart: string = 'String.fromCharCode(255 & bs >> (-2 * bc & 6))'; + + return selfDefending + ? `(func.charCodeAt(idx + 10) - 10 ? ${basePart} : bc)` + : basePart; + })()} + : 0 ) { buffer = chars.indexOf(buffer); } diff --git a/test/dev/dev.ts b/test/dev/dev.ts index c455aba1..fab83d4c 100644 --- a/test/dev/dev.ts +++ b/test/dev/dev.ts @@ -37,7 +37,8 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../src/options/presets/NoCustomNo stringArrayEncoding: ['rc4', 'base64'], stringArrayWrappersCount: 5, rotateStringArray: true, - identifierNamesGenerator: 'mangled' + identifierNamesGenerator: 'mangled', + selfDefending: true } ).getObfuscatedCode(); diff --git a/test/functional-tests/code-transformers/preparing-transformers/hashbang-operator-transformer/HashbangOperatorTransformer.spec.ts b/test/functional-tests/code-transformers/preparing-transformers/hashbang-operator-transformer/HashbangOperatorTransformer.spec.ts index 77c86a2a..eb77332a 100644 --- a/test/functional-tests/code-transformers/preparing-transformers/hashbang-operator-transformer/HashbangOperatorTransformer.spec.ts +++ b/test/functional-tests/code-transformers/preparing-transformers/hashbang-operator-transformer/HashbangOperatorTransformer.spec.ts @@ -2,6 +2,7 @@ import { assert } from 'chai'; import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes'; +import { getStringArrayRegExp } from '../../../../helpers/get-string-array-regexp'; import { readFileAsString } from '../../../../helpers/readFileAsString'; import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade'; @@ -59,8 +60,8 @@ describe('HashbangOperatorTransformer', () => { describe('Variant #3: `stringArray` option enabled', () => { const regExp: RegExp = new RegExp( - `^#!\/usr\/bin\/env node${lineSeparator}` + - `var _0x(\\w){4} *= *\\['abc'];` + `^#!\/usr\/bin\/env node${lineSeparator}.*` + + `${getStringArrayRegExp(['abc']).source}` ); let obfuscatedCode: string; diff --git a/test/functional-tests/custom-code-helpers/string-array/StringArrayCallsWrapperCodeHelper.spec.ts b/test/functional-tests/custom-code-helpers/string-array/StringArrayCallsWrapperCodeHelper.spec.ts index 299b8d9d..20a03ca3 100644 --- a/test/functional-tests/custom-code-helpers/string-array/StringArrayCallsWrapperCodeHelper.spec.ts +++ b/test/functional-tests/custom-code-helpers/string-array/StringArrayCallsWrapperCodeHelper.spec.ts @@ -56,9 +56,10 @@ describe('StringArrayCallsWrapperCodeHelper', () => { describe('Preserve string array name', () => { const callsWrapperRegExp: RegExp = new RegExp(`` + `function *b *\\(c, *d\\) *{ *` + - `b *= *function *\\(e, *f\\) *{` + - `e *= *e *- *0x0; *` + - `var g *= *a\\[e]; *` + + `var e *= *a\\(\\); *` + + `b *= *function *\\(f, *g\\) *{` + + `f *= *f *- *0x0; *` + + `var h *= *e\\[f]; *` + ``); let obfuscatedCode: string; diff --git a/test/functional-tests/custom-code-helpers/string-array/StringArrayCodeHelper.spec.ts b/test/functional-tests/custom-code-helpers/string-array/StringArrayCodeHelper.spec.ts index e90d7686..c189ce75 100644 --- a/test/functional-tests/custom-code-helpers/string-array/StringArrayCodeHelper.spec.ts +++ b/test/functional-tests/custom-code-helpers/string-array/StringArrayCodeHelper.spec.ts @@ -2,12 +2,13 @@ import { assert } from 'chai'; import { NO_ADDITIONAL_NODES_PRESET } from '../../../../src/options/presets/NoCustomNodes'; +import { getStringArrayRegExp } from '../../../helpers/get-string-array-regexp'; import { readFileAsString } from '../../../helpers/readFileAsString'; import { JavaScriptObfuscator } from '../../../../src/JavaScriptObfuscatorFacade'; describe('StringArrayCodeHelper', () => { - const regExp: RegExp = /^var _0x([a-f0-9]){4} *= *\[/; + const regExp: RegExp = getStringArrayRegExp(['test']); describe('`stringArray` option is set', () => { let obfuscatedCode: string; diff --git a/test/functional-tests/custom-code-helpers/string-array/StringArrayRotateFunctionCodeHelper.spec.ts b/test/functional-tests/custom-code-helpers/string-array/StringArrayRotateFunctionCodeHelper.spec.ts index 7e7295ef..b4858421 100644 --- a/test/functional-tests/custom-code-helpers/string-array/StringArrayRotateFunctionCodeHelper.spec.ts +++ b/test/functional-tests/custom-code-helpers/string-array/StringArrayRotateFunctionCodeHelper.spec.ts @@ -84,8 +84,8 @@ describe('StringArrayRotateFunctionCodeHelper', () => { }); describe('Preserve string array name', () => { - const arrayRotateRegExp: RegExp = /c\['push']\(c\['shift']\(\)\);/; - const comparisonRegExp: RegExp = /if *\(e *=== *d\) *{/; + const arrayRotateRegExp: RegExp = /e\['push']\(e\['shift']\(\)\);/; + const comparisonRegExp: RegExp = /if *\(f *=== *d\) *{/; let obfuscatedCode: string; diff --git a/test/functional-tests/custom-code-helpers/string-array/group/StringArrayCodeHelperGroup.spec.ts b/test/functional-tests/custom-code-helpers/string-array/group/StringArrayCodeHelperGroup.spec.ts index 65d09239..f13ce551 100644 --- a/test/functional-tests/custom-code-helpers/string-array/group/StringArrayCodeHelperGroup.spec.ts +++ b/test/functional-tests/custom-code-helpers/string-array/group/StringArrayCodeHelperGroup.spec.ts @@ -5,41 +5,59 @@ import { IdentifierNamesGenerator } from '../../../../../src/enums/generators/id import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes'; +import { getRegExpMatch } from '../../../../helpers/getRegExpMatch'; import { readFileAsString } from '../../../../helpers/readFileAsString'; import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade'; describe('StringArrayCodeHelperGroup', () => { const regExp: RegExp = new RegExp( - 'function *b *\\(\\w, *\\w\\) *{.*return \\w;}.*' + - 'function *c *\\(\\w, *\\w\\) *{.*return \\w;}.*' + - 'function *d *\\(\\w, *\\w\\) *{.*return \\w;}' + 'function *\\w *\\(\\w, *\\w\\) *{.*return \\w;}.*' + + 'function *\\w *\\(\\w, *\\w\\) *{.*return \\w;}.*' + + 'function *\\w *\\(\\w, *\\w\\) *{.*return \\w;}' + ); + const stringArrayCallsWrapperRegExp: RegExp = new RegExp( + `function *(\\w) *\\(\\w, *\\w\\) *{.*return \\w;}.*` ); describe('StringArrayCallsWrapper code helper names', () => { + const stringArrayCallsWrapperNames: Set = new Set(); + const samplesCount: number = 30; let obfuscatedCode: string; + const expectedUniqStringArrayCallsWrapperNamesCount: number = 3; + before(() => { const code: string = readFileAsString(__dirname + '/fixtures/simple-input.js'); - obfuscatedCode = JavaScriptObfuscator.obfuscate( - code, - { - ...NO_ADDITIONAL_NODES_PRESET, - identifierNamesGenerator: IdentifierNamesGenerator.MangledIdentifierNamesGenerator, - stringArray: true, - stringArrayThreshold: 1, - stringArrayEncoding: [ - StringArrayEncoding.None, - StringArrayEncoding.Base64, - StringArrayEncoding.Rc4 - ] - } - ).getObfuscatedCode(); + for (let i = 0; i < samplesCount; i++) { + obfuscatedCode = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_ADDITIONAL_NODES_PRESET, + identifierNamesGenerator: IdentifierNamesGenerator.MangledIdentifierNamesGenerator, + stringArray: true, + stringArrayThreshold: 1, + stringArrayEncoding: [ + StringArrayEncoding.None, + StringArrayEncoding.Base64, + StringArrayEncoding.Rc4 + ] + } + ).getObfuscatedCode(); + + const callsWrapperName: string = getRegExpMatch(obfuscatedCode, stringArrayCallsWrapperRegExp); + + stringArrayCallsWrapperNames.add(callsWrapperName); + } }); - it('should place multiple StringArrayCallsWrapper code helper names in the correct order', () => { + it('should correct place all StringArrayCallsWrapper code helpers', () => { assert.match(obfuscatedCode, regExp); }); + + it('should place multiple StringArrayCallsWrapper code helper names in the random order', () => { + assert.equal(stringArrayCallsWrapperNames.size, expectedUniqStringArrayCallsWrapperNamesCount); + }); }); }); diff --git a/test/functional-tests/custom-code-helpers/string-array/templates/string-array-calls-wrapper-node-template/StringArrayCallsWrapperTemplate.spec.ts b/test/functional-tests/custom-code-helpers/string-array/templates/string-array-calls-wrapper-node-template/StringArrayCallsWrapperTemplate.spec.ts index cb943a3b..49af7017 100644 --- a/test/functional-tests/custom-code-helpers/string-array/templates/string-array-calls-wrapper-node-template/StringArrayCallsWrapperTemplate.spec.ts +++ b/test/functional-tests/custom-code-helpers/string-array/templates/string-array-calls-wrapper-node-template/StringArrayCallsWrapperTemplate.spec.ts @@ -16,16 +16,19 @@ import { Rc4Template } from '../../../../../../src/custom-code-helpers/string-ar import { StringArrayBase64DecodeTemplate } from '../../../../../../src/custom-code-helpers/string-array/templates/string-array-calls-wrapper/StringArrayBase64DecodeTemplate'; import { StringArrayCallsWrapperTemplate } from '../../../../../../src/custom-code-helpers/string-array/templates/string-array-calls-wrapper/StringArrayCallsWrapperTemplate'; import { StringArrayRC4DecodeTemplate } from '../../../../../../src/custom-code-helpers/string-array/templates/string-array-calls-wrapper/StringArrayRC4DecodeTemplate'; +import { StringArrayTemplate } from '../../../../../../src/custom-code-helpers/string-array/templates/string-array/StringArrayTemplate'; import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../../src/options/presets/NoCustomNodes'; import { InversifyContainerFacade } from '../../../../../../src/container/InversifyContainerFacade'; import { JavaScriptObfuscator } from '../../../../../../src/JavaScriptObfuscatorFacade'; +import { minimizeCode } from '../../../../../helpers/minimizeCode'; import { readFileAsString } from '../../../../../helpers/readFileAsString'; import { swapLettersCase } from '../../../../../helpers/swapLettersCase'; describe('StringArrayCallsWrapperTemplate', () => { const stringArrayName: string = 'stringArrayName'; + const stringArrayFunctionName: string = 'stringArrayFunctionName'; const stringArrayCallsWrapperName: string = 'stringArrayCallsWrapperName'; const stringArrayCacheName: string = 'stringArrayCache'; const atobFunctionName: string = 'atob'; @@ -45,243 +48,510 @@ describe('StringArrayCallsWrapperTemplate', () => { }); describe('Variant #1: `base64` encoding', () => { - describe('Variant #1: index shift amount is `0`', () => { - const index: string = '0x0'; + describe('Variant #1: `selfDefending` option is disabled', () => { + const selfDefendingEnabled: boolean = false; - const indexShiftAmount: number = 0; + describe('Variant #1: index shift amount is `0`', () => { + const index: string = '0x0'; - const expectedDecodedValue: string = 'test1'; + const indexShiftAmount: number = 0; - let decodedValue: string; + const expectedDecodedValue: string = 'test1'; - before(() => { - const atobPolyfill = format(AtobTemplate(), { - atobFunctionName - }); - const atobDecodeTemplate: string = format( - StringArrayBase64DecodeTemplate(randomGenerator), - { - atobPolyfill, - atobFunctionName, - selfDefendingCode: '', + let decodedValue: string; + + before(() => { + const stringArrayTemplate = format(StringArrayTemplate(), { + stringArrayName, + stringArrayFunctionName, + stringArrayStorageItems: `'${cryptUtilsSwappedAlphabet.btoa('test1')}'` + }); + const atobPolyfill = format(AtobTemplate(selfDefendingEnabled), { + atobFunctionName + }); + const atobDecodeTemplate: string = format( + StringArrayBase64DecodeTemplate(randomGenerator), + { + atobPolyfill, + atobFunctionName, + selfDefendingCode: '', + stringArrayCacheName, + stringArrayCallsWrapperName + } + ); + const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), { + decodeCodeHelperTemplate: atobDecodeTemplate, + indexShiftAmount, stringArrayCacheName, - stringArrayCallsWrapperName - } - ); - const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), { - decodeCodeHelperTemplate: atobDecodeTemplate, - indexShiftAmount, - stringArrayCacheName, - stringArrayCallsWrapperName, - stringArrayName + stringArrayCallsWrapperName, + stringArrayFunctionName + }); + + decodedValue = Function(` + ${stringArrayTemplate} + + ${stringArrayCallsWrapperTemplate} + + return ${stringArrayCallsWrapperName}(${index}); + `)(); }); - decodedValue = Function(` - var ${stringArrayName} = ['${cryptUtilsSwappedAlphabet.btoa('test1')}']; - - ${stringArrayCallsWrapperTemplate} - - return ${stringArrayCallsWrapperName}(${index}); - `)(); + it('should correctly return decoded value', () => { + assert.deepEqual(decodedValue, expectedDecodedValue); + }); }); - it('should correctly return decoded value', () => { - assert.deepEqual(decodedValue, expectedDecodedValue); + describe('Variant #2: index shift amount is `5`', () => { + const index: string = '0x5'; + + const indexShiftAmount: number = 5; + + const expectedDecodedValue: string = 'test1'; + + let decodedValue: string; + + before(() => { + const stringArrayTemplate = format(StringArrayTemplate(), { + stringArrayName, + stringArrayFunctionName, + stringArrayStorageItems: `'${cryptUtilsSwappedAlphabet.btoa('test1')}'` + }); + const atobPolyfill = format(AtobTemplate(selfDefendingEnabled), { + atobFunctionName + }); + const atobDecodeTemplate: string = format( + StringArrayBase64DecodeTemplate(randomGenerator), + { + atobPolyfill, + atobFunctionName, + selfDefendingCode: '', + stringArrayCacheName, + stringArrayCallsWrapperName + } + ); + const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), { + decodeCodeHelperTemplate: atobDecodeTemplate, + indexShiftAmount, + stringArrayCacheName, + stringArrayCallsWrapperName, + stringArrayFunctionName + }); + + decodedValue = Function(` + ${stringArrayTemplate} + + ${stringArrayCallsWrapperTemplate} + + return ${stringArrayCallsWrapperName}(${index}); + `)(); + }); + + it('should correctly return decoded value', () => { + assert.deepEqual(decodedValue, expectedDecodedValue); + }); + }); + + describe('Variant #3: no regexp inside atob template', () => { + const indexShiftAmount: number = 0; + + const expectedRegExpTestValue: string = '12345'; + + let decodedValue: string; + + before(() => { + const stringArrayTemplate = format(StringArrayTemplate(), { + stringArrayName, + stringArrayFunctionName, + stringArrayStorageItems: `'${swapLettersCase('c3RyaQ==')}'` + }); + const atobPolyfill = format(AtobTemplate(selfDefendingEnabled), { + atobFunctionName + }); + const atobDecodeTemplate: string = format( + StringArrayBase64DecodeTemplate(randomGenerator), + { + atobPolyfill, + atobFunctionName, + selfDefendingCode: '', + stringArrayCacheName, + stringArrayCallsWrapperName + } + ); + const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), { + decodeCodeHelperTemplate: atobDecodeTemplate, + indexShiftAmount, + stringArrayCacheName, + stringArrayCallsWrapperName, + stringArrayFunctionName + }); + + decodedValue = Function(` + ${stringArrayTemplate} + + ${stringArrayCallsWrapperTemplate} + + /(.+)/.test("12345"); + ${stringArrayCallsWrapperName}(0x0); + + return RegExp.$1; + `)(); + }); + + it('should correctly return RegExp.$1 match without mutation by atob template', () => { + assert.deepEqual(decodedValue, expectedRegExpTestValue); + }); }); }); - describe('Variant #2: index shift amount is `5`', () => { - const index: string = '0x5'; + describe('Variant #2: `selfDefending` option is enabled', () => { + const selfDefendingEnabled: boolean = true; - const indexShiftAmount: number = 5; + describe('Variant #1: correct code evaluation for single-line code', () => { + describe('Variant #1: index shift amount is `0`', () => { + const index: string = '0x0'; - const expectedDecodedValue: string = 'test1'; + const indexShiftAmount: number = 0; - let decodedValue: string; + const expectedDecodedValue: string = 'test1test1'; - before(() => { - const atobPolyfill = format(AtobTemplate(), { - atobFunctionName + let decodedValue: string; + + before(async() => { + const stringArrayTemplate = format(StringArrayTemplate(), { + stringArrayName, + stringArrayFunctionName, + stringArrayStorageItems: `'${cryptUtilsSwappedAlphabet.btoa('test1test1')}'` + }); + const atobPolyfill = format(AtobTemplate(selfDefendingEnabled), { + atobFunctionName + }); + const atobDecodeTemplate: string = format( + StringArrayBase64DecodeTemplate(randomGenerator), + { + atobPolyfill, + atobFunctionName, + selfDefendingCode: '', + stringArrayCacheName, + stringArrayCallsWrapperName + } + ); + const stringArrayCallsWrapperTemplate: string = await minimizeCode( + format(StringArrayCallsWrapperTemplate(), { + decodeCodeHelperTemplate: atobDecodeTemplate, + indexShiftAmount, + stringArrayCacheName, + stringArrayCallsWrapperName, + stringArrayFunctionName + }) + ); + + decodedValue = Function(` + ${stringArrayTemplate} + + ${stringArrayCallsWrapperTemplate} + + return ${stringArrayCallsWrapperName}(${index}); + `)(); + }); + + it('should correctly return decoded value', () => { + assert.deepEqual(decodedValue, expectedDecodedValue); + }); }); - const atobDecodeTemplate: string = format( - StringArrayBase64DecodeTemplate(randomGenerator), - { - atobPolyfill, - atobFunctionName, - selfDefendingCode: '', - stringArrayCacheName, - stringArrayCallsWrapperName - } - ); - const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), { - decodeCodeHelperTemplate: atobDecodeTemplate, - indexShiftAmount, - stringArrayCacheName, - stringArrayCallsWrapperName, - stringArrayName - }); - - decodedValue = Function(` - var ${stringArrayName} = ['${cryptUtilsSwappedAlphabet.btoa('test1')}']; - - ${stringArrayCallsWrapperTemplate} - - return ${stringArrayCallsWrapperName}(${index}); - `)(); }); - it('should correctly return decoded value', () => { - assert.deepEqual(decodedValue, expectedDecodedValue); - }); - }); + describe('Variant #2: invalid code evaluation for multi-line code', () => { + describe('Variant #1: index shift amount is `0`', () => { + const index: string = '0x0'; - describe('Variant #3: no regexp inside atob template', () => { - const indexShiftAmount: number = 0; + const indexShiftAmount: number = 0; - const expectedRegExpTestValue: string = '12345'; + const expectedDecodedValue: string = 'test18est1'; - let decodedValue: string; + let decodedValue: string; - before(() => { - const atobPolyfill = format(AtobTemplate(), { - atobFunctionName + before(() => { + const stringArrayTemplate = format(StringArrayTemplate(), { + stringArrayName, + stringArrayFunctionName, + stringArrayStorageItems: `'${cryptUtilsSwappedAlphabet.btoa('test1test1')}'` + }); + const atobPolyfill = format(AtobTemplate(selfDefendingEnabled), { + atobFunctionName + }); + const atobDecodeTemplate: string = format( + StringArrayBase64DecodeTemplate(randomGenerator), + { + atobPolyfill, + atobFunctionName, + selfDefendingCode: '', + stringArrayCacheName, + stringArrayCallsWrapperName + } + ); + const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), { + decodeCodeHelperTemplate: atobDecodeTemplate, + indexShiftAmount, + stringArrayCacheName, + stringArrayCallsWrapperName, + stringArrayFunctionName + }); + + decodedValue = Function(` + ${stringArrayTemplate} + + ${stringArrayCallsWrapperTemplate} + + return ${stringArrayCallsWrapperName}(${index}); + `)(); + }); + + it('should correctly return decoded value', () => { + assert.deepEqual(decodedValue, expectedDecodedValue); + }); }); - const atobDecodeTemplate: string = format( - StringArrayBase64DecodeTemplate(randomGenerator), - { - atobPolyfill, - atobFunctionName, - selfDefendingCode: '', - stringArrayCacheName, - stringArrayCallsWrapperName - } - ); - const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), { - decodeCodeHelperTemplate: atobDecodeTemplate, - indexShiftAmount, - stringArrayCacheName, - stringArrayCallsWrapperName, - stringArrayName - }); - - decodedValue = Function(` - var ${stringArrayName} = ['${swapLettersCase('c3RyaQ==')}']; - - ${stringArrayCallsWrapperTemplate} - - /(.+)/.test("12345"); - ${stringArrayCallsWrapperName}(0x0); - - return RegExp.$1; - `)(); - }); - - it('should correctly return RegExp.$1 match without mutation by atob template', () => { - assert.deepEqual(decodedValue, expectedRegExpTestValue); }); }); }); describe('Variant #2: `rc4` encoding', () => { - describe('Variant #1: index shift amount is `0`', () => { - const index: string = '0x0'; - const key: string = 'key'; + describe('Variant #1: `selfDefending` option is disabled', () => { + const selfDefendingEnabled: boolean = false; - const indexShiftAmount: number = 0; + describe('Variant #1: index shift amount is `0`', () => { + const index: string = '0x0'; + const key: string = 'key'; - const expectedDecodedValue: string = 'test1'; + const indexShiftAmount: number = 0; - let decodedValue: string; + const expectedDecodedValue: string = 'test1'; - before(() => { - const atobPolyfill = format(AtobTemplate(), { - atobFunctionName - }); - const rc4Polyfill = format(Rc4Template(), { - atobFunctionName, - rc4FunctionName - }); - const rc4decodeCodeHelperTemplate: string = format( - StringArrayRC4DecodeTemplate(randomGenerator), - { - atobPolyfill, - rc4Polyfill, - rc4FunctionName, - selfDefendingCode: '', + let decodedValue: string; + + before(() => { + const stringArrayTemplate = format(StringArrayTemplate(), { + stringArrayName, + stringArrayFunctionName, + stringArrayStorageItems: `'${cryptUtilsSwappedAlphabet.btoa(cryptUtilsSwappedAlphabet.rc4('test1', key))}'` + }); + const atobPolyfill = format(AtobTemplate(selfDefendingEnabled), { + atobFunctionName + }); + const rc4Polyfill = format(Rc4Template(), { + atobFunctionName, + rc4FunctionName + }); + const rc4decodeCodeHelperTemplate: string = format( + StringArrayRC4DecodeTemplate(randomGenerator), + { + atobPolyfill, + rc4Polyfill, + rc4FunctionName, + selfDefendingCode: '', + stringArrayCacheName, + stringArrayCallsWrapperName + } + ); + const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), { + decodeCodeHelperTemplate: rc4decodeCodeHelperTemplate, + indexShiftAmount, stringArrayCacheName, - stringArrayCallsWrapperName - } - ); - const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), { - decodeCodeHelperTemplate: rc4decodeCodeHelperTemplate, - indexShiftAmount, - stringArrayCacheName, - stringArrayCallsWrapperName, - stringArrayName + stringArrayCallsWrapperName, + stringArrayFunctionName + }); + + decodedValue = Function(` + ${stringArrayTemplate} + + ${stringArrayCallsWrapperTemplate} + + return ${stringArrayCallsWrapperName}('${index}', '${key}'); + `)(); }); - decodedValue = Function(` - var ${stringArrayName} = ['${cryptUtilsSwappedAlphabet.btoa(cryptUtilsSwappedAlphabet.rc4('test1', key))}']; - - ${stringArrayCallsWrapperTemplate} - - return ${stringArrayCallsWrapperName}('${index}', '${key}'); - `)(); + it('should correctly return decoded value', () => { + assert.deepEqual(decodedValue, expectedDecodedValue); + }); }); - it('should correctly return decoded value', () => { - assert.deepEqual(decodedValue, expectedDecodedValue); + describe('Variant #2: index shift amount is `5`', () => { + const index: string = '0x5'; + const key: string = 'key'; + + const indexShiftAmount: number = 5; + + const expectedDecodedValue: string = 'test1'; + + let decodedValue: string; + + before(() => { + const stringArrayTemplate = format(StringArrayTemplate(), { + stringArrayName, + stringArrayFunctionName, + stringArrayStorageItems: `'${cryptUtilsSwappedAlphabet.btoa(cryptUtilsSwappedAlphabet.rc4('test1', key))}'` + }); + const atobPolyfill = format(AtobTemplate(selfDefendingEnabled), { + atobFunctionName + }); + const rc4Polyfill = format(Rc4Template(), { + atobFunctionName, + rc4FunctionName + }); + const rc4decodeCodeHelperTemplate: string = format( + StringArrayRC4DecodeTemplate(randomGenerator), + { + atobPolyfill, + rc4Polyfill, + rc4FunctionName, + selfDefendingCode: '', + stringArrayCacheName, + stringArrayCallsWrapperName + } + ); + const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), { + decodeCodeHelperTemplate: rc4decodeCodeHelperTemplate, + indexShiftAmount, + stringArrayCacheName, + stringArrayCallsWrapperName, + stringArrayFunctionName + }); + + decodedValue = Function(` + ${stringArrayTemplate} + + ${stringArrayCallsWrapperTemplate} + + return ${stringArrayCallsWrapperName}('${index}', '${key}'); + `)(); + }); + + it('should correctly return decoded value', () => { + assert.deepEqual(decodedValue, expectedDecodedValue); + }); }); }); - describe('Variant #2: index shift amount is `5`', () => { - const index: string = '0x5'; - const key: string = 'key'; + describe('Variant #2: `selfDefending` option is enabled', () => { + const selfDefendingEnabled: boolean = true; - const indexShiftAmount: number = 5; + describe('Variant #1: correct code evaluation for single-line code', () => { + describe('Variant #1: index shift amount is `0`', () => { + const index: string = '0x0'; + const key: string = 'key'; - const expectedDecodedValue: string = 'test1'; + const indexShiftAmount: number = 0; - let decodedValue: string; + const expectedDecodedValue: string = 'test1'; - before(() => { - const atobPolyfill = format(AtobTemplate(), { - atobFunctionName + let decodedValue: string; + + before(async() => { + const stringArrayTemplate = format(StringArrayTemplate(), { + stringArrayName, + stringArrayFunctionName, + stringArrayStorageItems: `'${cryptUtilsSwappedAlphabet.btoa(cryptUtilsSwappedAlphabet.rc4('test1', key))}'` + }); + const atobPolyfill = format(AtobTemplate(selfDefendingEnabled), { + atobFunctionName + }); + const rc4Polyfill = format(Rc4Template(), { + atobFunctionName, + rc4FunctionName + }); + const rc4decodeCodeHelperTemplate: string = format( + StringArrayRC4DecodeTemplate(randomGenerator), + { + atobPolyfill, + rc4Polyfill, + rc4FunctionName, + selfDefendingCode: '', + stringArrayCacheName, + stringArrayCallsWrapperName + } + ); + const stringArrayCallsWrapperTemplate: string = await minimizeCode( + format(StringArrayCallsWrapperTemplate(), { + decodeCodeHelperTemplate: rc4decodeCodeHelperTemplate, + indexShiftAmount, + stringArrayCacheName, + stringArrayCallsWrapperName, + stringArrayFunctionName + }) + ); + + console.log(stringArrayCallsWrapperTemplate); + + decodedValue = Function(` + ${stringArrayTemplate} + + ${stringArrayCallsWrapperTemplate} + + return ${stringArrayCallsWrapperName}('${index}', '${key}'); + `)(); + }); + + it('should correctly return decoded value', () => { + assert.deepEqual(decodedValue, expectedDecodedValue); + }); }); - const rc4Polyfill = format(Rc4Template(), { - atobFunctionName, - rc4FunctionName - }); - const rc4decodeCodeHelperTemplate: string = format( - StringArrayRC4DecodeTemplate(randomGenerator), - { - atobPolyfill, - rc4Polyfill, - rc4FunctionName, - selfDefendingCode: '', - stringArrayCacheName, - stringArrayCallsWrapperName - } - ); - const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), { - decodeCodeHelperTemplate: rc4decodeCodeHelperTemplate, - indexShiftAmount, - stringArrayCacheName, - stringArrayCallsWrapperName, - stringArrayName - }); - - decodedValue = Function(` - var ${stringArrayName} = ['${cryptUtilsSwappedAlphabet.btoa(cryptUtilsSwappedAlphabet.rc4('test1', key))}']; - - ${stringArrayCallsWrapperTemplate} - - return ${stringArrayCallsWrapperName}('${index}', '${key}'); - `)(); }); - it('should correctly return decoded value', () => { - assert.deepEqual(decodedValue, expectedDecodedValue); + describe('Variant #2: invalid code evaluation for multi-line code', () => { + describe('Variant #1: index shift amount is `0`', () => { + const index: string = '0x0'; + const key: string = 'key'; + + const indexShiftAmount: number = 0; + + const expectedDecodedValue: string = 'test\u001c'; + + let decodedValue: string; + + before(() => { + const stringArrayTemplate = format(StringArrayTemplate(), { + stringArrayName, + stringArrayFunctionName, + stringArrayStorageItems: `'${cryptUtilsSwappedAlphabet.btoa(cryptUtilsSwappedAlphabet.rc4('test1', key))}'` + }); + const atobPolyfill = format(AtobTemplate(selfDefendingEnabled), { + atobFunctionName + }); + const rc4Polyfill = format(Rc4Template(), { + atobFunctionName, + rc4FunctionName + }); + const rc4decodeCodeHelperTemplate: string = format( + StringArrayRC4DecodeTemplate(randomGenerator), + { + atobPolyfill, + rc4Polyfill, + rc4FunctionName, + selfDefendingCode: '', + stringArrayCacheName, + stringArrayCallsWrapperName + } + ); + const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), { + decodeCodeHelperTemplate: rc4decodeCodeHelperTemplate, + indexShiftAmount, + stringArrayCacheName, + stringArrayCallsWrapperName, + stringArrayFunctionName + }); + + decodedValue = Function(` + ${stringArrayTemplate} + + ${stringArrayCallsWrapperTemplate} + + return ${stringArrayCallsWrapperName}('${index}', '${key}'); + `)(); + }); + + it('should correctly return decoded value', () => { + assert.deepEqual(decodedValue, expectedDecodedValue); + }); + }); }); }); }); diff --git a/test/functional-tests/custom-code-helpers/string-array/templates/string-array-template/StringArrayTemplate.spec.ts b/test/functional-tests/custom-code-helpers/string-array/templates/string-array-template/StringArrayTemplate.spec.ts index 182825e5..3742c78e 100644 --- a/test/functional-tests/custom-code-helpers/string-array/templates/string-array-template/StringArrayTemplate.spec.ts +++ b/test/functional-tests/custom-code-helpers/string-array/templates/string-array-template/StringArrayTemplate.spec.ts @@ -7,13 +7,14 @@ import { IObfuscationResult } from '../../../../../../src/interfaces/source-code import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../../src/options/presets/NoCustomNodes'; import { JavaScriptObfuscator } from '../../../../../../src/JavaScriptObfuscatorFacade'; +import { getStringArrayRegExp } from '../../../../../helpers/get-string-array-regexp'; import { readFileAsString } from '../../../../../helpers/readFileAsString'; describe('StringArrayTemplate', () => { describe('Prevailing kind of variables', () => { describe('`var` kind', () => { let obfuscatedCode: string, - stringArrayRegExp: RegExp = /var (_0x(\w){4}) *= *\['.*'];/; + stringArrayRegExp: RegExp = getStringArrayRegExp(['foo'], {kind: 'var'}); beforeEach(() => { const code: string = readFileAsString(__dirname + '/fixtures/prevailing-kind-of-variables-var.js'); @@ -40,7 +41,7 @@ describe('StringArrayTemplate', () => { describe('`const` kind', () => { let obfuscatedCode: string, - stringArrayRegExp: RegExp = /const (_0x(\w){4}) *= *\['.*'];/; + stringArrayRegExp: RegExp = getStringArrayRegExp(['foo'], {kind: 'const'}); beforeEach(() => { const code: string = readFileAsString(__dirname + '/fixtures/prevailing-kind-of-variables-const.js'); @@ -67,7 +68,7 @@ describe('StringArrayTemplate', () => { describe('`let` kind', () => { let obfuscatedCode: string, - stringArrayRegExp: RegExp = /const (_0x(\w){4}) *= *\['.*'];/; + stringArrayRegExp: RegExp = getStringArrayRegExp(['foo'], {kind: 'const'}); beforeEach(() => { const code: string = readFileAsString(__dirname + '/fixtures/prevailing-kind-of-variables-let.js'); diff --git a/test/functional-tests/generators/identifier-names-generators/dictionary-identifier-names-generator/DictionaryIdentifierNamesGenerator.spec.ts b/test/functional-tests/generators/identifier-names-generators/dictionary-identifier-names-generator/DictionaryIdentifierNamesGenerator.spec.ts index b61cbed3..ef577d13 100644 --- a/test/functional-tests/generators/identifier-names-generators/dictionary-identifier-names-generator/DictionaryIdentifierNamesGenerator.spec.ts +++ b/test/functional-tests/generators/identifier-names-generators/dictionary-identifier-names-generator/DictionaryIdentifierNamesGenerator.spec.ts @@ -4,8 +4,9 @@ import { IdentifierNamesGenerator } from '../../../../../src/enums/generators/id import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes'; -import { readFileAsString } from '../../../../helpers/readFileAsString'; import { getRegExpMatch } from '../../../../helpers/getRegExpMatch'; +import { getStringArrayRegExp } from '../../../../helpers/get-string-array-regexp'; +import { readFileAsString } from '../../../../helpers/readFileAsString'; import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade'; @@ -13,10 +14,19 @@ describe('DictionaryIdentifierNamesGenerator', () => { describe('generateWithPrefix', () => { describe('Variant #1: should not generate same name for string array as existing name in code', () => { describe('Variant #1: `renameGlobals` option is disabled', () => { - const stringArrayStorageRegExp: RegExp = /const a[cABC] *= *\['_aa', *'_ab'];/; - const variableDeclarationIdentifierNameRegExp1: RegExp = /const aa *= *a[cABC]\(0x0\);/; - const variableDeclarationIdentifierNameRegExp2: RegExp = /const ab *= *a[cABC]\(0x1\);/; + const stringArrayStorageRegExp: RegExp = getStringArrayRegExp( + ['_aa', '_ab'], + { + name: '\\w*', + kind: 'const' + } + ); + const variableDeclarationIdentifierNameRegExp1: RegExp = /const (\w*) *= *\w*\(0x0\);/; + const variableDeclarationIdentifierNameRegExp2: RegExp = /const (\w*) *= *\w*\(0x1\);/; + let stringArrayName: string = ''; + let variableDeclarationIdentifierName1: string = ''; + let variableDeclarationIdentifierName2: string = ''; let obfuscatedCode: string; before(() => { @@ -34,26 +44,45 @@ describe('DictionaryIdentifierNamesGenerator', () => { stringArrayThreshold: 1 } ).getObfuscatedCode(); + + stringArrayName = getRegExpMatch(obfuscatedCode, stringArrayStorageRegExp); + variableDeclarationIdentifierName1 = getRegExpMatch( + obfuscatedCode, + variableDeclarationIdentifierNameRegExp1 + ); + variableDeclarationIdentifierName2 = getRegExpMatch( + obfuscatedCode, + variableDeclarationIdentifierNameRegExp2 + ); }); - it('Match #1: should generate correct identifier for string array', () => { + it('Should generate correct identifier for string array', () => { assert.match(obfuscatedCode, stringArrayStorageRegExp); }); - it('Match #2: should keep identifier name for existing variable declaration', () => { - assert.match(obfuscatedCode, variableDeclarationIdentifierNameRegExp1); + it('Should keep identifier name for existing variable declaration #1', () => { + assert.notEqual(stringArrayName, variableDeclarationIdentifierName1); }); - it('Match #3: should keep identifier name for existing variable declaration', () => { - assert.match(obfuscatedCode, variableDeclarationIdentifierNameRegExp2); + it('Should keep identifier name for existing variable declaration #2', () => { + assert.notEqual(stringArrayName, variableDeclarationIdentifierName2); }); }); describe('Variant #2: `renameGlobals` option is enabled', () => { - const stringArrayStorageRegExp: RegExp = /const a[cABC] *= *\['_aa', *'_ab'];/; - const lastVariableDeclarationIdentifierNameRegExp1: RegExp = /const a[cABC] *= *a[cABC]\(0x0\);/; - const lastVariableDeclarationIdentifierNameRegExp2: RegExp = /const a[cABC] *= *a[cABC]\(0x1\);/; + const stringArrayStorageRegExp: RegExp = getStringArrayRegExp( + ['_aa', '_ab'], + { + name: '\\w*', + kind: 'const' + } + ); + const variableDeclarationIdentifierNameRegExp1: RegExp = /const (\w*) *= *\w*\(0x0\);/; + const variableDeclarationIdentifierNameRegExp2: RegExp = /const (\w*) *= *\w*\(0x1\);/; + let stringArrayName: string = ''; + let variableDeclarationIdentifierName1: string = ''; + let variableDeclarationIdentifierName2: string = ''; let obfuscatedCode: string; before(() => { @@ -64,7 +93,7 @@ describe('DictionaryIdentifierNamesGenerator', () => { { ...NO_ADDITIONAL_NODES_PRESET, identifierNamesGenerator: IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator, - identifiersDictionary: ['a', 'b', 'c'], + identifiersDictionary: ['a', 'b', 'c', 'd'], identifiersPrefix: 'a', renameGlobals: true, transformObjectKeys: true, @@ -72,18 +101,28 @@ describe('DictionaryIdentifierNamesGenerator', () => { stringArrayThreshold: 1 } ).getObfuscatedCode(); + + stringArrayName = getRegExpMatch(obfuscatedCode, stringArrayStorageRegExp); + variableDeclarationIdentifierName1 = getRegExpMatch( + obfuscatedCode, + variableDeclarationIdentifierNameRegExp1 + ); + variableDeclarationIdentifierName2 = getRegExpMatch( + obfuscatedCode, + variableDeclarationIdentifierNameRegExp2 + ); }); - it('Match #1: should generate correct identifier for string array', () => { + it('Should generate correct identifier for string array', () => { assert.match(obfuscatedCode, stringArrayStorageRegExp); }); - it('Match #2: should keep identifier name for existing variable declaration', () => { - assert.match(obfuscatedCode, lastVariableDeclarationIdentifierNameRegExp1); + it('Should keep identifier name for existing variable declaration #1', () => { + assert.notEqual(stringArrayName, variableDeclarationIdentifierName1); }); - it('Match #3: should keep identifier name for existing variable declaration', () => { - assert.match(obfuscatedCode, lastVariableDeclarationIdentifierNameRegExp2); + it('Should keep identifier name for existing variable declaration #2', () => { + assert.notEqual(stringArrayName, variableDeclarationIdentifierName2); }); }); }); @@ -91,11 +130,17 @@ describe('DictionaryIdentifierNamesGenerator', () => { describe('Variant #2: should not generate same prefixed name for identifier in code as prefixed name of string array', function () { this.timeout(10000); - const samplesCount: number = 20; + const samplesCount: number = 30; describe('Variant #1: `renameGlobals` option is disabled', () => { - const stringArrayStorageRegExp: RegExp = /const ([abAB]{1,3}) *= *\['first', *'abc'];/; - const variableDeclarationIdentifierNameRegExp: RegExp = /const ([abAB]{1,3}){1,2} *= *[abAB]{1,3}\(0x0\);/; + const stringArrayStorageRegExp: RegExp = getStringArrayRegExp( + ['first', 'abc'], + { + name: '\\w*', + kind: 'const' + } + ); + const variableDeclarationIdentifierNameRegExp: RegExp = /const (\w*) *= *\w*\(0x0\);/; let isIdentifiersAreConflicted: boolean = false; @@ -133,8 +178,14 @@ describe('DictionaryIdentifierNamesGenerator', () => { }); describe('Variant #2: `renameGlobals` option is enabled', () => { - const stringArrayStorageRegExp: RegExp = /const ([abAB]{1,3}) *= *\['first', *'abc'];/; - const variableDeclarationIdentifierNameRegExp: RegExp = /const ([abAB]{1,3}){1,2} *= *[abAB]{1,3}\(0x0\);/; + const stringArrayStorageRegExp: RegExp = getStringArrayRegExp( + ['first', 'abc'], + { + name: '\\w*', + kind: 'const' + } + ); + const variableDeclarationIdentifierNameRegExp: RegExp = /const (\w*) *= *\w*\(0x0\);/; let isIdentifiersAreConflicted: boolean = false; diff --git a/test/functional-tests/generators/identifier-names-generators/dictionary-identifier-names-generator/fixtures/string-array-storage-name-conflict-2.js b/test/functional-tests/generators/identifier-names-generators/dictionary-identifier-names-generator/fixtures/string-array-storage-name-conflict-2.js index 743b63e1..7f01a109 100644 --- a/test/functional-tests/generators/identifier-names-generators/dictionary-identifier-names-generator/fixtures/string-array-storage-name-conflict-2.js +++ b/test/functional-tests/generators/identifier-names-generators/dictionary-identifier-names-generator/fixtures/string-array-storage-name-conflict-2.js @@ -1,5 +1,4 @@ function foo () { const testA = 'first'; const testB = 'abc'; - const testC = 'abc'; } \ No newline at end of file diff --git a/test/functional-tests/generators/identifier-names-generators/mangled-identifier-names-generator/MangledIdentifierNamesGenerator.spec.ts b/test/functional-tests/generators/identifier-names-generators/mangled-identifier-names-generator/MangledIdentifierNamesGenerator.spec.ts index 71dd3b25..62d8800a 100644 --- a/test/functional-tests/generators/identifier-names-generators/mangled-identifier-names-generator/MangledIdentifierNamesGenerator.spec.ts +++ b/test/functional-tests/generators/identifier-names-generators/mangled-identifier-names-generator/MangledIdentifierNamesGenerator.spec.ts @@ -4,6 +4,7 @@ import { IdentifierNamesGenerator } from '../../../../../src/enums/generators/id import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes'; +import { getStringArrayRegExp } from '../../../../helpers/get-string-array-regexp'; import { readFileAsString } from '../../../../helpers/readFileAsString'; import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade'; @@ -12,7 +13,10 @@ describe('MangledIdentifierNamesGenerator', () => { describe('generateWithPrefix', () => { describe('Variant #1: should not generate same name for string array as existing name in code', () => { describe('Variant #1: `renameGlobals` option is disabled', () => { - const stringArrayStorageRegExp: RegExp = /const ab *= *\['abc'];/; + const stringArrayStorageRegExp: RegExp = getStringArrayRegExp(['abc'], { + kind: 'const', + name: 'ab' + }); const lastVariableDeclarationIdentifierNameRegExp: RegExp = /const aa *= *ac\(0x0\);/; let obfuscatedCode: string; @@ -43,7 +47,10 @@ describe('MangledIdentifierNamesGenerator', () => { }); describe('Variant #2: `renameGlobals` option is enabled', () => { - const stringArrayStorageRegExp: RegExp = /const ab *= *\['abc'];/; + const stringArrayStorageRegExp: RegExp = getStringArrayRegExp(['abc'], { + kind: 'const', + name: 'ab' + }); const lastVariableDeclarationIdentifierNameRegExp: RegExp = /const aB *= *ac\(0x0\);/; let obfuscatedCode: string; @@ -77,7 +84,10 @@ describe('MangledIdentifierNamesGenerator', () => { describe('Variant #2: should not generate same prefixed name for identifier in code as prefixed name of string array', () => { describe('Variant #1: `renameGlobals` option is disabled', () => { - const stringArrayStorageRegExp: RegExp = /const aa *= *\['abc', *'last'];/; + const stringArrayStorageRegExp: RegExp = getStringArrayRegExp(['abc', 'last'], { + kind: 'const', + name: 'aa' + }); const functionDeclarationIdentifierNameRegExp: RegExp = /function foo *\(\) *{/; const lastVariableDeclarationIdentifierNameRegExp: RegExp = /const ac *= *ab\(0x1\);/; @@ -113,7 +123,10 @@ describe('MangledIdentifierNamesGenerator', () => { }); describe('Variant #2: `renameGlobals` option is enabled', () => { - const stringArrayStorageRegExp: RegExp = /const aa *= *\['abc', *'last'];/; + const stringArrayStorageRegExp: RegExp = getStringArrayRegExp(['abc', 'last'], { + kind: 'const', + name: 'aa' + }); const functionDeclarationIdentifierNameRegExp: RegExp = /function ac *\(\) *{/; const lastVariableDeclarationIdentifierNameRegExp: RegExp = /const ad *= *ab\(0x1\);/; @@ -221,7 +234,10 @@ describe('MangledIdentifierNamesGenerator', () => { describe('Variant #2: Should generate different names set for different lexical scopes when string array is enabled', () => { describe('Variant #1: `renameGlobals` option is disabled', () => { - const stringArrayIdentifierRegExp: RegExp = /var a *= *\['abc'];/; + const stringArrayIdentifierRegExp: RegExp = getStringArrayRegExp(['abc'], { + kind: 'var', + name: 'a' + }); const variableIdentifierRegExp: RegExp = /var foo *= *b\(0x0\);/; const functionDeclarationRegExp1: RegExp = /function bar *\(c, *d\) *{}/; const functionDeclarationRegExp2: RegExp = /function baz *\(c, *d\) *{}/; @@ -260,7 +276,10 @@ describe('MangledIdentifierNamesGenerator', () => { }); describe('Variant #2: `renameGlobals` option is enabled', () => { - const stringArrayIdentifierRegExp: RegExp = /var a *= *\['abc'];/; + const stringArrayIdentifierRegExp: RegExp = getStringArrayRegExp(['abc'], { + kind: 'var', + name: 'a' + }); const variableIdentifierRegExp: RegExp = /var c *= *b\(0x0\);/; const functionDeclarationRegExp1: RegExp = /function d *\(f, *g\) *{}/; const functionDeclarationRegExp2: RegExp = /function e *\(f, *g\) *{}/; diff --git a/test/functional-tests/javascript-obfuscator/JavaScriptObfuscator.spec.ts b/test/functional-tests/javascript-obfuscator/JavaScriptObfuscator.spec.ts index 0698c88a..affa0e91 100644 --- a/test/functional-tests/javascript-obfuscator/JavaScriptObfuscator.spec.ts +++ b/test/functional-tests/javascript-obfuscator/JavaScriptObfuscator.spec.ts @@ -27,6 +27,7 @@ import { OptionsPreset } from '../../../src/enums/options/presets/OptionsPreset' import { buildLargeCode } from '../../helpers/buildLargeCode'; import { getRegExpMatch } from '../../helpers/getRegExpMatch'; +import { getStringArrayRegExp } from '../../helpers/get-string-array-regexp'; import { readFileAsString } from '../../helpers/readFileAsString'; describe('JavaScriptObfuscator', () => { @@ -444,7 +445,12 @@ describe('JavaScriptObfuscator', () => { }); describe('Variant #4: with `stringArray`, `renameGlobals` and `identifiersPrefix` options', () => { - const stringArrayRegExp: RegExp = /^var foo_0x(\w){4} *= *\['abc'\];/; + const stringArrayRegExp: RegExp = new RegExp( + 'function foo_0x([a-f0-9]){4} *\\(\\) *{' + + 'var _0x([a-f0-9]){4,6} *= *\\[\'abc\'];.*' + + 'return foo_0x([a-f0-9]){4}\\(\\); *' + + '}' + ); const stringArrayCallRegExp: RegExp = /var foo_0x(\w){4,6} *= *foo_0x(\w){4}\(0x0\);$/; let obfuscatedCode: string; @@ -536,7 +542,7 @@ describe('JavaScriptObfuscator', () => { }); describe('latin literal variable value', () => { - const stringArrayLatinRegExp: RegExp = /^var _0x(\w){4} *= *\['abc'\];/; + const stringArrayLatinRegExp: RegExp = getStringArrayRegExp(['abc']); const stringArrayCallRegExp: RegExp = /var test *= *_0x(\w){4}\(0x0\);$/; let obfuscatedCode: string; @@ -564,7 +570,12 @@ describe('JavaScriptObfuscator', () => { }); describe('cyrillic literal variable value', () => { - const stringArrayCyrillicRegExp: RegExp = /^var _0x(\w){4} *= *\['абц'\];/; + const stringArrayCyrillicRegExp: RegExp = new RegExp( + 'function _0x(\\w){4} *\\(\\) *{' + + 'var _0x([a-f0-9]){4,6} *= *\\[\'абц\'];.*' + + 'return _0x(\\w){4}\\(\\); *' + + '}' + ); const stringArrayCallRegExp: RegExp = /var test *= *_0x(\w){4}\(0x0\);$/; let obfuscatedCode: string; @@ -689,7 +700,12 @@ describe('JavaScriptObfuscator', () => { const code1: string = readFileAsString(__dirname + '/fixtures/simple-input-cyrillic.js'); const code2: string = readFileAsString(__dirname + '/fixtures/simple-input-2.js'); - const regExp: RegExp = /var (_0x(\w){4}) *= *\['.*'\];/; + const regExp: RegExp = new RegExp( + 'function _0x(\\w){4} *\\(\\) *{' + + 'var _0x([a-f0-9]){4,6} *= *\\[\'.*\'];.*' + + 'return _0x(\\w){4}\\(\\); *' + + '}' + ); let match1: string, match2: string; diff --git a/test/functional-tests/node-transformers/converting-transformers/class-field-transformer/ClassFieldTransformer.spec.ts b/test/functional-tests/node-transformers/converting-transformers/class-field-transformer/ClassFieldTransformer.spec.ts index 6d72968d..d39281cd 100644 --- a/test/functional-tests/node-transformers/converting-transformers/class-field-transformer/ClassFieldTransformer.spec.ts +++ b/test/functional-tests/node-transformers/converting-transformers/class-field-transformer/ClassFieldTransformer.spec.ts @@ -2,6 +2,7 @@ import { assert } from 'chai'; import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes'; +import { getStringArrayRegExp } from '../../../../helpers/get-string-array-regexp'; import { readFileAsString } from '../../../../helpers/readFileAsString'; import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade'; @@ -31,7 +32,7 @@ describe('ClassFieldTransformer', () => { }); describe('Variant #2: `stringArray` option is enabled', () => { - const stringArrayRegExp: RegExp = /var _0x([a-f0-9]){4} *= *\['property', *'bar'\];/; + const stringArrayRegExp: RegExp = getStringArrayRegExp(['property', 'bar']); const stringArrayCallRegExp: RegExp = /\[_0x([a-f0-9]){4}\(0x1\)\]\(\)\{\}/; let obfuscatedCode: string; @@ -103,7 +104,7 @@ describe('ClassFieldTransformer', () => { }); describe('Variant #2: `stringArray` option is enabled', () => { - const stringArrayRegExp: RegExp = /var _0x([a-f0-9]){4} *= *\['property', *'constructor', *'bar'];/; + const stringArrayRegExp: RegExp = getStringArrayRegExp(['property', 'constructor', 'bar']); const stringArrayCallRegExp: RegExp = /\[_0x([a-f0-9]){4}\(0x2\)\]\(\)\{\}/; let obfuscatedCode: string; @@ -203,7 +204,7 @@ describe('ClassFieldTransformer', () => { }); describe('Variant #2: `stringArray` option is enabled', () => { - const stringArrayRegExp: RegExp = /var _0x([a-f0-9]){4} *= *\['property', *'bar'\];/; + const stringArrayRegExp: RegExp = getStringArrayRegExp(['property', 'bar']); const stringArrayCallRegExp: RegExp = /\[_0x([a-f0-9]){4}\(0x0\)\] *= *0x1;/; let obfuscatedCode: string; @@ -254,7 +255,7 @@ describe('ClassFieldTransformer', () => { }); describe('Variant #2: `stringArray` option is enabled', () => { - const stringArrayRegExp: RegExp = /var _0x([a-f0-9]){4} *= *\['property', *'constructor', *'bar'];/; + const stringArrayRegExp: RegExp = getStringArrayRegExp(['property', 'constructor', 'bar']); const stringArrayCallRegExp: RegExp = /\[_0x([a-f0-9]){4}\(0x0\)\] *= *0x1;/; let obfuscatedCode: string; diff --git a/test/functional-tests/node-transformers/converting-transformers/member-expression-transformer/MemberExpressionTransformer.spec.ts b/test/functional-tests/node-transformers/converting-transformers/member-expression-transformer/MemberExpressionTransformer.spec.ts index 0468808e..48b752b5 100644 --- a/test/functional-tests/node-transformers/converting-transformers/member-expression-transformer/MemberExpressionTransformer.spec.ts +++ b/test/functional-tests/node-transformers/converting-transformers/member-expression-transformer/MemberExpressionTransformer.spec.ts @@ -2,6 +2,7 @@ import { assert } from 'chai'; import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes'; +import { getStringArrayRegExp } from '../../../../helpers/get-string-array-regexp'; import { readFileAsString } from '../../../../helpers/readFileAsString'; import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade'; @@ -30,7 +31,7 @@ describe('MemberExpressionTransformer', () => { }); describe('`stringArray` option is enabled', () => { - const stringArrayRegExp: RegExp = /var _0x([a-f0-9]){4} *= *\['log'\];/; + const stringArrayRegExp: RegExp = getStringArrayRegExp(['log']); const stringArrayCallRegExp: RegExp = /var test *= *console\[_0x([a-f0-9]){4}\(0x0\)\];/; let obfuscatedCode: string; @@ -60,7 +61,7 @@ describe('MemberExpressionTransformer', () => { describe('transformation of member expression node with square brackets', () => { describe('Variant #1: square brackets literal ', () => { - const stringArrayRegExp: RegExp = /var _0x([a-f0-9]){4} *= *\['log'\];/; + const stringArrayRegExp: RegExp = getStringArrayRegExp(['log']); const stringArrayCallRegExp: RegExp = /var test *= *console\[_0x([a-f0-9]){4}\(0x0\)\];/; let obfuscatedCode: string; diff --git a/test/functional-tests/node-transformers/finalizing-transformers/directive-placement-transformer/DirectivePlacementTransformer.spec.ts b/test/functional-tests/node-transformers/finalizing-transformers/directive-placement-transformer/DirectivePlacementTransformer.spec.ts index 598fd5db..3ad9387a 100644 --- a/test/functional-tests/node-transformers/finalizing-transformers/directive-placement-transformer/DirectivePlacementTransformer.spec.ts +++ b/test/functional-tests/node-transformers/finalizing-transformers/directive-placement-transformer/DirectivePlacementTransformer.spec.ts @@ -2,6 +2,7 @@ import { assert } from 'chai'; import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes'; +import { getStringArrayRegExp } from '../../../../helpers/get-string-array-regexp'; import { readFileAsString } from '../../../../helpers/readFileAsString'; import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade'; @@ -11,7 +12,10 @@ describe('DirectivePlacementTransformer', function () { describe('Variant #1: program scope', () => { describe('Variant #1: directive at the top of program scope', () => { - const directiveRegExp: RegExp = /^'use strict'; *var _0x([a-f0-9]){4} *= *\['test'];/; + const directiveRegExp: RegExp = new RegExp( + '^\'use strict\';.*' + + getStringArrayRegExp(['test']).source + ); let obfuscatedCode: string; @@ -34,9 +38,8 @@ describe('DirectivePlacementTransformer', function () { }); describe('Variant #2: directive-like string literal at the middle of program scope', () => { + const stringArrayStorageRegExp: RegExp = getStringArrayRegExp(['test', 'use\\\\x20strict']); const directiveRegExp: RegExp = new RegExp( - '^var _0x([a-f0-9]){4} *= *\\[\'test\', *\'use\\\\x20strict\']; *' + - '.*?' + 'var test *= *_0x([a-f0-9]){4}\\(0x0\\);.*' + '_0x([a-f0-9]){4}\\(0x1\\);' ); @@ -56,7 +59,11 @@ describe('DirectivePlacementTransformer', function () { ).getObfuscatedCode(); }); - it('should keep directive-like string literal at the middle of program scope', () => { + it('should add directive-like string literal to the string array', () => { + assert.match(obfuscatedCode, stringArrayStorageRegExp); + }); + + it('should add call to the directive-like string literal from the string array', () => { assert.match(obfuscatedCode, directiveRegExp); }); }); diff --git a/test/functional-tests/node-transformers/finalizing-transformers/escape-sequence-transformer/EscapeSequenceTransformer.spec.ts b/test/functional-tests/node-transformers/finalizing-transformers/escape-sequence-transformer/EscapeSequenceTransformer.spec.ts index 3ce372fc..016f06f5 100644 --- a/test/functional-tests/node-transformers/finalizing-transformers/escape-sequence-transformer/EscapeSequenceTransformer.spec.ts +++ b/test/functional-tests/node-transformers/finalizing-transformers/escape-sequence-transformer/EscapeSequenceTransformer.spec.ts @@ -5,6 +5,7 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/N import { IdentifierNamesGenerator } from '../../../../../src/enums/generators/identifier-names-generators/IdentifierNamesGenerator'; import { StringArrayIndexesType } from '../../../../../src/enums/node-transformers/string-array-transformers/StringArrayIndexesType'; +import { getStringArrayRegExp } from '../../../../helpers/get-string-array-regexp'; import { readFileAsString } from '../../../../helpers/readFileAsString'; import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade'; @@ -57,7 +58,7 @@ describe('EscapeSequenceTransformer', function () { }); describe('Variant #3: `unicodeEscapeSequence` and `stringArray` options are enabled', () => { - const stringArrayRegExp: RegExp = /^var _0x([a-f0-9]){4} *= *\['\\x74\\x65\\x73\\x74'\];/; + const stringArrayRegExp: RegExp = getStringArrayRegExp(['\\\\x74\\\\x65\\\\x73\\\\x74']); const stringArrayCallRegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\('\\x30\\x78\\x30'\);/; let obfuscatedCode: string; diff --git a/test/functional-tests/node-transformers/initializing-transformers/comments-transformer/CommentsTransformer.spec.ts b/test/functional-tests/node-transformers/initializing-transformers/comments-transformer/CommentsTransformer.spec.ts index 11c58773..ef1d22af 100644 --- a/test/functional-tests/node-transformers/initializing-transformers/comments-transformer/CommentsTransformer.spec.ts +++ b/test/functional-tests/node-transformers/initializing-transformers/comments-transformer/CommentsTransformer.spec.ts @@ -5,6 +5,7 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/N import { readFileAsString } from '../../../../helpers/readFileAsString'; import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade'; +import { getStringArrayRegExp } from '../../../../helpers/get-string-array-regexp'; describe('CommentsTransformer', () => { const lineSeparatorEscaped: string = '\\r?\\n'; @@ -142,7 +143,10 @@ describe('CommentsTransformer', () => { describe('Variant #7: simple comment with preserved words and additional code helper is inserted', () => { describe('Variant #1: `stringArray` code helper', () => { - const regExp: RegExp = /^\/\/ *@license *test *comment *\n*var _0x([a-f0-9]){4} *= *\['abc'];/; + const regExp: RegExp = new RegExp( + '^\\/\\/ *@license *test *comment *\\n*.*' + + getStringArrayRegExp(['abc']).source + ); let obfuscatedCode: string; diff --git a/test/functional-tests/node-transformers/preparing-transformers/eval-call-expression-transformer/EvalCallExpressionTransformer.spec.ts b/test/functional-tests/node-transformers/preparing-transformers/eval-call-expression-transformer/EvalCallExpressionTransformer.spec.ts index c476b7c0..0021e9c2 100644 --- a/test/functional-tests/node-transformers/preparing-transformers/eval-call-expression-transformer/EvalCallExpressionTransformer.spec.ts +++ b/test/functional-tests/node-transformers/preparing-transformers/eval-call-expression-transformer/EvalCallExpressionTransformer.spec.ts @@ -4,10 +4,11 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/N import { StringArrayIndexesType } from '../../../../../src/enums/node-transformers/string-array-transformers/StringArrayIndexesType'; +import { getRegExpMatch } from '../../../../helpers/getRegExpMatch'; +import { getStringArrayRegExp } from '../../../../helpers/get-string-array-regexp'; import { readFileAsString } from '../../../../helpers/readFileAsString'; import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade'; -import { getRegExpMatch } from '../../../../helpers/getRegExpMatch'; describe('EvalCallExpressionTransformer', () => { describe('Variant #1: identifier reference', () => { @@ -95,7 +96,7 @@ describe('EvalCallExpressionTransformer', () => { describe('Variant #4: string array calls wrapper call', () => { describe('Variant #1: hexadecimal number indexes type', () => { - const stringArrayRegExp: RegExp = /var _0x([a-f0-9]){4} *= *\['log', *'bar'];/; + const stringArrayRegExp: RegExp = getStringArrayRegExp(['log', 'bar']); const stringArrayCallsWrapperRegExp: RegExp = /eval *\('console\[_0x([a-f0-9]){4,6}\(0\)]\(_0x([a-f0-9]){4,6}\(1\)\);'\);/; let obfuscatedCode: string; @@ -126,7 +127,7 @@ describe('EvalCallExpressionTransformer', () => { }); describe('Variant #1: hexadecimal numeric string indexes type', () => { - const stringArrayRegExp: RegExp = /var _0x([a-f0-9]){4} *= *\['log', *'bar'];/; + const stringArrayRegExp: RegExp = getStringArrayRegExp(['log', 'bar']); const stringArrayCallsWrapperRegExp: RegExp = /eval *\('console\[_0x([a-f0-9]){4,6}\(\\'0x0\\'\)]\(_0x([a-f0-9]){4,6}\(\\'0x1\\'\)\);'\);/; let obfuscatedCode: string; diff --git a/test/functional-tests/node-transformers/preparing-transformers/obfuscating-guards/black-list-obfuscating-guard/BlackListObfuscatingGuard.spec.ts b/test/functional-tests/node-transformers/preparing-transformers/obfuscating-guards/black-list-obfuscating-guard/BlackListObfuscatingGuard.spec.ts index dcdaf3f1..cca8864b 100644 --- a/test/functional-tests/node-transformers/preparing-transformers/obfuscating-guards/black-list-obfuscating-guard/BlackListObfuscatingGuard.spec.ts +++ b/test/functional-tests/node-transformers/preparing-transformers/obfuscating-guards/black-list-obfuscating-guard/BlackListObfuscatingGuard.spec.ts @@ -4,13 +4,14 @@ import { JavaScriptObfuscator } from '../../../../../../src/JavaScriptObfuscator import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../../src/options/presets/NoCustomNodes'; +import { getStringArrayRegExp } from '../../../../../helpers/get-string-array-regexp'; import { readFileAsString } from '../../../../../helpers/readFileAsString'; describe('BlackListObfuscatingGuard', () => { describe('check', () => { describe('`\'use strict\';` operator', () => { const useStrictOperatorRegExp: RegExp = /'use *strict';/; - const stringArrayLatinRegExp: RegExp = /var _0x(\w){4} *= *\['abc'\];/; + const stringArrayLatinRegExp: RegExp = getStringArrayRegExp(['abc']); const stringArrayCallRegExp: RegExp = /var test *= *_0x(\w){4}\(0x0\);$/; let obfuscatedCode: string; diff --git a/test/functional-tests/node-transformers/preparing-transformers/obfuscating-guards/conditional-comment-obfuscating-guard/ConditionalCommentObfuscatingGuard.spec.ts b/test/functional-tests/node-transformers/preparing-transformers/obfuscating-guards/conditional-comment-obfuscating-guard/ConditionalCommentObfuscatingGuard.spec.ts index d3cd7070..c1277a4e 100644 --- a/test/functional-tests/node-transformers/preparing-transformers/obfuscating-guards/conditional-comment-obfuscating-guard/ConditionalCommentObfuscatingGuard.spec.ts +++ b/test/functional-tests/node-transformers/preparing-transformers/obfuscating-guards/conditional-comment-obfuscating-guard/ConditionalCommentObfuscatingGuard.spec.ts @@ -10,9 +10,9 @@ describe('ConditionalCommentObfuscatingGuard', () => { describe('check', () => { describe('Variant #1: `disable` conditional comment', () => { const disableConditionalCommentRegExp: RegExp = /\/\/ *javascript-obfuscator:disable/; - const obfuscatedVariableDeclarationRegExp: RegExp = /var _0x([a-f0-9]){4,6} *= *0x1;/; + const obfuscatedVariableDeclarationRegExp: RegExp = /var _0x([a-f0-9]){5,6} *= *0x1;/; const ignoredVariableDeclarationRegExp: RegExp = /var bar *= *2;/; - const consoleLogRegExp: RegExp = /console.log\(_0x([a-f0-9]){4,6}\);/; + const consoleLogRegExp: RegExp = /console.log\(_0x([a-f0-9]){5,6}\);/; let obfuscatedCode: string; @@ -47,8 +47,8 @@ describe('ConditionalCommentObfuscatingGuard', () => { describe('Variant #2: `disable` and `enable` conditional comments #1', () => { const disableConditionalCommentRegExp: RegExp = /\/\/ *javascript-obfuscator:disable/; const enableConditionalCommentRegExp: RegExp = /\/\/ *javascript-obfuscator:enable/; - const obfuscatedVariableDeclaration1RegExp: RegExp = /var _0x([a-f0-9]){4,6} *= *0x1;/; - const obfuscatedVariableDeclaration2RegExp: RegExp = /var _0x([a-f0-9]){4,6} *= *0x3;/; + const obfuscatedVariableDeclaration1RegExp: RegExp = /var _0x([a-f0-9]){5,6} *= *0x1;/; + const obfuscatedVariableDeclaration2RegExp: RegExp = /var _0x([a-f0-9]){5,6} *= *0x3;/; const ignoredVariableDeclarationRegExp: RegExp = /var bar *= *2;/; let obfuscatedCode: string; @@ -87,7 +87,7 @@ describe('ConditionalCommentObfuscatingGuard', () => { describe('Variant #3: `disable` and `enable` conditional comments #2', () => { const ignoredVariableDeclarationRegExp: RegExp = /var foo *= *1;/; - const obfuscatedVariableDeclarationRegExp: RegExp = /var _0x([a-f0-9]){4,6} *= *0x2;/; + const obfuscatedVariableDeclarationRegExp: RegExp = /var _0x([a-f0-9]){5,6} *= *0x2;/; let obfuscatedCode: string; @@ -139,13 +139,13 @@ describe('ConditionalCommentObfuscatingGuard', () => { }); describe('Variant #5: `disable` and `enable` conditional comments with dead code injection', () => { - const obfuscatedFunctionExpressionRegExp: RegExp = /var _0x([a-f0-9]){4,6} *= *function *\(_0x([a-f0-9]){4,6}, *_0x([a-f0-9]){4,6}, *_0x([a-f0-9]){4,6}\) *{/g; + const obfuscatedFunctionExpressionRegExp: RegExp = /var _0x([a-f0-9]){5,6} *= *function *\(_0x([a-f0-9]){5,6}, *_0x([a-f0-9]){5,6}, *_0x([a-f0-9]){5,6}\) *{/g; const expectedObfuscatedFunctionExpressionLength: number = 3; const ignoredFunctionExpression1RegExp: RegExp = /var bar *= *function *\(a, *b, *c\) *{/; const ignoredFunctionExpression2RegExp: RegExp = /var baz *= *function *\(a, *b, *c\) *{/; - const obfuscatedFunctionCallRegExp: RegExp = /_0x([a-f0-9]){4,6}\( *\);/g; + const obfuscatedFunctionCallRegExp: RegExp = /_0x([a-f0-9]){5,6}\( *\);/g; const expectedObfuscatedFunctionCallsLength: number = 3; const ignoredFunctionCall1RegExp: RegExp = /bar\( *\);/; @@ -209,7 +209,7 @@ describe('ConditionalCommentObfuscatingGuard', () => { }); describe('Variant #6: `disable` and `enable` conditional comments with control flow flattening', () => { - const obfuscatedVariableDeclarationRegExp: RegExp = /var _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\['[a-zA-Z0-9]{1,5}'];/; + const obfuscatedVariableDeclarationRegExp: RegExp = /var _0x([a-f0-9]){5,6} *= *_0x([a-f0-9]){5,6}\['[a-zA-Z0-9]{1,5}'];/; const ignoredVariableDeclarationRegExp: RegExp = /var bar *= *'bar';/; let obfuscatedCode: string; diff --git a/test/functional-tests/node-transformers/preparing-transformers/variable-preserve-transformer/VariablePreserveTransformer.spec.ts b/test/functional-tests/node-transformers/preparing-transformers/variable-preserve-transformer/VariablePreserveTransformer.spec.ts index 4cc121e2..17895c56 100644 --- a/test/functional-tests/node-transformers/preparing-transformers/variable-preserve-transformer/VariablePreserveTransformer.spec.ts +++ b/test/functional-tests/node-transformers/preparing-transformers/variable-preserve-transformer/VariablePreserveTransformer.spec.ts @@ -2,6 +2,7 @@ import { assert } from 'chai'; import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes'; +import { getStringArrayRegExp } from '../../../../helpers/get-string-array-regexp'; import { readFileAsString } from '../../../../helpers/readFileAsString'; import { stubNodeTransformers } from '../../../../helpers/stubNodeTransformers'; @@ -11,7 +12,10 @@ import { ObjectPatternPropertiesTransformer } from '../../../../../src/node-tran describe('VariablePreserveTransformer', () => { describe('Variant #1: string array storage name conflicts with identifier name', () => { describe('Variant #1: `renameGlobals` option is disabled', () => { - const stringArrayStorageNameRegExp: RegExp = /const b *= *\['abc'];/; + const stringArrayStorageNameRegExp: RegExp = getStringArrayRegExp(['abc'], { + kind: 'const', + name: 'b' + }); const identifierNameRegExp: RegExp = /const a *= *c\(0x0\);/; let obfuscatedCode: string; @@ -40,7 +44,10 @@ describe('VariablePreserveTransformer', () => { }); describe('Variant #2: `renameGlobals` option is enabled', () => { - const stringArrayStorageNameRegExp: RegExp = /const b *= *\['abc'];/; + const stringArrayStorageNameRegExp: RegExp = getStringArrayRegExp(['abc'], { + kind: 'const', + name: 'b' + }); const identifierNameRegExp: RegExp = /const d *= *c\(0x0\);/; let obfuscatedCode: string; diff --git a/test/functional-tests/node-transformers/string-array-transformers/string-array-scope-calls-wrapper-transformer/StringArrayScopeCallsWrapperTransformer.spec.ts b/test/functional-tests/node-transformers/string-array-transformers/string-array-scope-calls-wrapper-transformer/StringArrayScopeCallsWrapperTransformer.spec.ts index af24d5e6..49b58313 100644 --- a/test/functional-tests/node-transformers/string-array-transformers/string-array-scope-calls-wrapper-transformer/StringArrayScopeCallsWrapperTransformer.spec.ts +++ b/test/functional-tests/node-transformers/string-array-transformers/string-array-scope-calls-wrapper-transformer/StringArrayScopeCallsWrapperTransformer.spec.ts @@ -651,11 +651,9 @@ describe('StringArrayScopeCallsWrapperTransformer', function () { '}'; const stringArrayScopeCallsWrapperRegExp1: RegExp = new RegExp( - 'const a *= *\\[.*?];.*?' + getStringArrayCallsWrapperMatch('f') ); const stringArrayScopeCallsWrapperRegExp2: RegExp = new RegExp( - 'const a *= *\\[.*?];.*?' + 'function test *\\( *\\) *{.*' + `${getStringArrayCallsWrapperMatch('g')}.*?` + '}' @@ -723,11 +721,9 @@ describe('StringArrayScopeCallsWrapperTransformer', function () { '}'; const stringArrayScopeCallsWrapperRegExp1: RegExp = new RegExp( - 'const a *= *\\[.*?];.*?' + getStringArrayCallsWrapperMatch('f') ); const stringArrayScopeCallsWrapperRegExp2: RegExp = new RegExp( - 'const a *= *\\[.*?];.*?' + 'function test *\\( *\\) *{.*' + `${getStringArrayCallsWrapperMatch('g')}.*?` + '}' @@ -791,13 +787,11 @@ describe('StringArrayScopeCallsWrapperTransformer', function () { describe('Variant #2: correct chained calls', () => { const stringArrayScopeCallsWrapperRegExp1: RegExp = new RegExp( - 'const a *= *\\[.*?];.*?' + 'function *f *\\(c, *d\\) *{' + `return b\\([cd] *-(?: -)?${hexadecimalIndexMatch}, *[cd]\\);` + '}.*' ); const stringArrayScopeCallsWrapperRegExp2: RegExp = new RegExp( - 'const a *= *\\[.*?];.*?' + 'function test *\\( *\\) *{.*' + 'function *g *\\(c, *d\\) *{' + `return f\\(` + @@ -863,7 +857,6 @@ describe('StringArrayScopeCallsWrapperTransformer', function () { describe('Variant #3: no wrappers on a root scope', () => { const stringArrayScopeCallsWrapperRegExp: RegExp = new RegExp( - 'const a *= *\\[.*?];.*' + 'function test *\\( *\\) *{.*' + 'function *f*\\(c, *d\\) *{' + `return b\\([cd] *-(?: -)?${hexadecimalIndexMatch}, *[cd]\\);` + @@ -1088,13 +1081,11 @@ describe('StringArrayScopeCallsWrapperTransformer', function () { .join(', *'); const stringArrayScopeCallsWrapperRegExp1: RegExp = new RegExp( - 'const a *= *\\[.*?];.*?' + 'function *f *\\(c, *d, *e, *h, *i\\) *{' + `return b\\([cdehi] *-(?: -)?${hexadecimalIndexMatch}, *[cdehi]\\);` + '}.*' ); const stringArrayScopeCallsWrapperRegExp2: RegExp = new RegExp( - 'const a *= *\\[.*?];.*?' + 'function test *\\( *\\) *{.*' + 'function *g *\\(c, *d, *e, *h, *i\\) *{' + `return f\\(` + @@ -1169,13 +1160,11 @@ describe('StringArrayScopeCallsWrapperTransformer', function () { .join(', *'); const stringArrayScopeCallsWrapperRegExp1: RegExp = new RegExp( - 'const a *= *\\[.*?];.*?' + 'function *f *\\(c, *d, *e, *h, *i\\) *{' + `return b\\([cdehi] *-(?: -)?${hexadecimalIndexMatch}, *[cdehi]\\);` + '}.*' ); const stringArrayScopeCallsWrapperRegExp2: RegExp = new RegExp( - 'const a *= *\\[.*?];.*?' + 'function test *\\( *\\) *{.*' + 'function *g *\\(c, *d, *e, *h, *i\\) *{' + `return f\\(` + diff --git a/test/functional-tests/node-transformers/string-array-transformers/string-array-transformer/StringArrayTransformer.spec.ts b/test/functional-tests/node-transformers/string-array-transformers/string-array-transformer/StringArrayTransformer.spec.ts index f60411e3..7c2764ca 100644 --- a/test/functional-tests/node-transformers/string-array-transformers/string-array-transformer/StringArrayTransformer.spec.ts +++ b/test/functional-tests/node-transformers/string-array-transformers/string-array-transformer/StringArrayTransformer.spec.ts @@ -7,6 +7,7 @@ import { StringArrayWrappersType } from '../../../../../src/enums/node-transform import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes'; +import { getStringArrayRegExp } from '../../../../helpers/get-string-array-regexp'; import { readFileAsString } from '../../../../helpers/readFileAsString'; import { getRegExpMatch } from '../../../../helpers/getRegExpMatch'; import { swapLettersCase } from '../../../../helpers/swapLettersCase'; @@ -17,7 +18,7 @@ describe('StringArrayTransformer', function () { this.timeout(120000); describe('Variant #1: default behaviour', () => { - const stringArrayRegExp: RegExp = /^var _0x([a-f0-9]){4} *= *\['test'\];/; + const stringArrayRegExp: RegExp = getStringArrayRegExp(['test']); const stringArrayCallRegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\(0x0\);/; let obfuscatedCode: string; @@ -355,7 +356,7 @@ describe('StringArrayTransformer', function () { }); describe('Variant #5: same literal node values', () => { - const stringArrayRegExp: RegExp = /^var _0x([a-f0-9]){4} *= *\['test'\];/; + const stringArrayRegExp: RegExp = getStringArrayRegExp(['test']); const stringArrayCallRegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\(0x0\);/; let obfuscatedCode: string; @@ -406,7 +407,12 @@ describe('StringArrayTransformer', function () { }); describe('Variant #7: base64 encoding', () => { - const stringArrayRegExp: RegExp = new RegExp(`^var _0x([a-f0-9]){4} *= *\\['${swapLettersCase('dGVzdA')}'];`); + const stringArrayRegExp: RegExp = new RegExp( + 'function _0x([a-f0-9]){4} *\\(\\) *{' + + `var _0x([a-f0-9]){4,6} *= *\\[\'${swapLettersCase('dGVzdA')}\'];.*` + + 'return _0x([a-f0-9]){4}\\(\\); *' + + '}' + ); const stringArrayCallRegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\(0x0\);/; let obfuscatedCode: string; @@ -506,8 +512,8 @@ describe('StringArrayTransformer', function () { const expectedMatchesChance: number = 0.5; const expectedMatchesDelta: number = 0.15; - const noneEncodingRegExp: RegExp = /^var _0x([a-f0-9]){4} *= *\['test'\];/; - const base64EncodingRegExp: RegExp = /^var _0x([a-f0-9]){4} *= *\['DgvZDa'\];/; + const noneEncodingRegExp: RegExp = getStringArrayRegExp(['test']); + const base64EncodingRegExp: RegExp = getStringArrayRegExp(['DgvZDa']); let noneEncodingMatchesCount: number = 0; let base64EncodingMatchesCount: number = 0; @@ -1080,7 +1086,7 @@ describe('StringArrayTransformer', function () { describe('Variant #16: object expression key literal', () => { describe('Variant #1: base key literal', () => { - const stringArrayRegExp: RegExp = /^var _0x([a-f0-9]){4} *= *\['bar'];/; + const stringArrayRegExp: RegExp = getStringArrayRegExp(['bar']) const objectExpressionRegExp: RegExp = /var test *= *{'foo' *: *_0x([a-f0-9]){4}\(0x0\)};/; let obfuscatedCode: string; @@ -1108,7 +1114,7 @@ describe('StringArrayTransformer', function () { }); describe('Variant #2: computed key literal', () => { - const stringArrayRegExp: RegExp = /^var _0x([a-f0-9]){4} *= *\['foo', *'bar'];/; + const stringArrayRegExp: RegExp = getStringArrayRegExp(['foo', 'bar']) const objectExpressionRegExp: RegExp = /var test *= *{\[_0x([a-f0-9]){4}\(0x0\)] *: *_0x([a-f0-9]){4}\(0x1\)};/; let obfuscatedCode: string; diff --git a/test/functional-tests/storages/string-array-transformers/string-array-storage/StringArrayStorage.spec.ts b/test/functional-tests/storages/string-array-transformers/string-array-storage/StringArrayStorage.spec.ts index 97a9759a..72714c4a 100644 --- a/test/functional-tests/storages/string-array-transformers/string-array-storage/StringArrayStorage.spec.ts +++ b/test/functional-tests/storages/string-array-transformers/string-array-storage/StringArrayStorage.spec.ts @@ -2,6 +2,7 @@ import { assert } from 'chai'; import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes'; +import { getStringArrayRegExp } from '../../../../helpers/get-string-array-regexp'; import { readFileAsString } from '../../../../helpers/readFileAsString'; import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade'; @@ -15,7 +16,7 @@ describe('StringArrayStorage', () => { const delta: number = 0.1; const expectedVariantProbability: number = 1; - const stringArrayVariantRegExp: RegExp = /var _0x([a-f0-9]){4} *= *\[(?:'.*?', *)?'test'(?:, *'.*?')?];/g; + const stringArrayVariantRegExp: RegExp = /var.*= *\[(?:'.*?', *)?'test'(?:, *'.*?')?];.*/; const literalNodeVariantRegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\(0x.\);/g; let stringArrayVariantProbability: number, @@ -74,8 +75,8 @@ describe('StringArrayStorage', () => { const literalNodeVariantsCount: number = 1; const stringArrayVariantRegExps: RegExp[] = [ - /var _0x([a-f0-9]){4} *= *\['foo', *'bar', *'baz'(?:, *'.*?')+];/g, - /var _0x([a-f0-9]){4} *= *\[(?:'.*?', *)+'foo', *'bar', *'baz'];/g + /var.*= *\['foo', *'bar', *'baz'(?:, *'.*?')+];.*/, + /var.*= *\[(?:'.*?', *)+'foo', *'bar', *'baz'];.*/, ]; const literalNodeVariantRegExps: RegExp[] = [ new RegExp( @@ -155,7 +156,7 @@ describe('StringArrayStorage', () => { const delta: number = 0.1; const expectedVariantProbability: number = 1; - const stringArrayVariantRegExp1: RegExp = /var _0x([a-f0-9]){4} *= *\['test'];/g; + const stringArrayVariantRegExp1: RegExp = getStringArrayRegExp(['test']); const literalNodeVariant1RegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\(0x0\);/g; let stringArrayVariant1Probability: number, @@ -212,12 +213,12 @@ describe('StringArrayStorage', () => { const variantsCount: number = 6; const stringArrayVariantRegExps: RegExp[] = [ - /var _0x([a-f0-9]){4} *= *\['foo', *'bar', *'baz'];/g, - /var _0x([a-f0-9]){4} *= *\['foo', *'baz', *'bar'];/g, - /var _0x([a-f0-9]){4} *= *\['bar', *'foo', *'baz'];/g, - /var _0x([a-f0-9]){4} *= *\['bar', *'baz', *'foo'];/g, - /var _0x([a-f0-9]){4} *= *\['baz', *'foo', *'bar'];/g, - /var _0x([a-f0-9]){4} *= *\['baz', *'bar', *'foo'];/g + getStringArrayRegExp(['foo', 'bar', 'baz']), + getStringArrayRegExp(['foo', 'baz', 'bar']), + getStringArrayRegExp(['bar', 'foo', 'baz']), + getStringArrayRegExp(['bar', 'baz', 'foo']), + getStringArrayRegExp(['baz', 'foo', 'bar']), + getStringArrayRegExp(['baz', 'bar', 'foo']) ]; const literalNodeVariantRegExps: RegExp[] = [ diff --git a/test/helpers/get-string-array-regexp.ts b/test/helpers/get-string-array-regexp.ts new file mode 100644 index 00000000..94f4997c --- /dev/null +++ b/test/helpers/get-string-array-regexp.ts @@ -0,0 +1,28 @@ +const defaultOptions = { + name: '_0x([a-f0-9]){4}', + kind: 'var' +} + +/** + * Returns string array RegExp + * + * @returns {RegExp} + */ +export function getStringArrayRegExp( + stringArrayItems: string[], + options: Partial = {} +): RegExp { + const mergedOptions = { + ...defaultOptions, + ...options + }; + + const {name, kind} = mergedOptions; + + return new RegExp( + `function (${name}) *\\(\\) *{` + + `${kind}.*= *\\[${stringArrayItems.map((item: string) => `\'${item}\'`).join(',')}];.*` + + `return ${name}\\(\\); *` + + '}' + ); +} \ No newline at end of file diff --git a/test/helpers/minimizeCode.ts b/test/helpers/minimizeCode.ts new file mode 100644 index 00000000..622b8292 --- /dev/null +++ b/test/helpers/minimizeCode.ts @@ -0,0 +1,13 @@ +import {minify} from 'terser'; + +/** + * Minimizes code + * + * @param {string} code + * @returns {string} + */ +export async function minimizeCode (code: string): Promise { + const result = await minify(code); + + return result.code ?? ''; +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 387441b8..5430a293 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4458,6 +4458,15 @@ terser@^5.7.0: source-map "~0.7.2" source-map-support "~0.5.19" +terser@^5.7.1: + version "5.7.1" + resolved "https://registry.yarnpkg.com/terser/-/terser-5.7.1.tgz#2dc7a61009b66bb638305cb2a824763b116bf784" + integrity sha512-b3e+d5JbHAe/JSjwsC3Zn55wsBIM7AsHLjKxT31kGCldgbpFePaFo+PiddtO6uwRZWRw7sPXmAN8dTW61xmnSg== + dependencies: + commander "^2.20.0" + source-map "~0.7.2" + source-map-support "~0.5.19" + test-exclude@^6.0.0: version "6.0.0" resolved "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz"