Skip to content

Commit

Permalink
Added ObjectPatternPropertiesTransformer. Added helper for stubbing s…
Browse files Browse the repository at this point in the history
…elected node transformers.
  • Loading branch information
sanex3339 committed Jul 31, 2020
1 parent f360d0e commit c85f6c0
Show file tree
Hide file tree
Showing 18 changed files with 227 additions and 54 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
Change Log

v1.8.2
---
* Improved obfuscation of destructured variables. https://github.com/javascript-obfuscator/javascript-obfuscator/issues/688

v1.8.1
---
* Fixed runtime error `Uncaught SyntaxError: yield is a reserved identifier` when `deadCodeInjection` is enabled
Expand Down
10 changes: 5 additions & 5 deletions dist/index.browser.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/index.cli.js

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion dist/index.js

Large diffs are not rendered by default.

12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "javascript-obfuscator",
"version": "1.8.1",
"version": "1.8.2",
"description": "JavaScript obfuscator",
"keywords": [
"obfuscator",
Expand Down Expand Up @@ -54,7 +54,7 @@
"@types/mkdirp": "1.0.1",
"@types/mocha": "8.0.0",
"@types/multimatch": "4.0.0",
"@types/node": "14.0.26",
"@types/node": "14.0.27",
"@types/rimraf": "3.0.0",
"@types/sinon": "9.0.4",
"@types/string-template": "1.0.2",
Expand All @@ -65,13 +65,13 @@
"coveralls": "3.1.0",
"eslint": "7.5.0",
"eslint-plugin-import": "2.22.0",
"eslint-plugin-jsdoc": "30.0.3",
"eslint-plugin-jsdoc": "30.1.0",
"eslint-plugin-no-null": "1.0.2",
"eslint-plugin-prefer-arrow": "1.2.2",
"eslint-plugin-unicorn": "21.0.0",
"fork-ts-checker-notifier-webpack-plugin": "3.0.0",
"fork-ts-checker-webpack-plugin": "5.0.11",
"mocha": "8.0.1",
"fork-ts-checker-webpack-plugin": "5.0.12",
"mocha": "8.1.0",
"nyc": "15.1.0",
"pjson": "1.0.9",
"pre-commit": "1.2.2",
Expand All @@ -81,7 +81,7 @@
"ts-loader": "8.0.1",
"ts-node": "8.10.2",
"typescript": "3.9.7",
"webpack": "4.44.0",
"webpack": "4.44.1",
"webpack-cli": "3.3.12",
"webpack-node-externals": "2.5.0"
},
Expand Down
1 change: 1 addition & 0 deletions src/JavaScriptObfuscator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export class JavaScriptObfuscator implements IJavaScriptObfuscator {
NodeTransformer.ObfuscatingGuardsTransformer,
NodeTransformer.ObjectExpressionKeysTransformer,
NodeTransformer.ObjectExpressionTransformer,
NodeTransformer.ObjectPatternPropertiesTransformer,
NodeTransformer.ParentificationTransformer,
NodeTransformer.ScopeIdentifiersTransformer,
NodeTransformer.SplitStringTransformer,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { MethodDefinitionTransformer } from '../../../node-transformers/converti
import { NumberToNumericalExpressionTransformer } from '../../../node-transformers/converting-transformers/NumberToNumericalExpressionTransformer';
import { ObjectExpressionKeysTransformer } from '../../../node-transformers/converting-transformers/ObjectExpressionKeysTransformer';
import { ObjectExpressionTransformer } from '../../../node-transformers/converting-transformers/ObjectExpressionTransformer';
import { ObjectPatternPropertiesTransformer } from '../../../node-transformers/converting-transformers/ObjectPatternPropertiesTransformer';
import { SplitStringTransformer } from '../../../node-transformers/converting-transformers/SplitStringTransformer';
import { TemplateLiteralTransformer } from '../../../node-transformers/converting-transformers/TemplateLiteralTransformer';

Expand All @@ -41,6 +42,10 @@ export const convertingTransformersModule: interfaces.ContainerModule = new Cont
.to(ObjectExpressionTransformer)
.whenTargetNamed(NodeTransformer.ObjectExpressionTransformer);

bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(ObjectPatternPropertiesTransformer)
.whenTargetNamed(NodeTransformer.ObjectPatternPropertiesTransformer);

bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(SplitStringTransformer)
.whenTargetNamed(NodeTransformer.SplitStringTransformer);
Expand Down
1 change: 1 addition & 0 deletions src/enums/node-transformers/NodeTransformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ export enum NodeTransformer {
ObfuscatingGuardsTransformer = 'ObfuscatingGuardsTransformer',
ObjectExpressionKeysTransformer = 'ObjectExpressionKeysTransformer',
ObjectExpressionTransformer = 'ObjectExpressionTransformer',
ObjectPatternPropertiesTransformer = 'ObjectPatternPropertiesTransformer',
ParentificationTransformer = 'ParentificationTransformer',
RenamePropertiesTransformer = 'RenamePropertiesTransformer',
ScopeIdentifiersTransformer = 'ScopeIdentifiersTransformer',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
import { inject, injectable, } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';

import * as ESTree from 'estree';

import { IOptions } from '../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
import { IVisitor } from '../../interfaces/node-transformers/IVisitor';

import { NodeTransformationStage } from '../../enums/node-transformers/NodeTransformationStage';

import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
import { NodeGuards } from '../../node/NodeGuards';
import { NodeUtils } from '../../node/NodeUtils';

@injectable()
export class ObjectPatternPropertiesTransformer extends AbstractNodeTransformer {
/**
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
*/
public constructor (
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
super(randomGenerator, options);
}

/**
* @param {NodeTransformationStage} nodeTransformationStage
* @returns {IVisitor | null}
*/
public getVisitor (nodeTransformationStage: NodeTransformationStage): IVisitor | null {
switch (nodeTransformationStage) {
case NodeTransformationStage.Converting:
return {
enter: (node: ESTree.Node, parentNode: ESTree.Node | null): ESTree.Node | undefined => {
if (parentNode && NodeGuards.isPropertyNode(node)) {
return this.transformNode(node, parentNode);
}
}
};

default:
return null;
}
}

/**
* replaces:
* const {foo} = bar;
*
* on:
* const {foo: foo} = bar;
*
* @param {Property} propertyNode
* @param {NodeGuards} parentNode
* @returns {NodeGuards}
*/
public transformNode (propertyNode: ESTree.Property, parentNode: ESTree.Node): ESTree.Node {
if (!NodeGuards.isObjectPatternNode(parentNode) || !propertyNode.shorthand) {
return propertyNode;
}

propertyNode.shorthand = false;
propertyNode.value = NodeUtils.clone(propertyNode.value);

NodeUtils.parentizeNode(propertyNode.value, parentNode);

return propertyNode;
}
}
10 changes: 4 additions & 6 deletions test/dev/dev.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,14 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../src/options/presets/NoCustomNo

let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
`
function foo () {
console.log(7);
return 9;
}
const {bar, baz} = {bar: 1, baz: 2};
console.log(bar, baz);
`,
{
...NO_ADDITIONAL_NODES_PRESET,
compact: false,
simplify: true
simplify: true,
renameGlobals: true
}
).getObfuscatedCode();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import { assert } from 'chai';
import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes';

import { readFileAsString } from '../../../../helpers/readFileAsString';
import { stubNodeTransformers } from '../../../../helpers/stubNodeTransformers';

import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade';
import { ObjectPatternPropertiesTransformer } from '../../../../../src/node-transformers/converting-transformers/ObjectPatternPropertiesTransformer';

describe('ObjectExpressionTransformer', () => {
describe('default behaviour', () => {
Expand Down Expand Up @@ -144,6 +146,8 @@ describe('ObjectExpressionTransformer', () => {
});

describe('object rest', () => {
stubNodeTransformers([ObjectPatternPropertiesTransformer]);

const objectRegExp: RegExp = /var _0x[a-f0-9]{4,6} *= *\{'foo': *0x1, *'bar': *0x2, *'baz': *0x3\};/;
const objectRestRegExp: RegExp = /var \{foo, *\.\.\.*_0x[a-f0-9]{4,6}\} *= *_0x[a-f0-9]{4,6};/;

Expand Down Expand Up @@ -201,6 +205,8 @@ describe('ObjectExpressionTransformer', () => {
});

describe('object spread: unicode escape sequence', () => {
stubNodeTransformers([ObjectPatternPropertiesTransformer]);

const object1RegExp: RegExp = /const _0x[a-f0-9]{4,6} *= *\{\};/;
const object2RegExp: RegExp = /_0x[a-f0-9]{4,6}\['\\x61'\] *= *0x1;/;
const object3RegExp: RegExp = /const \{a\} *= *_0x[a-f0-9]{4,6};/;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../../src/options/preset

import { getRegExpMatch } from '../../../../../helpers/getRegExpMatch';
import { readFileAsString } from '../../../../../helpers/readFileAsString';
import { stubNodeTransformers } from '../../../../../helpers/stubNodeTransformers';

import { JavaScriptObfuscator } from '../../../../../../src/JavaScriptObfuscatorFacade';
import { ObjectPatternPropertiesTransformer } from '../../../../../../src/node-transformers/converting-transformers/ObjectPatternPropertiesTransformer';

describe('ScopeIdentifiersTransformer CatchClause identifiers', () => {
let obfuscatedCode: string;
Expand Down Expand Up @@ -44,6 +46,8 @@ describe('ScopeIdentifiersTransformer CatchClause identifiers', () => {
});

describe('Variant #2: object pattern as parameter', () => {
stubNodeTransformers([ObjectPatternPropertiesTransformer]);

const functionParameterMatch: RegExp = /\} *catch *\(\{ *name *\}\) *\{/;
const functionBodyMatch: RegExp = /return *name;/;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ import { assert } from 'chai';
import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../../src/options/presets/NoCustomNodes';

import { readFileAsString } from '../../../../../helpers/readFileAsString';
import { getRegExpMatch } from '../../../../../helpers/getRegExpMatch';
import { stubNodeTransformers } from '../../../../../helpers/stubNodeTransformers';

import { JavaScriptObfuscator } from '../../../../../../src/JavaScriptObfuscatorFacade';
import { getRegExpMatch } from '../../../../../helpers/getRegExpMatch';
import { ObjectPatternPropertiesTransformer } from '../../../../../../src/node-transformers/converting-transformers/ObjectPatternPropertiesTransformer';

describe('ScopeIdentifiersTransformer Function identifiers', () => {
describe('identifiers transformation inside `FunctionDeclaration` and `FunctionExpression` node body', () => {
Expand Down Expand Up @@ -273,6 +275,8 @@ describe('ScopeIdentifiersTransformer Function identifiers', () => {
});

describe('object pattern as parameter', () => {
stubNodeTransformers([ObjectPatternPropertiesTransformer]);

describe('Variant #1: simple', () => {
const functionParameterRegExp: RegExp = /function *\(\{ *bar *\}\) *\{/;
const functionBodyRegExp: RegExp = /return *bar;/;
Expand Down Expand Up @@ -711,6 +715,8 @@ describe('ScopeIdentifiersTransformer Function identifiers', () => {
});

describe('object rest parameter', () => {
stubNodeTransformers([ObjectPatternPropertiesTransformer]);

const functionRegExp: RegExp = /function *func *\(\{foo, *..._0x[a-f0-9]{4,6}\}\) *\{/;
const returnRegExp: RegExp = /return *foo *\+ *_0x[a-f0-9]{4,6};/;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../../src/options/preset

import { getRegExpMatch } from '../../../../../helpers/getRegExpMatch';
import { readFileAsString } from '../../../../../helpers/readFileAsString';
import { stubNodeTransformers } from '../../../../../helpers/stubNodeTransformers';

import { IdentifierNamesGenerator } from '../../../../../../src/enums/generators/identifier-names-generators/IdentifierNamesGenerator';

import { JavaScriptObfuscator } from '../../../../../../src/JavaScriptObfuscatorFacade';
import { ObjectPatternPropertiesTransformer } from '../../../../../../src/node-transformers/converting-transformers/ObjectPatternPropertiesTransformer';

describe('ScopeIdentifiersTransformer VariableDeclaration identifiers', () => {
describe('Variant #1: default behaviour', () => {
Expand Down Expand Up @@ -315,6 +317,8 @@ describe('ScopeIdentifiersTransformer VariableDeclaration identifiers', () => {

describe('Variant #9: object pattern as variable declarator', () => {
describe('Variant #1: single level object pattern', () => {
stubNodeTransformers([ObjectPatternPropertiesTransformer]);

const objectPatternVariableDeclaratorRegExp: RegExp = /var \{ *bar *\} *= *\{ *'bar' *: *'foo' *\};/;
const variableUsageRegExp: RegExp = /console\['log'\]\(bar\);/;

Expand Down Expand Up @@ -611,6 +615,8 @@ describe('ScopeIdentifiersTransformer VariableDeclaration identifiers', () => {
});

describe('Variant #17: object rest', () => {
stubNodeTransformers([ObjectPatternPropertiesTransformer]);

const objectRegExp: RegExp = /var _0x[a-f0-9]{4,6} *= *\{'foo': *0x1, *'bar': *0x2, *'baz': *0x3\};/;
const objectRestRegExp: RegExp = /var \{foo, *\.\.\.*_0x[a-f0-9]{4,6}\} *= *_0x[a-f0-9]{4,6};/;

Expand All @@ -637,6 +643,8 @@ describe('ScopeIdentifiersTransformer VariableDeclaration identifiers', () => {
});

describe('Variant #18: destructing assignment without declaration #1', () => {
stubNodeTransformers([ObjectPatternPropertiesTransformer]);

const variablesDeclaration: RegExp = /var a, *b, *_0x[a-f0-9]{4,6};/;
const destructingAssignmentRegExp: RegExp = /\({ *a, *b *} *= *{ *'a' *: *0x1, *'b' *: *0x2 *}\);/;
const identifierAssignmentRegExp: RegExp = /_0x[a-f0-9]{4,6} *= *0x3;/;
Expand Down Expand Up @@ -709,6 +717,8 @@ describe('ScopeIdentifiersTransformer VariableDeclaration identifiers', () => {
});

describe('Variant #20: destructing assignment without declaration #3', () => {
stubNodeTransformers([ObjectPatternPropertiesTransformer]);

const variablesDeclaration: RegExp = /var a, *_0x[a-f0-9]{4,6};/;
const destructingAssignmentRegExp: RegExp = /\({ *a, *\.\.\._0x[a-f0-9]{4,6} *} *= *{ *'a' *: *0x1, *'b' *: *0x2 *}\);/;
const variablesUsageRegExp: RegExp = /console\['log']\(a, *_0x[a-f0-9]{4,6}\);/;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import { assert } from 'chai';
import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes';

import { readFileAsString } from '../../../../helpers/readFileAsString';
import { stubNodeTransformers } from '../../../../helpers/stubNodeTransformers';

import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade';
import { ObjectPatternPropertiesTransformer } from '../../../../../src/node-transformers/converting-transformers/ObjectPatternPropertiesTransformer';

describe('VariablePreserveTransformer', () => {
describe('Variant #1: string array storage name conflicts with identifier name', () => {
Expand Down Expand Up @@ -158,6 +160,8 @@ describe('VariablePreserveTransformer', () => {
});

describe('Variant #4: destructed object property identifier name conflict with identifier name', () => {
stubNodeTransformers([ObjectPatternPropertiesTransformer]);

describe('Variant #1: `renameGlobals` option is disabled', () => {
const variableDeclarationIdentifierName: RegExp = /var b *= *0x1;/;
const destructedObjectPropertyIdentifierName: RegExp = /const { *a *} *= *{ *'a' *: *0x2 *};/;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ import { assert } from 'chai';
import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes';

import { readFileAsString } from '../../../../helpers/readFileAsString';
import { stubNodeTransformers } from '../../../../helpers/stubNodeTransformers';

import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade';
import { ObjectPatternPropertiesTransformer } from '../../../../../src/node-transformers/converting-transformers/ObjectPatternPropertiesTransformer';

describe('VariableDeclarationsMergeTransformer', () => {
describe('base behaviour', () => {
Expand Down Expand Up @@ -176,6 +178,8 @@ describe('VariableDeclarationsMergeTransformer', () => {
});

describe('object pattern as initializer', () => {
stubNodeTransformers([ObjectPatternPropertiesTransformer]);

const regExp: RegExp = new RegExp(
'var foo *= *0x1, *' +
'{bar} *= *{\'bar\': *0x2}, *' +
Expand Down
24 changes: 24 additions & 0 deletions test/helpers/stubNodeTransformers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import * as mocha from 'mocha';
import * as sinon from 'sinon';

import { INodeTransformer } from '../../src/interfaces/node-transformers/INodeTransformer';

export function stubNodeTransformers (nodeTransformers: (new (...args: any[]) => INodeTransformer)[]): void {
const transformerStubs: sinon.SinonStub[] = [];

mocha.before(() => {
for (const nodeTransformer of nodeTransformers) {
const stub: sinon.SinonStub = sinon
.stub(nodeTransformer.prototype, 'getVisitor')
.callsFake(() => null);

transformerStubs.push(stub);
}
});

mocha.after(() => {
for (const stub of transformerStubs) {
stub.restore();
}
});
}
Loading

0 comments on commit c85f6c0

Please sign in to comment.