import { assert } from 'chai'; import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes'; import { readFileAsString } from '../../../../helpers/readFileAsString'; import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade'; describe('ObjectExpressionKeysTransformer', () => { const variableMatch: string = '_0x([a-f0-9]){4,6}'; describe('transformation of object keys', () => { describe('Variant #1: simple', () => { const match: string = `` + `var *${variableMatch} *= *{};` + `${variableMatch}\\['foo'] *= *'bar';` + `${variableMatch}\\['baz'] *= *'bark';` + ``; const regExp: RegExp = new RegExp(match); let obfuscatedCode: string; before(() => { const code: string = readFileAsString(__dirname + '/fixtures/simple.js'); obfuscatedCode = JavaScriptObfuscator.obfuscate( code, { ...NO_ADDITIONAL_NODES_PRESET, transformObjectKeys: true } ).getObfuscatedCode(); }); it('should correctly transform object keys', () => { assert.match(obfuscatedCode, regExp); }); }); describe('Variant #2: nested objects #1', () => { const match: string = `` + `var *${variableMatch} *= *{};` + `${variableMatch}\\['foo'] *= *'bar';` + `${variableMatch}\\['inner'] *= *{};` + `${variableMatch}\\['inner']\\['inner1'] *= *{};` + `${variableMatch}\\['inner']\\['inner1']\\['baz'] *= *'bark';` + ``; const regExp: RegExp = new RegExp(match); let obfuscatedCode: string; before(() => { const code: string = readFileAsString(__dirname + '/fixtures/nested-objects-1.js'); obfuscatedCode = JavaScriptObfuscator.obfuscate( code, { ...NO_ADDITIONAL_NODES_PRESET, transformObjectKeys: true } ).getObfuscatedCode(); }); it('should correctly transform object keys', () => { assert.match(obfuscatedCode, regExp); }); }); describe('Variant #3: nested objects #2', () => { const match: string = `` + `var *${variableMatch} *= *{};` + `${variableMatch}\\['foo'] *= *'bar';` + `${variableMatch}\\['inner'] *= *{};` + `${variableMatch}\\['ball'] *= *'door';` + `${variableMatch}\\['inner']\\['baz'] *= *'bark';` + `${variableMatch}\\['inner']\\['inner1'] *= *{};` + `${variableMatch}\\['inner']\\['cow'] *= *'bear';` + `${variableMatch}\\['inner']\\['inner1']\\['hawk'] *= *'geek';` + ``; const regExp: RegExp = new RegExp(match); let obfuscatedCode: string; before(() => { const code: string = readFileAsString(__dirname + '/fixtures/nested-objects-2.js'); obfuscatedCode = JavaScriptObfuscator.obfuscate( code, { ...NO_ADDITIONAL_NODES_PRESET, transformObjectKeys: true } ).getObfuscatedCode(); }); it('should correctly transform object keys', () => { assert.match(obfuscatedCode, regExp); }); }); describe('Variant #4: correct integration with control flow flattening object', () => { const match: string = `` + `var *${variableMatch} *= *{};` + `${variableMatch}\\['\\w{5}'] *= *function *\\(${variableMatch}, *${variableMatch}\\) *{` + `return *${variableMatch} *\\+ *${variableMatch};` + `};` + `var *${variableMatch} *= *${variableMatch}\\['\\w{5}']\\(0x1, *0x2\\);` + ``; const regExp: RegExp = new RegExp(match); let obfuscatedCode: string; before(() => { const code: string = readFileAsString(__dirname + '/fixtures/integration-with-control-flow-flattening.js'); obfuscatedCode = JavaScriptObfuscator.obfuscate( code, { ...NO_ADDITIONAL_NODES_PRESET, controlFlowFlattening: true, controlFlowFlatteningThreshold: 1, transformObjectKeys: true } ).getObfuscatedCode(); }); it('should correctly transform object keys', () => { assert.match(obfuscatedCode, regExp); }); }); describe('Variant #5: variable declaration without initialization', () => { const match: string = `` + `var *${variableMatch};` + `${variableMatch} *= *{};` + `${variableMatch}\\['foo'] *= *'bar';` + `${variableMatch}\\['baz'] *= *'bark';` + ``; const regExp: RegExp = new RegExp(match); let obfuscatedCode: string; before(() => { const code: string = readFileAsString(__dirname + '/fixtures/variable-declaration-without-initialization.js'); obfuscatedCode = JavaScriptObfuscator.obfuscate( code, { ...NO_ADDITIONAL_NODES_PRESET, transformObjectKeys: true } ).getObfuscatedCode(); }); it('shouldn\'t transform object keys', () => { assert.match(obfuscatedCode, regExp); }); }); }); describe('member expression as host of object expression', () => { describe('Variant #1: simple', () => { const match: string = `` + `this\\['state'] *= *{};` + `this\\['state']\\['foo'] *= *'bar';` + `this\\['state']\\['baz'] *= *'bark';` + ``; const regExp: RegExp = new RegExp(match); let obfuscatedCode: string; before(() => { const code: string = readFileAsString(__dirname + '/fixtures/member-expression-host-1.js'); obfuscatedCode = JavaScriptObfuscator.obfuscate( code, { ...NO_ADDITIONAL_NODES_PRESET, transformObjectKeys: true } ).getObfuscatedCode(); }); it('should correctly transform object keys', () => { assert.match(obfuscatedCode, regExp); }); }); describe('Variant #2: long members chain', () => { const match: string = `` + `this\\['state']\\['foo'] *= *{};` + `this\\['state']\\['foo']\\['foo'] *= *'bar';` + `this\\['state']\\['foo']\\['baz'] *= *'bark';` + ``; const regExp: RegExp = new RegExp(match); let obfuscatedCode: string; before(() => { const code: string = readFileAsString(__dirname + '/fixtures/member-expression-host-2.js'); obfuscatedCode = JavaScriptObfuscator.obfuscate( code, { ...NO_ADDITIONAL_NODES_PRESET, transformObjectKeys: true } ).getObfuscatedCode(); }); it('should correctly transform object keys', () => { assert.match(obfuscatedCode, regExp); }); }); }); describe('correct placement of expression statements', () => { describe('Variant #1: if statement', () => { const match: string = `` + `if *\\(!!\\[]\\) *{` + `var *${variableMatch} *= *{};` + `${variableMatch}\\['foo'] *= *'bar';` + `}` + ``; const regExp: RegExp = new RegExp(match); let obfuscatedCode: string; before(() => { const code: string = readFileAsString(__dirname + '/fixtures/placement-inside-if-statement.js'); obfuscatedCode = JavaScriptObfuscator.obfuscate( code, { ...NO_ADDITIONAL_NODES_PRESET, transformObjectKeys: true } ).getObfuscatedCode(); }); it('should correctly transform object keys', () => { assert.match(obfuscatedCode, regExp); }); }); describe('Variant #2: try statement', () => { const match: string = `` + `try *{` + `var *${variableMatch} *= *{};` + `${variableMatch}\\['foo'] *= *'bar';` + `} *catch *\\(${variableMatch}\\) *{` + `}` + ``; const regExp: RegExp = new RegExp(match); let obfuscatedCode: string; before(() => { const code: string = readFileAsString(__dirname + '/fixtures/placement-inside-try-statement.js'); obfuscatedCode = JavaScriptObfuscator.obfuscate( code, { ...NO_ADDITIONAL_NODES_PRESET, transformObjectKeys: true } ).getObfuscatedCode(); }); it('should correctly transform object keys', () => { assert.match(obfuscatedCode, regExp); }); }); describe('Variant #3: catch clause statement', () => { const match: string = `` + `try *{` + `} *catch *\\(${variableMatch}\\) *{` + `var *${variableMatch} *= *{};` + `${variableMatch}\\['foo'] *= *'bar';` + `}` + ``; const regExp: RegExp = new RegExp(match); let obfuscatedCode: string; before(() => { const code: string = readFileAsString(__dirname + '/fixtures/placement-inside-catch-clause.js'); obfuscatedCode = JavaScriptObfuscator.obfuscate( code, { ...NO_ADDITIONAL_NODES_PRESET, transformObjectKeys: true } ).getObfuscatedCode(); }); it('should correctly transform object keys', () => { assert.match(obfuscatedCode, regExp); }); }); describe('Variant #4: switch catch statement', () => { const match: string = `` + `switch *\\(!!\\[]\\) *{` + `case *!!\\[]:` + `var *${variableMatch} *= *{};` + `${variableMatch}\\['foo'] *= *'bar';` + `}` + ``; const regExp: RegExp = new RegExp(match); let obfuscatedCode: string; before(() => { const code: string = readFileAsString(__dirname + '/fixtures/placement-inside-switch-case.js'); obfuscatedCode = JavaScriptObfuscator.obfuscate( code, { ...NO_ADDITIONAL_NODES_PRESET, transformObjectKeys: true } ).getObfuscatedCode(); }); it('should transform object keys', () => { assert.match(obfuscatedCode, regExp); }); }); describe('Variant #5: variable declarator with object call', () => { describe('Variant #1', () => { const match: string = `` + `const *${variableMatch} *= *{}; *` + `${variableMatch}\\['foo'] *= *'foo'; *` + `const *${variableMatch} *= *${variableMatch}\\['foo'];` + ``; const regExp: RegExp = new RegExp(match); let obfuscatedCode: string; before(() => { const code: string = readFileAsString(__dirname + '/fixtures/variable-declarator-with-object-call-1.js'); obfuscatedCode = JavaScriptObfuscator.obfuscate( code, { ...NO_ADDITIONAL_NODES_PRESET, transformObjectKeys: true } ).getObfuscatedCode(); }); it('should correctly transform object keys', () => { assert.match(obfuscatedCode, regExp); }); }); describe('Variant #2', () => { const match: string = `` + `const *${variableMatch} *= *0x1, *` + `${variableMatch} *= *{}; *` + `${variableMatch}\\['foo'] *= *'foo'; *` + `const *${variableMatch} *= *${variableMatch}\\['foo'];` + ``; const regExp: RegExp = new RegExp(match); let obfuscatedCode: string; before(() => { const code: string = readFileAsString(__dirname + '/fixtures/variable-declarator-with-object-call-2.js'); obfuscatedCode = JavaScriptObfuscator.obfuscate( code, { ...NO_ADDITIONAL_NODES_PRESET, transformObjectKeys: true } ).getObfuscatedCode(); }); it('should correctly transform object keys', () => { assert.match(obfuscatedCode, regExp); }); }); describe('Variant #3: two objects', () => { const match: string = `` + `const *${variableMatch} *= *{}, *` + `${variableMatch} *= *{'bar': *'bar'}, *` + `${variableMatch} *= *${variableMatch}\\['bar']; *` + `${variableMatch}\\['foo'] *= *'foo';` + ``; const regExp: RegExp = new RegExp(match); let obfuscatedCode: string; before(() => { const code: string = readFileAsString(__dirname + '/fixtures/variable-declarator-with-object-call-3.js'); obfuscatedCode = JavaScriptObfuscator.obfuscate( code, { ...NO_ADDITIONAL_NODES_PRESET, transformObjectKeys: true } ).getObfuscatedCode(); }); it('should correctly transform first object keys and ignore second object keys', () => { assert.match(obfuscatedCode, regExp); }); }); }); }); describe('Ignore transformation', () => { describe('Variant #1: disabled option', () => { const match: string = `` + `var *${variableMatch} *= *{` + `'foo': *'bar',` + `'baz': *'bark'` + `}` + ``; const regExp: RegExp = new RegExp(match); let obfuscatedCode: string; before(() => { const code: string = readFileAsString(__dirname + '/fixtures/simple.js'); obfuscatedCode = JavaScriptObfuscator.obfuscate( code, { ...NO_ADDITIONAL_NODES_PRESET } ).getObfuscatedCode(); }); it('shouldn\'t transform object keys', () => { assert.match(obfuscatedCode, regExp); }); }); describe('Variant #2: empty object expression', () => { const match: string = `var *${variableMatch} *= *{};`; const regExp: RegExp = new RegExp(match); let obfuscatedCode: string; before(() => { const code: string = readFileAsString(__dirname + '/fixtures/empty-object-expression.js'); obfuscatedCode = JavaScriptObfuscator.obfuscate( code, { ...NO_ADDITIONAL_NODES_PRESET } ).getObfuscatedCode(); }); it('shouldn\'t transform object keys', () => { assert.match(obfuscatedCode, regExp); }); }); describe('Variant #3: variable declarator object call inside other variable declarator', () => { describe('Variant #1', () => { const match: string = `` + `const *${variableMatch} *= *{'foo': *'foo'}, *` + `${variableMatch} *= *${variableMatch}\\['foo'];` + ``; const regExp: RegExp = new RegExp(match); let obfuscatedCode: string; before(() => { const code: string = readFileAsString(__dirname + '/fixtures/variable-declarator-with-object-call-ignore-1.js'); obfuscatedCode = JavaScriptObfuscator.obfuscate( code, { ...NO_ADDITIONAL_NODES_PRESET, transformObjectKeys: true } ).getObfuscatedCode(); }); it('shouldn\'t transform object keys', () => { assert.match(obfuscatedCode, regExp); }); }); describe('Variant #2', () => { const match: string = `` + `const *${variableMatch} *= *{'foo': *'foo'}, *` + `${variableMatch} *= *\\[${variableMatch}\\['foo']];` + ``; const regExp: RegExp = new RegExp(match); let obfuscatedCode: string; before(() => { const code: string = readFileAsString(__dirname + '/fixtures/variable-declarator-with-object-call-ignore-2.js'); obfuscatedCode = JavaScriptObfuscator.obfuscate( code, { ...NO_ADDITIONAL_NODES_PRESET, transformObjectKeys: true } ).getObfuscatedCode(); }); it('shouldn\'t transform object keys', () => { assert.match(obfuscatedCode, regExp); }); }); }); describe('Variant #4: assignment expression and member expression', () => { const match: string = `` + `var ${variableMatch}; *` + `\\(${variableMatch} *= *{'foo': *'bar'}\\)\\['baz'] *= *${variableMatch}\\['foo'];` + ``; const regExp: RegExp = new RegExp(match); let obfuscatedCode: string; before(() => { const code: string = readFileAsString(__dirname + '/fixtures/assignment-expression-and-member-expression.js'); obfuscatedCode = JavaScriptObfuscator.obfuscate( code, { ...NO_ADDITIONAL_NODES_PRESET, transformObjectKeys: true } ).getObfuscatedCode(); }); it('shouldn\'t transform object keys', () => { assert.match(obfuscatedCode, regExp); }); }); }); });