Browse Source

Merge branch 'dev'

sanex3339 8 years ago
parent
commit
6cc62cc076
26 changed files with 458 additions and 370 deletions
  1. 231 220
      dist/index.js
  2. 4 4
      package.json
  3. 11 7
      src/Obfuscator.ts
  4. 2 2
      src/custom-nodes/control-flow-storage-nodes/ControlFlowStorageNode.ts
  5. 2 1
      src/interfaces/node-transformers/INodeTransformer.d.ts
  6. 3 1
      src/interfaces/node-transformers/IObfuscatorReplacer.d.ts
  7. 3 1
      src/interfaces/node-transformers/IObfuscatorReplacerWithStorage.d.ts
  8. 10 2
      src/node-transformers/AbstractNodeTransformer.ts
  9. 4 1
      src/node-transformers/node-control-flow-transformers/FunctionControlFlowTransformer.ts
  10. 7 5
      src/node-transformers/node-obfuscators/CatchClauseObfuscator.ts
  11. 8 6
      src/node-transformers/node-obfuscators/FunctionDeclarationObfuscator.ts
  12. 7 5
      src/node-transformers/node-obfuscators/FunctionObfuscator.ts
  13. 7 5
      src/node-transformers/node-obfuscators/LabeledStatementObfuscator.ts
  14. 6 3
      src/node-transformers/node-obfuscators/LiteralObfuscator.ts
  15. 5 2
      src/node-transformers/node-obfuscators/MemberExpressionObfuscator.ts
  16. 4 1
      src/node-transformers/node-obfuscators/MethodDefinitionObfuscator.ts
  17. 37 37
      src/node-transformers/node-obfuscators/ObjectExpressionObfuscator.ts
  18. 8 6
      src/node-transformers/node-obfuscators/VariableDeclarationObfuscator.ts
  19. 1 1
      src/node-transformers/node-obfuscators/replacers/AbstractReplacer.ts
  20. 5 5
      src/node-transformers/node-obfuscators/replacers/IdentifierReplacer.ts
  21. 17 2
      src/node-transformers/node-obfuscators/replacers/NumberLiteralReplacer.ts
  22. 11 5
      src/node/NodeUtils.ts
  23. 19 4
      src/utils/Utils.ts
  24. 6 6
      test/unit-tests/node/NodeAppender.spec.ts
  25. 37 37
      test/unit-tests/node/NodeUtils.spec.ts
  26. 3 1
      tslint.json

File diff suppressed because it is too large
+ 231 - 220
dist/index.js


+ 4 - 4
package.json

@@ -1,6 +1,6 @@
 {
   "name": "javascript-obfuscator",
-  "version": "0.9.0-dev.4",
+  "version": "0.9.0-dev.5",
   "description": "JavaScript obfuscator",
   "keywords": [
     "obfuscator",
@@ -26,7 +26,7 @@
     "class-validator": "0.6.6",
     "commander": "2.9.0",
     "escodegen": "1.8.1",
-    "esprima": "3.1.2",
+    "esprima": "3.1.3",
     "estraverse": "4.2.0",
     "inversify": "^3.0.0-rc.2",
     "lodash": "^4.17.2",
@@ -47,7 +47,7 @@
     "@types/lodash": "^4.14.44",
     "@types/mkdirp": "0.3.29",
     "@types/mocha": "2.2.34",
-    "@types/node": "6.0.52",
+    "@types/node": "6.0.53",
     "@types/sinon": "1.16.33",
     "@types/string-template": "1.0.2",
     "awesome-typescript-loader": "3.0.0-beta.17",
@@ -61,7 +61,7 @@
     "mocha": "3.2.0",
     "sinon": "2.0.0-pre.4",
     "ts-node": "1.7.2",
-    "tslint": "4.1.1",
+    "tslint": "4.2.0",
     "tslint-loader": "^3.3.0",
     "typescript": "2.1.4",
     "webpack": "2.2.0-rc.2",

+ 11 - 7
src/Obfuscator.ts

@@ -109,7 +109,7 @@ export class Obfuscator implements IObfuscator {
             return astTree;
         }
 
-        NodeUtils.parentize(astTree);
+        astTree = <ESTree.Program>NodeUtils.parentize(astTree);
 
         const stackTraceData: IStackTraceData[] = this.stackTraceAnalyzer.analyze(astTree.body);
 
@@ -129,7 +129,7 @@ export class Obfuscator implements IObfuscator {
 
         // first pass: control flow flattening
         if (this.options.controlFlowFlattening) {
-            this.transformAstTree(
+            astTree = this.transformAstTree(
                 astTree,
                 VisitorDirection.leave,
                 this.nodeTransformersFactory(Obfuscator.nodeControlFlowTransformersMap)
@@ -137,7 +137,7 @@ export class Obfuscator implements IObfuscator {
         }
 
         // second pass: nodes obfuscation
-        this.transformAstTree(
+        astTree = this.transformAstTree(
             astTree,
             VisitorDirection.enter,
             this.nodeTransformersFactory(Obfuscator.nodeObfuscatorsMap)
@@ -157,15 +157,19 @@ export class Obfuscator implements IObfuscator {
         astTree: ESTree.Program,
         direction: TVisitorDirection,
         nodeTransformersConcreteFactory: (nodeType: string) => INodeTransformer[]
-    ): void {
-        estraverse.traverse(astTree, {
-            [direction]: (node: ESTree.Node, parentNode: ESTree.Node): void => {
+    ): ESTree.Program {
+        estraverse.replace(astTree, {
+            [direction]: (node: ESTree.Node, parentNode: ESTree.Node): ESTree.Node => {
                 const nodeTransformers: INodeTransformer[] = nodeTransformersConcreteFactory(node.type);
 
                 nodeTransformers.forEach((nodeTransformer: INodeTransformer) => {
-                    nodeTransformer.transformNode(node, parentNode);
+                    node = nodeTransformer.transformNode(node, parentNode);
                 });
+
+                return node;
             }
         });
+
+        return astTree;
     }
 }

+ 2 - 2
src/custom-nodes/control-flow-storage-nodes/ControlFlowStorageNode.ts

@@ -43,7 +43,7 @@ export class ControlFlowStorageNode extends AbstractCustomNode {
      * @returns {TStatement[]}
      */
     protected getNodeStructure (): TStatement[] {
-        const structure: ESTree.Node = Nodes.getVariableDeclarationNode([
+        let structure: ESTree.Node = Nodes.getVariableDeclarationNode([
             Nodes.getVariableDeclaratorNode(
                 Nodes.getIdentifierNode(this.controlFlowStorage.getStorageId()),
                 Nodes.getObjectExpressionNode(
@@ -59,7 +59,7 @@ export class ControlFlowStorageNode extends AbstractCustomNode {
             )
         ]);
 
-        NodeUtils.parentize(structure);
+        structure = NodeUtils.parentize(structure);
 
         return [structure];
     }

+ 2 - 1
src/interfaces/node-transformers/INodeTransformer.d.ts

@@ -4,6 +4,7 @@ export interface INodeTransformer {
     /**
      * @param node
      * @param parentNode
+     * @returns {ESTree.Node}
      */
-    transformNode (node: ESTree.Node, parentNode?: ESTree.Node): void;
+    transformNode (node: ESTree.Node, parentNode: ESTree.Node): ESTree.Node;
 }

+ 3 - 1
src/interfaces/node-transformers/IObfuscatorReplacer.d.ts

@@ -1,7 +1,9 @@
+import * as ESTree from 'estree';
+
 export interface IObfuscatorReplacer {
     /**
      * @param nodeValue
      * @param nodeIdentifier
      */
-    replace (nodeValue: any, nodeIdentifier?: string): string;
+    replace (nodeValue: any, nodeIdentifier?: number): string;
 }

+ 3 - 1
src/interfaces/node-transformers/IObfuscatorReplacerWithStorage.d.ts

@@ -1,3 +1,5 @@
+import * as ESTree from 'estree';
+
 import { IObfuscatorReplacer } from './IObfuscatorReplacer';
 
 export interface IObfuscatorReplacerWithStorage extends IObfuscatorReplacer {
@@ -5,5 +7,5 @@ export interface IObfuscatorReplacerWithStorage extends IObfuscatorReplacer {
      * @param nodeValue
      * @param nodeIdentifier
      */
-    storeNames (nodeValue: any, nodeIdentifier: string): void;
+    storeNames (nodeValue: any, nodeIdentifier: number): void;
 }

+ 10 - 2
src/node-transformers/AbstractNodeTransformer.ts

@@ -1,13 +1,20 @@
 import { injectable, inject } from 'inversify';
+import { ServiceIdentifiers } from '../container/ServiceIdentifiers';
 
 import * as ESTree from 'estree';
 
 import { INodeTransformer } from '../interfaces/node-transformers/INodeTransformer';
 import { IOptions } from '../interfaces/options/IOptions';
-import { ServiceIdentifiers } from '../container/ServiceIdentifiers';
+
+import { RandomGeneratorUtils } from '../utils/RandomGeneratorUtils';
 
 @injectable()
 export abstract class AbstractNodeTransformer implements INodeTransformer {
+    /**
+     * @type {number}
+     */
+    protected nodeIdentifier: number = RandomGeneratorUtils.getRandomInteger(0, 10000);
+
     /**
      * @type {IOptions}
      */
@@ -25,6 +32,7 @@ export abstract class AbstractNodeTransformer implements INodeTransformer {
     /**
      * @param node
      * @param parentNode
+     * @returns {ESTree.Node}
      */
-    public abstract transformNode (node: ESTree.Node, parentNode?: ESTree.Node): void;
+    public abstract transformNode (node: ESTree.Node, parentNode: ESTree.Node): ESTree.Node;
 }

+ 4 - 1
src/node-transformers/node-control-flow-transformers/FunctionControlFlowTransformer.ts

@@ -113,9 +113,12 @@ export class FunctionControlFlowTransformer extends AbstractNodeTransformer {
 
     /**
      * @param functionNode
+     * @returns {ESTree.Node}
      */
-    public transformNode (functionNode: ESTree.Function): void {
+    public transformNode (functionNode: ESTree.Function): ESTree.Node {
         this.changeFunctionBodyControlFlow(functionNode);
+
+        return functionNode;
     }
 
     /**

+ 7 - 5
src/node-transformers/node-obfuscators/CatchClauseObfuscator.ts

@@ -14,7 +14,6 @@ import { NodeType } from '../../enums/NodeType';
 import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
 import { Node } from '../../node/Node';
 import { NodeUtils } from '../../node/NodeUtils';
-import { RandomGeneratorUtils } from '../../utils/RandomGeneratorUtils';
 
 /**
  * replaces:
@@ -46,19 +45,22 @@ export class CatchClauseObfuscator extends AbstractNodeTransformer {
 
     /**
      * @param catchClauseNode
+     * @returns {ESTree.Node}
      */
-    public transformNode (catchClauseNode: ESTree.CatchClause): void {
-        const nodeIdentifier: string = RandomGeneratorUtils.getRandomString(7);
+    public transformNode (catchClauseNode: ESTree.CatchClause): ESTree.Node {
+        const nodeIdentifier: number = this.nodeIdentifier++;
 
         this.storeCatchClauseParam(catchClauseNode, nodeIdentifier);
         this.replaceCatchClauseParam(catchClauseNode, nodeIdentifier);
+
+        return catchClauseNode;
     }
 
     /**
      * @param catchClauseNode
      * @param nodeIdentifier
      */
-    private storeCatchClauseParam (catchClauseNode: ESTree.CatchClause, nodeIdentifier: string): void {
+    private storeCatchClauseParam (catchClauseNode: ESTree.CatchClause, nodeIdentifier: number): void {
         NodeUtils.typedTraverse(catchClauseNode.param, NodeType.Identifier, {
             enter: (node: ESTree.Identifier) => this.identifierReplacer.storeNames(node.name, nodeIdentifier)
         });
@@ -68,7 +70,7 @@ export class CatchClauseObfuscator extends AbstractNodeTransformer {
      * @param catchClauseNode
      * @param nodeIdentifier
      */
-    private replaceCatchClauseParam (catchClauseNode: ESTree.CatchClause, nodeIdentifier: string): void {
+    private replaceCatchClauseParam (catchClauseNode: ESTree.CatchClause, nodeIdentifier: number): void {
         estraverse.replace(catchClauseNode, {
             enter: (node: ESTree.Node, parentNode: ESTree.Node): any => {
                 if (Node.isReplaceableIdentifierNode(node, parentNode)) {

+ 8 - 6
src/node-transformers/node-obfuscators/FunctionDeclarationObfuscator.ts

@@ -16,7 +16,6 @@ import { NodeType } from '../../enums/NodeType';
 import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
 import { Node } from '../../node/Node';
 import { NodeUtils } from '../../node/NodeUtils';
-import { RandomGeneratorUtils } from '../../utils/RandomGeneratorUtils';
 
 /**
  * replaces:
@@ -55,25 +54,28 @@ export class FunctionDeclarationObfuscator extends AbstractNodeTransformer {
     /**
      * @param functionDeclarationNode
      * @param parentNode
+     * @returns {ESTree.Node}
      */
-    public transformNode (functionDeclarationNode: ESTree.FunctionDeclaration, parentNode: ESTree.Node): void {
-        const nodeIdentifier: string = RandomGeneratorUtils.getRandomString(7);
+    public transformNode (functionDeclarationNode: ESTree.FunctionDeclaration, parentNode: ESTree.Node): ESTree.Node {
+        const nodeIdentifier: number = this.nodeIdentifier++;
         const blockScopeOfFunctionDeclarationNode: TNodeWithBlockStatement = NodeUtils
             .getBlockScopesOfNode(functionDeclarationNode)[0];
 
         if (blockScopeOfFunctionDeclarationNode.type === NodeType.Program) {
-            return;
+            return functionDeclarationNode;
         }
 
         this.storeFunctionName(functionDeclarationNode, nodeIdentifier);
         this.replaceFunctionName(blockScopeOfFunctionDeclarationNode, nodeIdentifier);
+
+        return functionDeclarationNode;
     }
 
     /**
      * @param functionDeclarationNode
      * @param nodeIdentifier
      */
-    private storeFunctionName (functionDeclarationNode: ESTree.FunctionDeclaration, nodeIdentifier: string): void {
+    private storeFunctionName (functionDeclarationNode: ESTree.FunctionDeclaration, nodeIdentifier: number): void {
         NodeUtils.typedTraverse(functionDeclarationNode.id, NodeType.Identifier, {
             enter: (node: ESTree.Identifier) => this.identifierReplacer.storeNames(node.name, nodeIdentifier)
         });
@@ -83,7 +85,7 @@ export class FunctionDeclarationObfuscator extends AbstractNodeTransformer {
      * @param scopeNode
      * @param nodeIdentifier
      */
-    private replaceFunctionName (scopeNode: ESTree.Node, nodeIdentifier: string): void {
+    private replaceFunctionName (scopeNode: ESTree.Node, nodeIdentifier: number): void {
         let replaceableIdentifiersForCurrentScope: ESTree.Identifier[];
 
         // check for cached identifiers for current scope node. If exist - loop through them.

+ 7 - 5
src/node-transformers/node-obfuscators/FunctionObfuscator.ts

@@ -14,7 +14,6 @@ import { NodeType } from '../../enums/NodeType';
 import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
 import { Node } from '../../node/Node';
 import { NodeUtils } from '../../node/NodeUtils';
-import { RandomGeneratorUtils } from '../../utils/RandomGeneratorUtils';
 
 /**
  * replaces:
@@ -46,19 +45,22 @@ export class FunctionObfuscator extends AbstractNodeTransformer {
 
     /**
      * @param functionNode
+     * @returns {ESTree.Node}
      */
-    public transformNode (functionNode: ESTree.Function): void {
-        const nodeIdentifier: string = RandomGeneratorUtils.getRandomString(7);
+    public transformNode (functionNode: ESTree.Function): ESTree.Node {
+        const nodeIdentifier: number = this.nodeIdentifier++;
 
         this.storeFunctionParams(functionNode, nodeIdentifier);
         this.replaceFunctionParams(functionNode, nodeIdentifier);
+
+        return functionNode;
     }
 
     /**
      * @param functionNode
      * @param nodeIdentifier
      */
-    private storeFunctionParams (functionNode: ESTree.Function, nodeIdentifier: string): void {
+    private storeFunctionParams (functionNode: ESTree.Function, nodeIdentifier: number): void {
         functionNode.params
             .forEach((paramsNode: ESTree.Node) => {
                 NodeUtils.typedTraverse(paramsNode, NodeType.Identifier, {
@@ -71,7 +73,7 @@ export class FunctionObfuscator extends AbstractNodeTransformer {
      * @param functionNode
      * @param nodeIdentifier
      */
-    private replaceFunctionParams (functionNode: ESTree.Function, nodeIdentifier: string): void {
+    private replaceFunctionParams (functionNode: ESTree.Function, nodeIdentifier: number): void {
         const traverseVisitor: estraverse.Visitor = {
             enter: (node: ESTree.Node, parentNode: ESTree.Node): any => {
                 if (Node.isReplaceableIdentifierNode(node, parentNode)) {

+ 7 - 5
src/node-transformers/node-obfuscators/LabeledStatementObfuscator.ts

@@ -14,7 +14,6 @@ import { NodeType } from '../../enums/NodeType';
 import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
 import { Node } from '../../node/Node';
 import { NodeUtils } from '../../node/NodeUtils';
-import { RandomGeneratorUtils } from '../../utils/RandomGeneratorUtils';
 
 /**
  * replaces:
@@ -54,19 +53,22 @@ export class LabeledStatementObfuscator extends AbstractNodeTransformer {
 
     /**
      * @param labeledStatementNode
+     * @returns {ESTree.Node}
      */
-    public transformNode (labeledStatementNode: ESTree.LabeledStatement): void {
-        const nodeIdentifier: string = RandomGeneratorUtils.getRandomString(7);
+    public transformNode (labeledStatementNode: ESTree.LabeledStatement): ESTree.Node {
+        const nodeIdentifier: number = this.nodeIdentifier++;
 
         this.storeLabeledStatementName(labeledStatementNode, nodeIdentifier);
         this.replaceLabeledStatementName(labeledStatementNode, nodeIdentifier);
+
+        return labeledStatementNode;
     }
 
     /**
      * @param labeledStatementNode
      * @param nodeIdentifier
      */
-    private storeLabeledStatementName (labeledStatementNode: ESTree.LabeledStatement, nodeIdentifier: string): void {
+    private storeLabeledStatementName (labeledStatementNode: ESTree.LabeledStatement, nodeIdentifier: number): void {
         NodeUtils.typedTraverse(labeledStatementNode.label, NodeType.Identifier, {
             enter: (node: ESTree.Identifier) => this.identifierReplacer.storeNames(node.name, nodeIdentifier)
         });
@@ -76,7 +78,7 @@ export class LabeledStatementObfuscator extends AbstractNodeTransformer {
      * @param labeledStatementNode
      * @param nodeIdentifier
      */
-    private replaceLabeledStatementName (labeledStatementNode: ESTree.LabeledStatement, nodeIdentifier: string): void {
+    private replaceLabeledStatementName (labeledStatementNode: ESTree.LabeledStatement, nodeIdentifier: number): void {
         estraverse.replace(labeledStatementNode, {
             enter: (node: ESTree.Node, parentNode: ESTree.Node): any => {
                 if (Node.isLabelIdentifierNode(node, parentNode)) {

+ 6 - 3
src/node-transformers/node-obfuscators/LiteralObfuscator.ts

@@ -35,10 +35,11 @@ export class LiteralObfuscator extends AbstractNodeTransformer {
     /**
      * @param literalNode
      * @param parentNode
+     * @returns {ESTree.Node}
      */
-    public transformNode (literalNode: ESTree.Literal, parentNode: ESTree.Node): void {
+    public transformNode (literalNode: ESTree.Literal, parentNode: ESTree.Node): ESTree.Node {
         if (Node.isPropertyNode(parentNode) && parentNode.key === literalNode) {
-            return;
+            return literalNode;
         }
 
         let content: string;
@@ -63,12 +64,14 @@ export class LiteralObfuscator extends AbstractNodeTransformer {
                 break;
 
             default:
-                return;
+                return literalNode;
         }
 
         literalNode['x-verbatim-property'] = {
             content : content,
             precedence: escodegen.Precedence.Primary
         };
+
+        return literalNode;
     }
 }

+ 5 - 2
src/node-transformers/node-obfuscators/MemberExpressionObfuscator.ts

@@ -35,20 +35,23 @@ export class MemberExpressionObfuscator extends AbstractNodeTransformer {
 
     /**
      * @param memberExpressionNode
+     * @returns {ESTree.Node}
      */
-    public transformNode (memberExpressionNode: ESTree.MemberExpression): void {
+    public transformNode (memberExpressionNode: ESTree.MemberExpression): ESTree.Node {
         if (Node.isLiteralNode(memberExpressionNode.property)) {
             memberExpressionNode.property = this.obfuscateLiteralProperty(memberExpressionNode.property);
         }
 
         if (Node.isIdentifierNode(memberExpressionNode.property)) {
             if (memberExpressionNode.computed) {
-                return;
+                return memberExpressionNode;
             }
 
             memberExpressionNode.computed = true;
             memberExpressionNode.property = this.obfuscateIdentifierProperty(memberExpressionNode.property);
         }
+
+        return memberExpressionNode;
     }
 
     /**

+ 4 - 1
src/node-transformers/node-obfuscators/MethodDefinitionObfuscator.ts

@@ -47,9 +47,12 @@ export class MethodDefinitionObfuscator extends AbstractNodeTransformer {
     /**
      * @param methodDefinitionNode
      * @param parentNode
+     * @returns {ESTree.Node}
      */
-    public transformNode (methodDefinitionNode: ESTree.MethodDefinition, parentNode: ESTree.Node): void {
+    public transformNode (methodDefinitionNode: ESTree.MethodDefinition, parentNode: ESTree.Node): ESTree.Node {
         this.replaceMethodName(methodDefinitionNode);
+
+        return methodDefinitionNode;
     }
 
     /**

+ 37 - 37
src/node-transformers/node-obfuscators/ObjectExpressionObfuscator.ts

@@ -34,61 +34,61 @@ export class ObjectExpressionObfuscator extends AbstractNodeTransformer {
         super(options);
     }
 
-    /**
-     * @param objectExpressionNode
-     */
-    public transformNode (objectExpressionNode: ESTree.ObjectExpression): void {
-        objectExpressionNode.properties
-            .forEach((property: ESTree.Property) => {
-                if (property.shorthand) {
-                    property.shorthand = false;
-                }
-
-                estraverse.traverse(property.key, {
-                    enter: (node: ESTree.Node, parentNode: ESTree.Node): any => {
-                        if (Node.isLiteralNode(node)) {
-                            this.obfuscateLiteralPropertyKey(node);
-
-                            return;
-                        }
-
-                        if (Node.isIdentifierNode(node)) {
-                            this.obfuscateIdentifierPropertyKey(node);
-                        }
-                    }
-                });
-            });
-    }
-
     /**
      * @param node
+     * @returns {ESTree.Literal}
      */
-    private obfuscateLiteralPropertyKey (node: ESTree.Literal): void {
+    private static obfuscateLiteralPropertyKey (node: ESTree.Literal): ESTree.Literal {
         if (typeof node.value === 'string' && !node['x-verbatim-property']) {
             node['x-verbatim-property'] = {
                 content : `'${Utils.stringToUnicodeEscapeSequence(node.value)}'`,
                 precedence: escodegen.Precedence.Primary
             };
         }
+
+        return node;
     }
 
     /**
      * @param node
+     * @returns {ESTree.Literal}
      */
-    private obfuscateIdentifierPropertyKey (node: ESTree.Identifier): void {
-        const nodeValue: string = node.name;
-        const literalNode: ESTree.Literal = {
-            raw: `'${nodeValue}'`,
+    private static obfuscateIdentifierPropertyKey (node: ESTree.Identifier): ESTree.Literal {
+        return {
+            type: NodeType.Literal,
+            value: node.name,
+            raw: `'${node.name}'`,
             'x-verbatim-property': {
-                content : `'${Utils.stringToUnicodeEscapeSequence(nodeValue)}'`,
+                content : `'${Utils.stringToUnicodeEscapeSequence(node.name)}'`,
                 precedence: escodegen.Precedence.Primary
-            },
-            type: NodeType.Literal,
-            value: nodeValue
+            }
         };
+    }
 
-        delete node.name;
+    /**
+     * @param objectExpressionNode
+     * @returns {ESTree.Node}
+     */
+    public transformNode (objectExpressionNode: ESTree.ObjectExpression): ESTree.Node {
+        objectExpressionNode.properties
+            .forEach((property: ESTree.Property) => {
+                if (property.shorthand) {
+                    property.shorthand = false;
+                }
+
+                estraverse.replace(property.key, {
+                    enter: (node: ESTree.Node, parentNode: ESTree.Node): any => {
+                        if (Node.isLiteralNode(node)) {
+                            property.key = ObjectExpressionObfuscator.obfuscateLiteralPropertyKey(node);
+                        }
+
+                        if (Node.isIdentifierNode(node)) {
+                            property.key = ObjectExpressionObfuscator.obfuscateIdentifierPropertyKey(node);
+                        }
+                    }
+                });
+            });
 
-        Object.assign(node, literalNode);
+        return objectExpressionNode;
     }
 }

+ 8 - 6
src/node-transformers/node-obfuscators/VariableDeclarationObfuscator.ts

@@ -16,7 +16,6 @@ import { NodeType } from '../../enums/NodeType';
 import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
 import { Node } from '../../node/Node';
 import { NodeUtils } from '../../node/NodeUtils';
-import { RandomGeneratorUtils } from '../../utils/RandomGeneratorUtils';
 
 /**
  * replaces:
@@ -56,29 +55,32 @@ export class VariableDeclarationObfuscator extends AbstractNodeTransformer {
     /**
      * @param variableDeclarationNode
      * @param parentNode
+     * @returns {ESTree.Node}
      */
-    public transformNode (variableDeclarationNode: ESTree.VariableDeclaration, parentNode: ESTree.Node): void {
+    public transformNode (variableDeclarationNode: ESTree.VariableDeclaration, parentNode: ESTree.Node): ESTree.Node {
         const blockScopeOfVariableDeclarationNode: TNodeWithBlockStatement = NodeUtils
             .getBlockScopesOfNode(variableDeclarationNode)[0];
 
         if (blockScopeOfVariableDeclarationNode.type === NodeType.Program) {
-            return;
+            return variableDeclarationNode;
         }
 
-        const nodeIdentifier: string = RandomGeneratorUtils.getRandomString(7);
+        const nodeIdentifier: number = this.nodeIdentifier++;
         const scopeNode: ESTree.Node = variableDeclarationNode.kind === 'var'
             ? blockScopeOfVariableDeclarationNode
             : parentNode;
 
         this.storeVariableNames(variableDeclarationNode, nodeIdentifier);
         this.replaceVariableNames(scopeNode, nodeIdentifier);
+
+        return variableDeclarationNode;
     }
 
     /**
      * @param variableDeclarationNode
      * @param nodeIdentifier
      */
-    private storeVariableNames (variableDeclarationNode: ESTree.VariableDeclaration, nodeIdentifier: string): void {
+    private storeVariableNames (variableDeclarationNode: ESTree.VariableDeclaration, nodeIdentifier: number): void {
         variableDeclarationNode.declarations
             .forEach((declarationNode: ESTree.VariableDeclarator) => {
                 NodeUtils.typedTraverse(declarationNode.id, NodeType.Identifier, {
@@ -91,7 +93,7 @@ export class VariableDeclarationObfuscator extends AbstractNodeTransformer {
      * @param scopeNode
      * @param nodeIdentifier
      */
-    private replaceVariableNames (scopeNode: ESTree.Node, nodeIdentifier: string): void {
+    private replaceVariableNames (scopeNode: ESTree.Node, nodeIdentifier: number): void {
         let replaceableIdentifiersForCurrentScope: ESTree.Identifier[];
 
         // check for cached identifiers for current scope node. If exist - loop through them.

+ 1 - 1
src/node-transformers/node-obfuscators/replacers/AbstractReplacer.ts

@@ -25,5 +25,5 @@ export abstract class AbstractReplacer implements IObfuscatorReplacer {
      * @param nodeIdentifier
      * @returns {string}
      */
-    public abstract replace (nodeValue: any, nodeIdentifier?: string): string;
+    public abstract replace (nodeValue: any, nodeIdentifier?: number): string;
 }

+ 5 - 5
src/node-transformers/node-obfuscators/replacers/IdentifierReplacer.ts

@@ -28,8 +28,8 @@ export class IdentifierReplacer extends AbstractReplacer implements IObfuscatorR
      * @param nodeIdentifier
      * @returns {string}
      */
-    public replace (nodeValue: string, nodeIdentifier: string): string {
-        const mapKey: string = `${nodeValue}-${nodeIdentifier}`;
+    public replace (nodeValue: string, nodeIdentifier: number): string {
+        const mapKey: string = `${nodeValue}-${String(nodeIdentifier)}`;
 
         if (!this.namesMap.has(mapKey)) {
             return nodeValue;
@@ -39,15 +39,15 @@ export class IdentifierReplacer extends AbstractReplacer implements IObfuscatorR
     }
 
     /**
-     * Store all identifiers names as keys in given `namesMap` with random names as value.
+     * Store all `nodeIdentifier`'s as keys in given `namesMap` with random names as value.
      * Reserved names will be ignored.
      *
      * @param nodeName
      * @param nodeIdentifier
      */
-    public storeNames (nodeName: string, nodeIdentifier: string): void {
+    public storeNames (nodeName: string, nodeIdentifier: number): void {
         if (!this.isReservedName(nodeName)) {
-            this.namesMap.set(`${nodeName}-${nodeIdentifier}`, RandomGeneratorUtils.getRandomVariableName());
+            this.namesMap.set(`${nodeName}-${String(nodeIdentifier)}`, RandomGeneratorUtils.getRandomVariableName());
         }
     }
 

+ 17 - 2
src/node-transformers/node-obfuscators/replacers/NumberLiteralReplacer.ts

@@ -8,6 +8,11 @@ import { Utils } from '../../../utils/Utils';
 
 @injectable()
 export class NumberLiteralReplacer extends AbstractReplacer {
+    /**
+     * @type {Map<string, string>}
+     */
+    private readonly numberLiteralCache: Map <number, string> = new Map();
+
     /**
      * @param options
      */
@@ -22,10 +27,20 @@ export class NumberLiteralReplacer extends AbstractReplacer {
      * @returns {string}
      */
     public replace (nodeValue: number): string {
+        if (this.numberLiteralCache.has(nodeValue)) {
+            return <string>this.numberLiteralCache.get(nodeValue);
+        }
+
+        let result: string;
+
         if (!Utils.isCeilNumber(nodeValue)) {
-            return String(nodeValue);
+            result = String(nodeValue);
+        } else {
+            result = `${Utils.hexadecimalPrefix}${Utils.decToHex(nodeValue)}`;
         }
 
-        return `${Utils.hexadecimalPrefix}${Utils.decToHex(nodeValue)}`;
+        this.numberLiteralCache.set(nodeValue, result);
+
+        return result;
     }
 }

+ 11 - 5
src/node/NodeUtils.ts

@@ -24,8 +24,9 @@ export class NodeUtils {
 
     /**
      * @param node
+     * @return {T}
      */
-    public static addXVerbatimPropertyToLiterals (node: ESTree.Node): void {
+    public static addXVerbatimPropertyToLiterals <T extends ESTree.Node> (node: T): T {
         NodeUtils.typedReplace(node, NodeType.Literal, {
             leave: (node: ESTree.Literal) => {
                 node['x-verbatim-property'] = {
@@ -34,6 +35,8 @@ export class NodeUtils {
                 };
             }
         });
+
+        return node;
     }
 
     /**
@@ -41,10 +44,10 @@ export class NodeUtils {
      * @returns {TStatement[]}
      */
     public static convertCodeToStructure (code: string): TStatement[] {
-        const structure: ESTree.Program = esprima.parse(code);
+        let structure: ESTree.Program = esprima.parse(code);
 
-        NodeUtils.addXVerbatimPropertyToLiterals(structure);
-        NodeUtils.parentize(structure);
+        structure = NodeUtils.addXVerbatimPropertyToLiterals(structure);
+        structure = NodeUtils.parentize(structure);
 
         return <TStatement[]>structure.body;
     }
@@ -142,8 +145,9 @@ export class NodeUtils {
 
     /**
      * @param node
+     * @return {T}
      */
-    public static parentize (node: ESTree.Node): void {
+    public static parentize <T extends ESTree.Node> (node: T): T {
         let isRootNode: boolean = true;
 
         estraverse.replace(node, {
@@ -167,6 +171,8 @@ export class NodeUtils {
                 node.obfuscated = false;
             }
         });
+
+        return node;
     }
 
     /**

+ 19 - 4
src/utils/Utils.ts

@@ -7,6 +7,11 @@ export class Utils {
      */
     public static readonly hexadecimalPrefix: string = '0x';
 
+    /**
+     * @type {Map<string, string>}
+     */
+    private static readonly stringToUnicodeEscapeSequenceCache: Map <string, string> = new Map();
+
     /**
      * @param array
      * @param times
@@ -128,6 +133,12 @@ export class Utils {
      * @returns {string}
      */
     public static stringToUnicodeEscapeSequence (string: string, nonLatinAndNonDigitsOnly: boolean = false): string {
+        const cacheKey: string = `${string}-${String(nonLatinAndNonDigitsOnly)}`;
+
+        if (Utils.stringToUnicodeEscapeSequenceCache.has(cacheKey)) {
+            return <string>Utils.stringToUnicodeEscapeSequenceCache.get(cacheKey);
+        }
+
         const radix: number = 16;
         const replaceRegExp: RegExp = new RegExp('[\\s\\S]', 'g');
         const escapeRegExp: RegExp = new RegExp('[^a-zA-Z0-9]');
@@ -136,11 +147,11 @@ export class Utils {
         let prefix: string,
             template: string;
 
-        return `${string.replace(replaceRegExp, (escape: string): string => {
+        const result: string = string.replace(replaceRegExp, (escape: string): string => {
             if (nonLatinAndNonDigitsOnly && !escapeRegExp.test(escape)) {
                 return escape;
             }
-            
+
             if (regexp.test(escape)) {
                 prefix = '\\x';
                 template = '0'.repeat(2);
@@ -148,8 +159,12 @@ export class Utils {
                 prefix = '\\u';
                 template = '0'.repeat(4);
             }
-            
+
             return `${prefix}${(template + escape.charCodeAt(0).toString(radix)).slice(-template.length)}`;
-        })}`;
+        });
+
+        Utils.stringToUnicodeEscapeSequenceCache.set(cacheKey, result);
+
+        return result;
     }
 }

+ 6 - 6
test/unit-tests/node/NodeAppender.spec.ts

@@ -40,8 +40,8 @@ describe('NodeAppender', () => {
                 )
             );
 
-            NodeUtils.parentize(astTree);
-            NodeUtils.parentize(expectedAstTree);
+            astTree = NodeUtils.parentize(astTree);
+            expectedAstTree = NodeUtils.parentize(expectedAstTree);
 
             NodeAppender.appendNode(astTree, node);
         });
@@ -205,8 +205,8 @@ describe('NodeAppender', () => {
                 )
             );
 
-            NodeUtils.parentize(astTree);
-            NodeUtils.parentize(expectedAstTree);
+            astTree = NodeUtils.parentize(astTree);
+            expectedAstTree = NodeUtils.parentize(expectedAstTree);
 
             NodeAppender.insertNodeAtIndex(astTree, node, 2);
         });
@@ -238,8 +238,8 @@ describe('NodeAppender', () => {
                 )
             );
 
-            NodeUtils.parentize(astTree);
-            NodeUtils.parentize(expectedAstTree);
+            astTree = NodeUtils.parentize(astTree);
+            expectedAstTree = NodeUtils.parentize(expectedAstTree);
 
             NodeAppender.prependNode(astTree, node);
         });

+ 37 - 37
test/unit-tests/node/NodeUtils.spec.ts

@@ -51,11 +51,11 @@ describe('NodeUtils', () => {
                 variableDeclarationNode
             ]);
 
-            programNode['parentNode'] = programNode;
-            variableDeclarationNode['parentNode'] = programNode;
-            variableDeclaratorNode['parentNode'] = variableDeclarationNode;
-            identifierNode['parentNode'] = variableDeclaratorNode;
-            literalNode['parentNode'] = variableDeclaratorNode;
+            programNode.parentNode = programNode;
+            variableDeclarationNode.parentNode = programNode;
+            variableDeclaratorNode.parentNode = variableDeclarationNode;
+            identifierNode.parentNode = variableDeclaratorNode;
+            literalNode.parentNode = variableDeclaratorNode;
         });
 
         it('should convert code to `ESTree.Node[]` structure array', () => {
@@ -162,15 +162,15 @@ describe('NodeUtils', () => {
                 functionDeclarationNode
             ]);
 
-            programNode['parentNode'] = programNode;
-            functionDeclarationNode['parentNode'] = programNode;
-            functionDeclarationBlockStatementNode['parentNode'] = functionDeclarationNode;
-            expressionStatementNode1['parentNode'] = functionDeclarationBlockStatementNode;
-            ifStatementNode1['parentNode'] = functionDeclarationBlockStatementNode;
-            ifStatementBlockStatementNode1['parentNode'] = ifStatementNode1;
-            ifStatementNode2['parentNode'] = ifStatementBlockStatementNode1;
-            ifStatementBlockStatementNode2['parentNode'] = ifStatementNode2;
-            expressionStatementNode3['parentNode'] = ifStatementBlockStatementNode2;
+            programNode.parentNode = programNode;
+            functionDeclarationNode.parentNode = programNode;
+            functionDeclarationBlockStatementNode.parentNode = functionDeclarationNode;
+            expressionStatementNode1.parentNode = functionDeclarationBlockStatementNode;
+            ifStatementNode1.parentNode = functionDeclarationBlockStatementNode;
+            ifStatementBlockStatementNode1.parentNode = ifStatementNode1;
+            ifStatementNode2.parentNode = ifStatementBlockStatementNode1;
+            ifStatementBlockStatementNode2.parentNode = ifStatementNode2;
+            expressionStatementNode3.parentNode = ifStatementBlockStatementNode2;
         });
 
         it('should return block-scope node for given node', () => {
@@ -249,17 +249,17 @@ describe('NodeUtils', () => {
                 functionDeclarationNode1
             ]);
 
-            programNode['parentNode'] = programNode;
-            functionDeclarationNode1['parentNode'] = programNode;
-            functionDeclarationBlockStatementNode1['parentNode'] = functionDeclarationNode1;
-            expressionStatementNode1['parentNode'] = functionDeclarationBlockStatementNode1;
-            ifStatementNode1['parentNode'] = functionDeclarationBlockStatementNode1;
-            ifStatementBlockStatementNode1['parentNode'] = ifStatementNode1;
-            functionDeclarationNode2['parentNode'] = ifStatementBlockStatementNode1;
-            functionDeclarationBlockStatementNode2['parentNode'] = functionDeclarationNode2;
-            expressionStatementNode2['parentNode'] = functionDeclarationBlockStatementNode2;
-            ifStatementNode2['parentNode'] = functionDeclarationBlockStatementNode2;
-            ifStatementBlockStatementNode2['parentNode'] = ifStatementNode2;
+            programNode.parentNode = programNode;
+            functionDeclarationNode1.parentNode = programNode;
+            functionDeclarationBlockStatementNode1.parentNode = functionDeclarationNode1;
+            expressionStatementNode1.parentNode = functionDeclarationBlockStatementNode1;
+            ifStatementNode1.parentNode = functionDeclarationBlockStatementNode1;
+            ifStatementBlockStatementNode1.parentNode = ifStatementNode1;
+            functionDeclarationNode2.parentNode = ifStatementBlockStatementNode1;
+            functionDeclarationBlockStatementNode2.parentNode = functionDeclarationNode2;
+            expressionStatementNode2.parentNode = functionDeclarationBlockStatementNode2;
+            ifStatementNode2.parentNode = functionDeclarationBlockStatementNode2;
+            ifStatementBlockStatementNode2.parentNode = ifStatementNode2;
         });
 
         it('should return block-scope depth for given node', () => {
@@ -308,27 +308,27 @@ describe('NodeUtils', () => {
                 ifStatementNode
             ]);
 
-            NodeUtils.parentize(programNode);
+            programNode = NodeUtils.parentize(programNode);
 
-            assert.deepEqual(programNode['parentNode'], programNode);
-            assert.deepEqual(ifStatementNode['parentNode'], programNode);
-            assert.deepEqual(ifStatementBlockStatementNode['parentNode'], ifStatementNode);
-            assert.deepEqual(expressionStatementNode1['parentNode'], ifStatementBlockStatementNode);
-            assert.deepEqual(expressionStatementNode2['parentNode'], ifStatementBlockStatementNode);
+            assert.deepEqual(programNode.parentNode, programNode);
+            assert.deepEqual(ifStatementNode.parentNode, programNode);
+            assert.deepEqual(ifStatementBlockStatementNode.parentNode, ifStatementNode);
+            assert.deepEqual(expressionStatementNode1.parentNode, ifStatementBlockStatementNode);
+            assert.deepEqual(expressionStatementNode2.parentNode, ifStatementBlockStatementNode);
         });
 
         it('should parentize given AST-tree', () => {
             programNode = Nodes.getProgramNode([
                 ifStatementNode
             ]);
-            programNode['parentNode'] = programNode;
+            programNode.parentNode = programNode;
 
-            NodeUtils.parentize(ifStatementNode);
+            ifStatementNode = NodeUtils.parentize(ifStatementNode);
 
-            assert.deepEqual(ifStatementNode['parentNode'], programNode);
-            assert.deepEqual(ifStatementBlockStatementNode['parentNode'], ifStatementNode);
-            assert.deepEqual(expressionStatementNode1['parentNode'], ifStatementBlockStatementNode);
-            assert.deepEqual(expressionStatementNode2['parentNode'], ifStatementBlockStatementNode);
+            assert.deepEqual(ifStatementNode.parentNode, programNode);
+            assert.deepEqual(ifStatementBlockStatementNode.parentNode, ifStatementNode);
+            assert.deepEqual(expressionStatementNode1.parentNode, ifStatementBlockStatementNode);
+            assert.deepEqual(expressionStatementNode2.parentNode, ifStatementBlockStatementNode);
         });
     });
 });

+ 3 - 1
tslint.json

@@ -57,6 +57,7 @@
     "no-default-export": true,
     "no-duplicate-variable": true,
     "no-empty": false,
+    "no-empty-interface": true,
     "no-eval": false,
     "no-inferrable-types": false,
     "no-internal-module": true,
@@ -67,8 +68,9 @@
     "no-require-imports": false,
     "no-shadowed-variable": false,
     "no-string-literal": true,
+    "no-string-throw": true,
     "no-switch-case-fall-through": false,
-    "no-trailing-whitespace": true,
+    "no-trailing-whitespace": false,
     "no-unused-expression": true,
     "no-use-before-declare": true,
     "no-var-keyword": true,

Some files were not shown because too many files changed in this diff