|  | @@ -12,7 +12,7 @@ import { swapLettersCase } from '../../../../helpers/swapLettersCase';
 | 
	
		
			
				|  |  |  import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade';
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |  describe('StringArrayTransformer', function () {
 | 
	
		
			
				|  |  | -    this.timeout(60000);
 | 
	
		
			
				|  |  | +    this.timeout(120000);
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      describe('Variant #1: default behaviour', () => {
 | 
	
		
			
				|  |  |          const stringArrayRegExp: RegExp = /^var _0x([a-f0-9]){4} *= *\['test'\];/;
 | 
	
	
		
			
				|  | @@ -63,21 +63,156 @@ describe('StringArrayTransformer', function () {
 | 
	
		
			
				|  |  |          });
 | 
	
		
			
				|  |  |      });
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -    describe('Variant #3: `stringArrayIntermediateVariablesCount` option is enabled', () => {
 | 
	
		
			
				|  |  | -        describe('Variant #1: correct amount of intermediate calls', () => {
 | 
	
		
			
				|  |  | +    describe('Variant #3: `stringArrayWrappersCount` option is enabled', () => {
 | 
	
		
			
				|  |  | +        describe('Variant #1: root scope', () => {
 | 
	
		
			
				|  |  | +            describe('Variant #1: option value value is lower then count `literal` nodes in the scope', () => {
 | 
	
		
			
				|  |  | +                const stringArrayCallRegExp: RegExp = new RegExp(
 | 
	
		
			
				|  |  | +                        'return _0x([a-f0-9]){4,6};' +
 | 
	
		
			
				|  |  | +                    '};' +
 | 
	
		
			
				|  |  | +                    'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
 | 
	
		
			
				|  |  | +                    'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
 | 
	
		
			
				|  |  | +                    'const foo *= *_0x([a-f0-9]){4,6}\\(\'0x0\'\\);' +
 | 
	
		
			
				|  |  | +                    'const bar *= *_0x([a-f0-9]){4,6}\\(\'0x1\'\\);' +
 | 
	
		
			
				|  |  | +                    'const baz *= *_0x([a-f0-9]){4,6}\\(\'0x2\'\\);'
 | 
	
		
			
				|  |  | +                );
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                let obfuscatedCode: string;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                before(() => {
 | 
	
		
			
				|  |  | +                    const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-count-const.js');
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    obfuscatedCode = JavaScriptObfuscator.obfuscate(
 | 
	
		
			
				|  |  | +                        code,
 | 
	
		
			
				|  |  | +                        {
 | 
	
		
			
				|  |  | +                            ...NO_ADDITIONAL_NODES_PRESET,
 | 
	
		
			
				|  |  | +                            stringArray: true,
 | 
	
		
			
				|  |  | +                            stringArrayThreshold: 1,
 | 
	
		
			
				|  |  | +                            stringArrayWrappersCount: 2
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +                    ).getObfuscatedCode();
 | 
	
		
			
				|  |  | +                });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                it('should add scope calls wrappers', () => {
 | 
	
		
			
				|  |  | +                    assert.match(obfuscatedCode, stringArrayCallRegExp);
 | 
	
		
			
				|  |  | +                });
 | 
	
		
			
				|  |  | +            });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            describe('Variant #2: option value is bigger then count `literal` nodes in the scope', () => {
 | 
	
		
			
				|  |  | +                const stringArrayCallRegExp: RegExp = new RegExp(
 | 
	
		
			
				|  |  | +                        'return _0x([a-f0-9]){4,6};' +
 | 
	
		
			
				|  |  | +                    '};' +
 | 
	
		
			
				|  |  | +                    'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
 | 
	
		
			
				|  |  | +                    'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
 | 
	
		
			
				|  |  | +                    'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
 | 
	
		
			
				|  |  | +                    'const foo *= *_0x([a-f0-9]){4,6}\\(\'0x0\'\\);' +
 | 
	
		
			
				|  |  | +                    'const bar *= *_0x([a-f0-9]){4,6}\\(\'0x1\'\\);' +
 | 
	
		
			
				|  |  | +                    'const baz *= *_0x([a-f0-9]){4,6}\\(\'0x2\'\\);'
 | 
	
		
			
				|  |  | +                );
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                let obfuscatedCode: string;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                before(() => {
 | 
	
		
			
				|  |  | +                    const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-count-const.js');
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    obfuscatedCode = JavaScriptObfuscator.obfuscate(
 | 
	
		
			
				|  |  | +                        code,
 | 
	
		
			
				|  |  | +                        {
 | 
	
		
			
				|  |  | +                            ...NO_ADDITIONAL_NODES_PRESET,
 | 
	
		
			
				|  |  | +                            stringArray: true,
 | 
	
		
			
				|  |  | +                            stringArrayThreshold: 1,
 | 
	
		
			
				|  |  | +                            stringArrayWrappersCount: 5
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +                    ).getObfuscatedCode();
 | 
	
		
			
				|  |  | +                });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                it('should add scope calls wrappers', () => {
 | 
	
		
			
				|  |  | +                    assert.match(obfuscatedCode, stringArrayCallRegExp);
 | 
	
		
			
				|  |  | +                });
 | 
	
		
			
				|  |  | +            });
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        describe('Variant #2: function scope', () => {
 | 
	
		
			
				|  |  | +            describe('Variant #1: option value is lower then count `literal` nodes in the scope', () => {
 | 
	
		
			
				|  |  | +                const stringArrayCallRegExp: RegExp = new RegExp(
 | 
	
		
			
				|  |  | +                    'function test *\\( *\\) *{' +
 | 
	
		
			
				|  |  | +                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
 | 
	
		
			
				|  |  | +                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
 | 
	
		
			
				|  |  | +                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x3\'\\);' +
 | 
	
		
			
				|  |  | +                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x4\'\\);' +
 | 
	
		
			
				|  |  | +                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x5\'\\);' +
 | 
	
		
			
				|  |  | +                    '}'
 | 
	
		
			
				|  |  | +                );
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                let obfuscatedCode: string;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                before(() => {
 | 
	
		
			
				|  |  | +                    const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-count-const.js');
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    obfuscatedCode = JavaScriptObfuscator.obfuscate(
 | 
	
		
			
				|  |  | +                        code,
 | 
	
		
			
				|  |  | +                        {
 | 
	
		
			
				|  |  | +                            ...NO_ADDITIONAL_NODES_PRESET,
 | 
	
		
			
				|  |  | +                            stringArray: true,
 | 
	
		
			
				|  |  | +                            stringArrayThreshold: 1,
 | 
	
		
			
				|  |  | +                            stringArrayWrappersCount: 2
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +                    ).getObfuscatedCode();
 | 
	
		
			
				|  |  | +                });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                it('should add scope calls wrappers', () => {
 | 
	
		
			
				|  |  | +                    assert.match(obfuscatedCode, stringArrayCallRegExp);
 | 
	
		
			
				|  |  | +                });
 | 
	
		
			
				|  |  | +            });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +            describe('Variant #2: option value is bigger then count `literal` nodes in the scope', () => {
 | 
	
		
			
				|  |  | +                const stringArrayCallRegExp: RegExp = new RegExp(
 | 
	
		
			
				|  |  | +                    'function test *\\(\\) *{' +
 | 
	
		
			
				|  |  | +                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
 | 
	
		
			
				|  |  | +                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
 | 
	
		
			
				|  |  | +                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
 | 
	
		
			
				|  |  | +                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x3\'\\);' +
 | 
	
		
			
				|  |  | +                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x4\'\\);' +
 | 
	
		
			
				|  |  | +                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x5\'\\);' +
 | 
	
		
			
				|  |  | +                    '}'
 | 
	
		
			
				|  |  | +                );
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                let obfuscatedCode: string;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                before(() => {
 | 
	
		
			
				|  |  | +                    const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-count-const.js');
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    obfuscatedCode = JavaScriptObfuscator.obfuscate(
 | 
	
		
			
				|  |  | +                        code,
 | 
	
		
			
				|  |  | +                        {
 | 
	
		
			
				|  |  | +                            ...NO_ADDITIONAL_NODES_PRESET,
 | 
	
		
			
				|  |  | +                            stringArray: true,
 | 
	
		
			
				|  |  | +                            stringArrayThreshold: 1,
 | 
	
		
			
				|  |  | +                            stringArrayWrappersCount: 5
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +                    ).getObfuscatedCode();
 | 
	
		
			
				|  |  | +                });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                it('should add scope calls wrappers', () => {
 | 
	
		
			
				|  |  | +                    assert.match(obfuscatedCode, stringArrayCallRegExp);
 | 
	
		
			
				|  |  | +                });
 | 
	
		
			
				|  |  | +            });
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        describe('Variant #3: prevailing kind of variables', () => {
 | 
	
		
			
				|  |  |              const stringArrayCallRegExp: RegExp = new RegExp(
 | 
	
		
			
				|  |  |                      'return _0x([a-f0-9]){4,6};' +
 | 
	
		
			
				|  |  |                  '};' +
 | 
	
		
			
				|  |  | -                'var _0x([a-f0-9]){4} *= *_0x([a-f0-9]){4};' +
 | 
	
		
			
				|  |  | -                'var _0x([a-f0-9]){4} *= *_0x([a-f0-9]){4};' +
 | 
	
		
			
				|  |  | -                'var _0x([a-f0-9]){4} *= *_0x([a-f0-9]){4};' +
 | 
	
		
			
				|  |  | -                'var test *= *_0x([a-f0-9]){4}\\(\'0x0\'\\);'
 | 
	
		
			
				|  |  | +                'var _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
 | 
	
		
			
				|  |  | +                'var _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
 | 
	
		
			
				|  |  | +                'var foo *= *_0x([a-f0-9]){4,6}\\(\'0x0\'\\);' +
 | 
	
		
			
				|  |  | +                'var bar *= *_0x([a-f0-9]){4,6}\\(\'0x1\'\\);' +
 | 
	
		
			
				|  |  | +                'var baz *= *_0x([a-f0-9]){4,6}\\(\'0x2\'\\);'
 | 
	
		
			
				|  |  |              );
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              let obfuscatedCode: string;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              before(() => {
 | 
	
		
			
				|  |  | -                const code: string = readFileAsString(__dirname + '/fixtures/simple-input.js');
 | 
	
		
			
				|  |  | +                const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-count-var.js');
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  obfuscatedCode = JavaScriptObfuscator.obfuscate(
 | 
	
		
			
				|  |  |                      code,
 | 
	
	
		
			
				|  | @@ -85,22 +220,22 @@ describe('StringArrayTransformer', function () {
 | 
	
		
			
				|  |  |                          ...NO_ADDITIONAL_NODES_PRESET,
 | 
	
		
			
				|  |  |                          stringArray: true,
 | 
	
		
			
				|  |  |                          stringArrayThreshold: 1,
 | 
	
		
			
				|  |  | -                        stringArrayIntermediateVariablesCount: 3
 | 
	
		
			
				|  |  | +                        stringArrayWrappersCount: 2
 | 
	
		
			
				|  |  |                      }
 | 
	
		
			
				|  |  |                  ).getObfuscatedCode();
 | 
	
		
			
				|  |  |              });
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            it('should add intermediate calls to the string array calls wrapper', () => {
 | 
	
		
			
				|  |  | +            it('should add scope calls wrappers with a correct variables kind', () => {
 | 
	
		
			
				|  |  |                  assert.match(obfuscatedCode, stringArrayCallRegExp);
 | 
	
		
			
				|  |  |              });
 | 
	
		
			
				|  |  |          });
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        describe('Variant #2: correct evaluation of the intermediate calls', () => {
 | 
	
		
			
				|  |  | -            const expectedEvaluationResult: number = 15;
 | 
	
		
			
				|  |  | -            let evaluationResult: number;
 | 
	
		
			
				|  |  | +        describe('Variant #4: correct evaluation of the scope calls wrappers', () => {
 | 
	
		
			
				|  |  | +            const expectedEvaluationResult: string = 'aaabbbcccdddeee';
 | 
	
		
			
				|  |  | +            let evaluationResult: string;
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |              before(() => {
 | 
	
		
			
				|  |  | -                const code: string = readFileAsString(__dirname + '/fixtures/intermediate-variables-count-eval.js');
 | 
	
		
			
				|  |  | +                const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-count-eval.js');
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
 | 
	
		
			
				|  |  |                      code,
 | 
	
	
		
			
				|  | @@ -108,17 +243,57 @@ describe('StringArrayTransformer', function () {
 | 
	
		
			
				|  |  |                          ...NO_ADDITIONAL_NODES_PRESET,
 | 
	
		
			
				|  |  |                          stringArray: true,
 | 
	
		
			
				|  |  |                          stringArrayThreshold: 1,
 | 
	
		
			
				|  |  | -                        stringArrayIntermediateVariablesCount: 5
 | 
	
		
			
				|  |  | +                        stringArrayWrappersCount: 5
 | 
	
		
			
				|  |  |                      }
 | 
	
		
			
				|  |  |                  ).getObfuscatedCode();
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |                  evaluationResult = eval(obfuscatedCode);
 | 
	
		
			
				|  |  |              });
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            it('should correctly evaluate intermediate calls', () => {
 | 
	
		
			
				|  |  | +            it('should correctly evaluate scope calls wrappers', () => {
 | 
	
		
			
				|  |  |                  assert.equal(evaluationResult, expectedEvaluationResult);
 | 
	
		
			
				|  |  |              });
 | 
	
		
			
				|  |  |          });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        describe('Variant #5: `stringArrayWrappersChainedCalls` option is enabled', () => {
 | 
	
		
			
				|  |  | +            describe('Variant #1: correct evaluation of the string array wrappers chained calls', () => {
 | 
	
		
			
				|  |  | +                const samplesCount: number = 50;
 | 
	
		
			
				|  |  | +                const expectedEvaluationResult: string = 'aaabbbcccdddeee';
 | 
	
		
			
				|  |  | +                let isEvaluationSuccessful: boolean = true;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                before(() => {
 | 
	
		
			
				|  |  | +                    const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-chained-calls-eval.js');
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    for (let i = 0; i < samplesCount; i++) {
 | 
	
		
			
				|  |  | +                        const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
 | 
	
		
			
				|  |  | +                            code,
 | 
	
		
			
				|  |  | +                            {
 | 
	
		
			
				|  |  | +                                ...NO_ADDITIONAL_NODES_PRESET,
 | 
	
		
			
				|  |  | +                                stringArray: true,
 | 
	
		
			
				|  |  | +                                stringArrayThreshold: 1,
 | 
	
		
			
				|  |  | +                                stringArrayEncoding: [
 | 
	
		
			
				|  |  | +                                    StringArrayEncoding.None,
 | 
	
		
			
				|  |  | +                                    StringArrayEncoding.Rc4
 | 
	
		
			
				|  |  | +                                ],
 | 
	
		
			
				|  |  | +                                stringArrayWrappersChainedCalls: true,
 | 
	
		
			
				|  |  | +                                stringArrayWrappersCount: 5
 | 
	
		
			
				|  |  | +                            }
 | 
	
		
			
				|  |  | +                        ).getObfuscatedCode();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                        const evaluationResult: string = eval(obfuscatedCode);
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                        if (evaluationResult !== expectedEvaluationResult) {
 | 
	
		
			
				|  |  | +                            isEvaluationSuccessful = false;
 | 
	
		
			
				|  |  | +                            break;
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +                    }
 | 
	
		
			
				|  |  | +                });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                it('should correctly evaluate string array wrappers chained calls', () => {
 | 
	
		
			
				|  |  | +                    assert.equal(isEvaluationSuccessful, true);
 | 
	
		
			
				|  |  | +                });
 | 
	
		
			
				|  |  | +            });
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  |      });
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      describe('Variant #4: string contains non-latin and non-digit characters and `unicodeEscapeSequence` is disabled', () => {
 | 
	
	
		
			
				|  | @@ -342,7 +517,7 @@ describe('StringArrayTransformer', function () {
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      describe('Variant #11: none and base64 encoding', () => {
 | 
	
		
			
				|  |  |          describe('Variant #1: string array values', () => {
 | 
	
		
			
				|  |  | -            const samplesCount: number = 100;
 | 
	
		
			
				|  |  | +            const samplesCount: number = 300;
 | 
	
		
			
				|  |  |              const expectedMatchesChance: number = 0.5;
 | 
	
		
			
				|  |  |              const expectedMatchesDelta: number = 0.15;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -395,48 +570,170 @@ describe('StringArrayTransformer', function () {
 | 
	
		
			
				|  |  |              });
 | 
	
		
			
				|  |  |          });
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -        describe('Variant #2: `stringArrayIntermediateVariablesCount` option is enabled', () => {
 | 
	
		
			
				|  |  | -            const stringArrayIntermediateCallRegExp: RegExp = new RegExp(
 | 
	
		
			
				|  |  | -                    'return _0x([a-f0-9]){4,6};' +
 | 
	
		
			
				|  |  | -                '};' +
 | 
	
		
			
				|  |  | -                'var _0x([a-f0-9]){4} *= *_0x([a-f0-9]){4};' +
 | 
	
		
			
				|  |  | -                'var _0x([a-f0-9]){4} *= *_0x([a-f0-9]){4};' +
 | 
	
		
			
				|  |  | -                'var _0x([a-f0-9]){4} *= *_0x([a-f0-9]){4};' +
 | 
	
		
			
				|  |  | -                'var _0x([a-f0-9]){4} *= *_0x([a-f0-9]){4};' +
 | 
	
		
			
				|  |  | -                'var _0x([a-f0-9]){4} *= *_0x([a-f0-9]){4};' +
 | 
	
		
			
				|  |  | -                'var _0x([a-f0-9]){4} *= *_0x([a-f0-9]){4};' +
 | 
	
		
			
				|  |  | -                'var test *= *_0x([a-f0-9]){4}\\(\'0x0\'\\);'
 | 
	
		
			
				|  |  | -            );
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            let obfuscatedCode: string;
 | 
	
		
			
				|  |  | -
 | 
	
		
			
				|  |  | -            before(() => {
 | 
	
		
			
				|  |  | -                const code: string = readFileAsString(__dirname + '/fixtures/simple-input.js');
 | 
	
		
			
				|  |  | +        describe('Variant #2: `stringArrayWrappersCount` option is enabled', () => {
 | 
	
		
			
				|  |  | +            describe('Variant #1: root scope', () => {
 | 
	
		
			
				|  |  | +                describe('Variant #1: `1` scope calls wrapper for each encoding type', () => {
 | 
	
		
			
				|  |  | +                    const stringArrayWrappersRegExp: RegExp = new RegExp(
 | 
	
		
			
				|  |  | +                            'return _0x([a-f0-9]){4,6};' +
 | 
	
		
			
				|  |  | +                        '};' +
 | 
	
		
			
				|  |  | +                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
 | 
	
		
			
				|  |  | +                        // this one may be added or not depends on:
 | 
	
		
			
				|  |  | +                        // if all literal values encoded with a single encoding or not
 | 
	
		
			
				|  |  | +                        '(?:const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};)?' +
 | 
	
		
			
				|  |  | +                        'const foo *= *_0x([a-f0-9]){4,6}\\(\'0x0\'\\);' +
 | 
	
		
			
				|  |  | +                        'const bar *= *_0x([a-f0-9]){4,6}\\(\'0x1\'\\);' +
 | 
	
		
			
				|  |  | +                        'const baz *= *_0x([a-f0-9]){4,6}\\(\'0x2\'\\);'
 | 
	
		
			
				|  |  | +                    );
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    let obfuscatedCode: string;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    before(() => {
 | 
	
		
			
				|  |  | +                        const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-count-const.js');
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                        obfuscatedCode = JavaScriptObfuscator.obfuscate(
 | 
	
		
			
				|  |  | +                            code,
 | 
	
		
			
				|  |  | +                            {
 | 
	
		
			
				|  |  | +                                ...NO_ADDITIONAL_NODES_PRESET,
 | 
	
		
			
				|  |  | +                                stringArray: true,
 | 
	
		
			
				|  |  | +                                stringArrayEncoding: [
 | 
	
		
			
				|  |  | +                                    StringArrayEncoding.None,
 | 
	
		
			
				|  |  | +                                    StringArrayEncoding.Base64
 | 
	
		
			
				|  |  | +                                ],
 | 
	
		
			
				|  |  | +                                stringArrayWrappersCount: 1,
 | 
	
		
			
				|  |  | +                                stringArrayThreshold: 1
 | 
	
		
			
				|  |  | +                            }
 | 
	
		
			
				|  |  | +                        ).getObfuscatedCode();
 | 
	
		
			
				|  |  | +                    });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    it('should add scope calls wrappers for both `none` and `base64` string array wrappers', () => {
 | 
	
		
			
				|  |  | +                        assert.match(obfuscatedCode, stringArrayWrappersRegExp);
 | 
	
		
			
				|  |  | +                    });
 | 
	
		
			
				|  |  | +                });
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -                obfuscatedCode = JavaScriptObfuscator.obfuscate(
 | 
	
		
			
				|  |  | -                    code,
 | 
	
		
			
				|  |  | -                    {
 | 
	
		
			
				|  |  | -                        ...NO_ADDITIONAL_NODES_PRESET,
 | 
	
		
			
				|  |  | -                        stringArray: true,
 | 
	
		
			
				|  |  | -                        stringArrayEncoding: [
 | 
	
		
			
				|  |  | -                            StringArrayEncoding.None,
 | 
	
		
			
				|  |  | -                            StringArrayEncoding.Base64
 | 
	
		
			
				|  |  | -                        ],
 | 
	
		
			
				|  |  | -                        stringArrayIntermediateVariablesCount: 3,
 | 
	
		
			
				|  |  | -                        stringArrayThreshold: 1
 | 
	
		
			
				|  |  | -                    }
 | 
	
		
			
				|  |  | -                ).getObfuscatedCode();
 | 
	
		
			
				|  |  | +                describe('Variant #2: `2` scope calls wrappers for each encoding type', () => {
 | 
	
		
			
				|  |  | +                    const stringArrayWrappersRegExp: RegExp = new RegExp(
 | 
	
		
			
				|  |  | +                            'return _0x([a-f0-9]){4,6};' +
 | 
	
		
			
				|  |  | +                        '};' +
 | 
	
		
			
				|  |  | +                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
 | 
	
		
			
				|  |  | +                        'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
 | 
	
		
			
				|  |  | +                        // this one may be added or not depends on:
 | 
	
		
			
				|  |  | +                        // if all literal values encoded with a single encoding or not
 | 
	
		
			
				|  |  | +                        '(?:const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};)?' +
 | 
	
		
			
				|  |  | +                        'const foo *= *_0x([a-f0-9]){4,6}\\(\'0x0\'\\);' +
 | 
	
		
			
				|  |  | +                        'const bar *= *_0x([a-f0-9]){4,6}\\(\'0x1\'\\);' +
 | 
	
		
			
				|  |  | +                        'const baz *= *_0x([a-f0-9]){4,6}\\(\'0x2\'\\);'
 | 
	
		
			
				|  |  | +                    );
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    let obfuscatedCode: string;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    before(() => {
 | 
	
		
			
				|  |  | +                        const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-count-const.js');
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                        obfuscatedCode = JavaScriptObfuscator.obfuscate(
 | 
	
		
			
				|  |  | +                            code,
 | 
	
		
			
				|  |  | +                            {
 | 
	
		
			
				|  |  | +                                ...NO_ADDITIONAL_NODES_PRESET,
 | 
	
		
			
				|  |  | +                                stringArray: true,
 | 
	
		
			
				|  |  | +                                stringArrayEncoding: [
 | 
	
		
			
				|  |  | +                                    StringArrayEncoding.None,
 | 
	
		
			
				|  |  | +                                    StringArrayEncoding.Base64
 | 
	
		
			
				|  |  | +                                ],
 | 
	
		
			
				|  |  | +                                stringArrayWrappersCount: 2,
 | 
	
		
			
				|  |  | +                                stringArrayThreshold: 1
 | 
	
		
			
				|  |  | +                            }
 | 
	
		
			
				|  |  | +                        ).getObfuscatedCode();
 | 
	
		
			
				|  |  | +                    });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    it('should add scope calls wrappers for both `none` and `base64` string array wrappers', () => {
 | 
	
		
			
				|  |  | +                        assert.match(obfuscatedCode, stringArrayWrappersRegExp);
 | 
	
		
			
				|  |  | +                    });
 | 
	
		
			
				|  |  | +                });
 | 
	
		
			
				|  |  |              });
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  | -            it('should add intermediate variables for both `none` and `base64` string array wrappers', () => {
 | 
	
		
			
				|  |  | -                assert.match(obfuscatedCode, stringArrayIntermediateCallRegExp);
 | 
	
		
			
				|  |  | +            describe('Variant #2: function scope', () => {
 | 
	
		
			
				|  |  | +                describe('Variant #1: `1` scope calls wrapper for each encoding type', () => {
 | 
	
		
			
				|  |  | +                    const stringArrayWrappersRegExp: RegExp = new RegExp(
 | 
	
		
			
				|  |  | +                        'function test *\\( *\\) *{' +
 | 
	
		
			
				|  |  | +                            'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
 | 
	
		
			
				|  |  | +                            // this one may be added or not depends on:
 | 
	
		
			
				|  |  | +                            // if all literal values encoded with a single encoding or not
 | 
	
		
			
				|  |  | +                            '(?:const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};)?' +
 | 
	
		
			
				|  |  | +                            'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x3\'\\);' +
 | 
	
		
			
				|  |  | +                            'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x4\'\\);' +
 | 
	
		
			
				|  |  | +                            'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x5\'\\);' +
 | 
	
		
			
				|  |  | +                        '}'
 | 
	
		
			
				|  |  | +                    );
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    let obfuscatedCode: string;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    before(() => {
 | 
	
		
			
				|  |  | +                        const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-count-const.js');
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                        obfuscatedCode = JavaScriptObfuscator.obfuscate(
 | 
	
		
			
				|  |  | +                            code,
 | 
	
		
			
				|  |  | +                            {
 | 
	
		
			
				|  |  | +                                ...NO_ADDITIONAL_NODES_PRESET,
 | 
	
		
			
				|  |  | +                                stringArray: true,
 | 
	
		
			
				|  |  | +                                stringArrayEncoding: [
 | 
	
		
			
				|  |  | +                                    StringArrayEncoding.None,
 | 
	
		
			
				|  |  | +                                    StringArrayEncoding.Base64
 | 
	
		
			
				|  |  | +                                ],
 | 
	
		
			
				|  |  | +                                stringArrayWrappersCount: 1,
 | 
	
		
			
				|  |  | +                                stringArrayThreshold: 1
 | 
	
		
			
				|  |  | +                            }
 | 
	
		
			
				|  |  | +                        ).getObfuscatedCode();
 | 
	
		
			
				|  |  | +                    });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    it('should add scope calls wrappers for both `none` and `base64` string array wrappers', () => {
 | 
	
		
			
				|  |  | +                        assert.match(obfuscatedCode, stringArrayWrappersRegExp);
 | 
	
		
			
				|  |  | +                    });
 | 
	
		
			
				|  |  | +                });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                describe('Variant #2: `2` scope calls wrappers for each encoding type', () => {
 | 
	
		
			
				|  |  | +                    const stringArrayWrappersRegExp: RegExp = new RegExp(
 | 
	
		
			
				|  |  | +                        'function test *\\( *\\) *{' +
 | 
	
		
			
				|  |  | +                            'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
 | 
	
		
			
				|  |  | +                            'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
 | 
	
		
			
				|  |  | +                            // this one may be added or not depends on:
 | 
	
		
			
				|  |  | +                            // if all literal values encoded with a single encoding or not
 | 
	
		
			
				|  |  | +                            '(?:const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};)?' +
 | 
	
		
			
				|  |  | +                            'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x3\'\\);' +
 | 
	
		
			
				|  |  | +                            'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x4\'\\);' +
 | 
	
		
			
				|  |  | +                            'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x5\'\\);' +
 | 
	
		
			
				|  |  | +                        '}'
 | 
	
		
			
				|  |  | +                    );
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    let obfuscatedCode: string;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    before(() => {
 | 
	
		
			
				|  |  | +                        const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-count-const.js');
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                        obfuscatedCode = JavaScriptObfuscator.obfuscate(
 | 
	
		
			
				|  |  | +                            code,
 | 
	
		
			
				|  |  | +                            {
 | 
	
		
			
				|  |  | +                                ...NO_ADDITIONAL_NODES_PRESET,
 | 
	
		
			
				|  |  | +                                stringArray: true,
 | 
	
		
			
				|  |  | +                                stringArrayEncoding: [
 | 
	
		
			
				|  |  | +                                    StringArrayEncoding.None,
 | 
	
		
			
				|  |  | +                                    StringArrayEncoding.Base64
 | 
	
		
			
				|  |  | +                                ],
 | 
	
		
			
				|  |  | +                                stringArrayWrappersCount: 2,
 | 
	
		
			
				|  |  | +                                stringArrayThreshold: 1
 | 
	
		
			
				|  |  | +                            }
 | 
	
		
			
				|  |  | +                        ).getObfuscatedCode();
 | 
	
		
			
				|  |  | +                    });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    it('should add scope calls wrappers for both `none` and `base64` string array wrappers', () => {
 | 
	
		
			
				|  |  | +                        assert.match(obfuscatedCode, stringArrayWrappersRegExp);
 | 
	
		
			
				|  |  | +                    });
 | 
	
		
			
				|  |  | +                });
 | 
	
		
			
				|  |  |              });
 | 
	
		
			
				|  |  |          });
 | 
	
		
			
				|  |  |      });
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      describe('Variant #12: none and rc4 encoding', () => {
 | 
	
		
			
				|  |  |          describe('Variant #1: string array calls wrapper call', () => {
 | 
	
		
			
				|  |  | -            const samplesCount: number = 100;
 | 
	
		
			
				|  |  | +            const samplesCount: number = 300;
 | 
	
		
			
				|  |  |              const expectedMatchesChance: number = 0.5;
 | 
	
		
			
				|  |  |              const expectedMatchesDelta: number = 0.15;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -488,11 +785,42 @@ describe('StringArrayTransformer', function () {
 | 
	
		
			
				|  |  |                  assert.closeTo(rc4EncodingMatchesChance, expectedMatchesChance, expectedMatchesDelta);
 | 
	
		
			
				|  |  |              });
 | 
	
		
			
				|  |  |          });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        describe('Variant #2: `stringArrayWrappersCount` option is enabled', () => {
 | 
	
		
			
				|  |  | +            describe('Variant #1: correct evaluation of the scope calls wrappers', () => {
 | 
	
		
			
				|  |  | +                const expectedEvaluationResult: string = 'aaabbbcccdddeee';
 | 
	
		
			
				|  |  | +                let evaluationResult: string;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                before(() => {
 | 
	
		
			
				|  |  | +                    const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-count-eval.js');
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
 | 
	
		
			
				|  |  | +                        code,
 | 
	
		
			
				|  |  | +                        {
 | 
	
		
			
				|  |  | +                            ...NO_ADDITIONAL_NODES_PRESET,
 | 
	
		
			
				|  |  | +                            stringArray: true,
 | 
	
		
			
				|  |  | +                            stringArrayThreshold: 1,
 | 
	
		
			
				|  |  | +                            stringArrayEncoding: [
 | 
	
		
			
				|  |  | +                                StringArrayEncoding.None,
 | 
	
		
			
				|  |  | +                                StringArrayEncoding.Rc4
 | 
	
		
			
				|  |  | +                            ],
 | 
	
		
			
				|  |  | +                            stringArrayWrappersCount: 5
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +                    ).getObfuscatedCode();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    evaluationResult = eval(obfuscatedCode);
 | 
	
		
			
				|  |  | +                });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                it('should correctly evaluate scope calls wrappers', () => {
 | 
	
		
			
				|  |  | +                    assert.equal(evaluationResult, expectedEvaluationResult);
 | 
	
		
			
				|  |  | +                });
 | 
	
		
			
				|  |  | +            });
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  |      });
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      describe('Variant #13: base64 and rc4 encoding', () => {
 | 
	
		
			
				|  |  |          describe('Variant #1: single string literal', () => {
 | 
	
		
			
				|  |  | -            const samplesCount: number = 100;
 | 
	
		
			
				|  |  | +            const samplesCount: number = 300;
 | 
	
		
			
				|  |  |              const expectedMatchesChance: number = 0.5;
 | 
	
		
			
				|  |  |              const expectedMatchesDelta: number = 0.15;
 | 
	
		
			
				|  |  |  
 | 
	
	
		
			
				|  | @@ -544,6 +872,37 @@ describe('StringArrayTransformer', function () {
 | 
	
		
			
				|  |  |                  assert.closeTo(rc4EncodingMatchesChance, expectedMatchesChance, expectedMatchesDelta);
 | 
	
		
			
				|  |  |              });
 | 
	
		
			
				|  |  |          });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +        describe('Variant #2: `stringArrayWrappersCount` option is enabled', () => {
 | 
	
		
			
				|  |  | +            describe('Variant #1: correct evaluation of the scope calls wrappers', () => {
 | 
	
		
			
				|  |  | +                const expectedEvaluationResult: string = 'aaabbbcccdddeee';
 | 
	
		
			
				|  |  | +                let evaluationResult: string;
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                before(() => {
 | 
	
		
			
				|  |  | +                    const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-count-eval.js');
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
 | 
	
		
			
				|  |  | +                        code,
 | 
	
		
			
				|  |  | +                        {
 | 
	
		
			
				|  |  | +                            ...NO_ADDITIONAL_NODES_PRESET,
 | 
	
		
			
				|  |  | +                            stringArray: true,
 | 
	
		
			
				|  |  | +                            stringArrayThreshold: 1,
 | 
	
		
			
				|  |  | +                            stringArrayEncoding: [
 | 
	
		
			
				|  |  | +                                StringArrayEncoding.Base64,
 | 
	
		
			
				|  |  | +                                StringArrayEncoding.Rc4
 | 
	
		
			
				|  |  | +                            ],
 | 
	
		
			
				|  |  | +                            stringArrayWrappersCount: 5
 | 
	
		
			
				|  |  | +                        }
 | 
	
		
			
				|  |  | +                    ).getObfuscatedCode();
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                    evaluationResult = eval(obfuscatedCode);
 | 
	
		
			
				|  |  | +                });
 | 
	
		
			
				|  |  | +
 | 
	
		
			
				|  |  | +                it('should correctly evaluate scope calls wrappers', () => {
 | 
	
		
			
				|  |  | +                    assert.equal(evaluationResult, expectedEvaluationResult);
 | 
	
		
			
				|  |  | +                });
 | 
	
		
			
				|  |  | +            });
 | 
	
		
			
				|  |  | +        });
 | 
	
		
			
				|  |  |      });
 | 
	
		
			
				|  |  |  
 | 
	
		
			
				|  |  |      describe('Variant #14: `stringArrayThreshold` option value', () => {
 |