Преглед на файлове

some optimisations and new tests

sanex3339 преди 8 години
родител
ревизия
6bf5ba7bda

+ 22 - 12
dist/index.js

@@ -1454,6 +1454,7 @@ var Obfuscator = function () {
         _classCallCheck(this, Obfuscator);
 
         this.customNodes = new Map();
+        this.obfuscatorsCache = new Map();
         this.options = options;
     }
 
@@ -1494,13 +1495,15 @@ var Obfuscator = function () {
         value: function initializeCustomNodes(stackTraceData) {
             var _this = this;
 
+            var customNodes = [];
             Obfuscator.nodeGroups.forEach(function (nodeGroupConstructor) {
                 var nodeGroupNodes = new nodeGroupConstructor(stackTraceData, _this.options).getNodes();
                 if (!nodeGroupNodes) {
                     return;
                 }
-                _this.customNodes = new Map([].concat(_toConsumableArray(_this.customNodes), _toConsumableArray(nodeGroupNodes)));
+                customNodes.push.apply(customNodes, _toConsumableArray(nodeGroupNodes));
             });
+            this.customNodes = new Map(customNodes);
         }
     }, {
         key: 'initializeNodeObfuscators',
@@ -1512,7 +1515,12 @@ var Obfuscator = function () {
                 return;
             }
             nodeObfuscators.forEach(function (obfuscator) {
-                new obfuscator(_this2.customNodes, _this2.options).obfuscateNode(node, parentNode);
+                var cachedObfuscator = _this2.obfuscatorsCache.get(obfuscator);
+                if (!cachedObfuscator) {
+                    cachedObfuscator = new obfuscator(_this2.customNodes, _this2.options);
+                    _this2.obfuscatorsCache.set(obfuscator, cachedObfuscator);
+                }
+                cachedObfuscator.obfuscateNode(node, parentNode);
             });
         }
     }, {
@@ -1520,7 +1528,7 @@ var Obfuscator = function () {
         value: function obfuscate(node) {
             var _this3 = this;
 
-            estraverse.replace(node, {
+            estraverse.traverse(node, {
                 enter: function enter(node, parentNode) {
                     _this3.initializeNodeObfuscators(node, parentNode);
                 }
@@ -1531,6 +1539,7 @@ var Obfuscator = function () {
     return Obfuscator;
 }();
 
+Obfuscator.counter = 0;
 Obfuscator.nodeGroups = [DomainLockNodesGroup_1.DomainLockNodesGroup, SelfDefendingNodesGroup_1.SelfDefendingNodesGroup, ConsoleOutputNodesGroup_1.ConsoleOutputNodesGroup, DebugProtectionNodesGroup_1.DebugProtectionNodesGroup, UnicodeArrayNodesGroup_1.UnicodeArrayNodesGroup];
 Obfuscator.nodeObfuscators = new Map([[NodeType_1.NodeType.ArrowFunctionExpression, [FunctionObfuscator_1.FunctionObfuscator]], [NodeType_1.NodeType.ClassDeclaration, [FunctionDeclarationObfuscator_1.FunctionDeclarationObfuscator]], [NodeType_1.NodeType.CatchClause, [CatchClauseObfuscator_1.CatchClauseObfuscator]], [NodeType_1.NodeType.FunctionDeclaration, [FunctionDeclarationObfuscator_1.FunctionDeclarationObfuscator, FunctionObfuscator_1.FunctionObfuscator]], [NodeType_1.NodeType.FunctionExpression, [FunctionObfuscator_1.FunctionObfuscator]], [NodeType_1.NodeType.MemberExpression, [MemberExpressionObfuscator_1.MemberExpressionObfuscator]], [NodeType_1.NodeType.MethodDefinition, [MethodDefinitionObfuscator_1.MethodDefinitionObfuscator]], [NodeType_1.NodeType.ObjectExpression, [ObjectExpressionObfuscator_1.ObjectExpressionObfuscator]], [NodeType_1.NodeType.VariableDeclaration, [VariableDeclarationObfuscator_1.VariableDeclarationObfuscator]], [NodeType_1.NodeType.Literal, [LiteralObfuscator_1.LiteralObfuscator]]]);
 exports.Obfuscator = Obfuscator;
@@ -3971,7 +3980,6 @@ var ObjectExpressionCalleeDataExtractor = function () {
     function ObjectExpressionCalleeDataExtractor(blockScopeBody, callee) {
         _classCallCheck(this, ObjectExpressionCalleeDataExtractor);
 
-        this.objectMembersCallsChain = [];
         this.blockScopeBody = blockScopeBody;
         this.callee = callee;
     }
@@ -3982,12 +3990,12 @@ var ObjectExpressionCalleeDataExtractor = function () {
             var calleeBlockStatement = null,
                 functionExpressionName = null;
             if (Nodes_1.Nodes.isMemberExpressionNode(this.callee)) {
-                this.objectMembersCallsChain = this.createObjectMembersCallsChain(this.objectMembersCallsChain, this.callee);
-                if (!this.objectMembersCallsChain.length) {
+                var objectMembersCallsChain = this.createObjectMembersCallsChain([], this.callee);
+                if (!objectMembersCallsChain.length) {
                     return null;
                 }
-                functionExpressionName = this.objectMembersCallsChain[this.objectMembersCallsChain.length - 1];
-                calleeBlockStatement = this.getCalleeBlockStatement(NodeUtils_1.NodeUtils.getBlockScopeOfNode(this.blockScopeBody[0]), this.objectMembersCallsChain);
+                functionExpressionName = objectMembersCallsChain[objectMembersCallsChain.length - 1];
+                calleeBlockStatement = this.getCalleeBlockStatement(NodeUtils_1.NodeUtils.getBlockScopeOfNode(this.blockScopeBody[0]), objectMembersCallsChain);
             }
             if (!calleeBlockStatement) {
                 return null;
@@ -4000,17 +4008,16 @@ var ObjectExpressionCalleeDataExtractor = function () {
     }, {
         key: 'createObjectMembersCallsChain',
         value: function createObjectMembersCallsChain(currentChain, memberExpression) {
-            if (Nodes_1.Nodes.isIdentifierNode(memberExpression.property)) {
+            if (Nodes_1.Nodes.isIdentifierNode(memberExpression.property) && memberExpression.computed === false) {
                 currentChain.unshift(memberExpression.property.name);
-            } else if (Nodes_1.Nodes.isLiteralNode(memberExpression.property) && typeof memberExpression.property.value === 'string') {
+            } else if (Nodes_1.Nodes.isLiteralNode(memberExpression.property) && (typeof memberExpression.property.value === 'string' || typeof memberExpression.property.value === 'number')) {
                 currentChain.unshift(memberExpression.property.value);
             } else {
                 return currentChain;
             }
             if (Nodes_1.Nodes.isMemberExpressionNode(memberExpression.object)) {
                 return this.createObjectMembersCallsChain(currentChain, memberExpression.object);
-            }
-            if (Nodes_1.Nodes.isIdentifierNode(memberExpression.object)) {
+            } else if (Nodes_1.Nodes.isIdentifierNode(memberExpression.object)) {
                 currentChain.unshift(memberExpression.object.name);
             }
             return currentChain;
@@ -4021,6 +4028,9 @@ var ObjectExpressionCalleeDataExtractor = function () {
             var _this = this;
 
             var objectName = objectMembersCallsChain.shift();
+            if (!objectName) {
+                return null;
+            }
             var calleeBlockStatement = null;
             estraverse.traverse(node, {
                 enter: function enter(node, parentNode) {

+ 26 - 10
src/Obfuscator.ts

@@ -1,14 +1,15 @@
 import * as estraverse from 'estraverse';
 import * as ESTree from 'estree';
 
+import { TNodeGroup } from './types/TNodeGroup';
+import { TNodeObfuscator } from './types/TNodeObfuscator';
+
 import { ICustomNode } from './interfaces/custom-nodes/ICustomNode';
+import { INodeObfuscator } from './interfaces/INodeObfuscator';
 import { IObfuscator } from './interfaces/IObfuscator';
 import { IOptions } from './interfaces/IOptions';
 import { IStackTraceData } from './interfaces/stack-trace-analyzer/IStackTraceData';
 
-import { TNodeGroup } from './types/TNodeGroup';
-import { TNodeObfuscator } from './types/TNodeObfuscator';
-
 import { AppendState } from './enums/AppendState';
 import { NodeType } from './enums/NodeType';
 
@@ -30,6 +31,8 @@ import { VariableDeclarationObfuscator } from './node-obfuscators/VariableDeclar
 import { StackTraceAnalyzer } from './stack-trace-analyzer/StackTraceAnalyzer';
 
 export class Obfuscator implements IObfuscator {
+    static counter: number = 0;
+
     /**
      * @type {TNodeGroup[]}
      */
@@ -65,6 +68,11 @@ export class Obfuscator implements IObfuscator {
      */
     private customNodes: Map <string, ICustomNode> = new Map <string, ICustomNode> ();
 
+    /**
+     * @type {Map<TNodeObfuscator, INodeObfuscator>}
+     */
+    private obfuscatorsCache: Map <TNodeObfuscator, INodeObfuscator> = new Map <TNodeObfuscator, INodeObfuscator> ();
+
     /**
      * @type {IOptions}
      */
@@ -125,6 +133,8 @@ export class Obfuscator implements IObfuscator {
      * @param stackTraceData
      */
     private initializeCustomNodes (stackTraceData: IStackTraceData[]): void {
+        let customNodes: [string, ICustomNode][] = [];
+
         Obfuscator.nodeGroups.forEach((nodeGroupConstructor: TNodeGroup) => {
             const nodeGroupNodes: Map <string, ICustomNode> | undefined = new nodeGroupConstructor(
                 stackTraceData, this.options
@@ -134,11 +144,10 @@ export class Obfuscator implements IObfuscator {
                 return;
             }
 
-            this.customNodes = new Map <string, ICustomNode> ([
-                ...this.customNodes,
-                ...nodeGroupNodes
-            ]);
+            customNodes.push(...nodeGroupNodes);
         });
+
+        this.customNodes = new Map <string, ICustomNode> (customNodes);
     }
 
 
@@ -154,7 +163,14 @@ export class Obfuscator implements IObfuscator {
         }
 
         nodeObfuscators.forEach((obfuscator: TNodeObfuscator) => {
-            new obfuscator(this.customNodes, this.options).obfuscateNode(node, parentNode);
+            let cachedObfuscator: INodeObfuscator|undefined = this.obfuscatorsCache.get(obfuscator);
+
+            if (!cachedObfuscator) {
+                cachedObfuscator = new obfuscator(this.customNodes, this.options);
+                this.obfuscatorsCache.set(obfuscator,  cachedObfuscator);
+            }
+
+            cachedObfuscator.obfuscateNode(node, parentNode);
         });
     }
 
@@ -162,8 +178,8 @@ export class Obfuscator implements IObfuscator {
      * @param node
      */
     private obfuscate (node: ESTree.Node): void {
-        estraverse.replace(node, {
-            enter: (node: ESTree.Node, parentNode: ESTree.Node): any => {
+        estraverse.traverse(node, {
+            enter: (node: ESTree.Node, parentNode: ESTree.Node): void => {
                 this.initializeNodeObfuscators(node, parentNode);
             }
         });

+ 1 - 1
src/interfaces/stack-trace-analyzer/ICalleeData.d.ts

@@ -2,5 +2,5 @@ import * as ESTree from 'estree';
 
 export interface ICalleeData {
     callee: ESTree.BlockStatement;
-    name: string | null;
+    name: string | number | null;
 }

+ 2 - 2
src/node-obfuscators/VariableDeclarationObfuscator.ts

@@ -68,8 +68,8 @@ export class VariableDeclarationObfuscator extends AbstractNodeObfuscator {
      */
     private replaceVariableNames (variableDeclarationNode: ESTree.VariableDeclaration, variableParentNode: ESTree.Node): void {
         let scopeNode: ESTree.Node = variableDeclarationNode.kind === 'var' ? NodeUtils.getBlockScopeOfNode(
-                variableDeclarationNode
-            ) : variableParentNode;
+            variableDeclarationNode
+        ) : variableParentNode;
 
         estraverse.replace(scopeNode, {
             enter: (node: ESTree.Node, parentNode: ESTree.Node): any => {

+ 37 - 22
src/stack-trace-analyzer/callee-data-extractors/ObjectExpressionCalleeDataExtractor.ts

@@ -1,6 +1,8 @@
 import * as estraverse from 'estraverse';
 import * as ESTree from 'estree';
 
+import { TObjectMembersCallsChain } from '../../types/TObjectMembersCallsChain';
+
 import { ICalleeData } from '../../interfaces/stack-trace-analyzer/ICalleeData';
 import { ICalleeDataExtractor } from '../../interfaces/stack-trace-analyzer/ICalleeDataExtractor';
 
@@ -18,11 +20,6 @@ export class ObjectExpressionCalleeDataExtractor implements ICalleeDataExtractor
      */
     private callee: ESTree.MemberExpression;
 
-    /**
-     * @type {Array}
-     */
-    private objectMembersCallsChain: string[] = [];
-
     /**
      * @param blockScopeBody
      * @param callee
@@ -37,20 +34,22 @@ export class ObjectExpressionCalleeDataExtractor implements ICalleeDataExtractor
      */
     public extract (): ICalleeData|null {
         let calleeBlockStatement: ESTree.BlockStatement|null = null,
-            functionExpressionName: string|null = null;
+            functionExpressionName: string|number|null = null;
 
         if (Nodes.isMemberExpressionNode(this.callee)) {
-            this.objectMembersCallsChain = this.createObjectMembersCallsChain(this.objectMembersCallsChain, this.callee);
+            const objectMembersCallsChain: TObjectMembersCallsChain = this.createObjectMembersCallsChain(
+                [],
+                this.callee
+            );
 
-            if (!this.objectMembersCallsChain.length) {
+            if (!objectMembersCallsChain.length) {
                 return null;
             }
 
-            functionExpressionName = this.objectMembersCallsChain[this.objectMembersCallsChain.length - 1];
-
+            functionExpressionName = objectMembersCallsChain[objectMembersCallsChain.length - 1];
             calleeBlockStatement = this.getCalleeBlockStatement(
                 NodeUtils.getBlockScopeOfNode(this.blockScopeBody[0]),
-                this.objectMembersCallsChain
+                objectMembersCallsChain
             );
         }
 
@@ -71,22 +70,31 @@ export class ObjectExpressionCalleeDataExtractor implements ICalleeDataExtractor
      *
      * @param currentChain
      * @param memberExpression
-     * @returns {string[]}
+     * @returns {TObjectMembersCallsChain}
      */
-    private createObjectMembersCallsChain (currentChain: string[], memberExpression: ESTree.MemberExpression): string[] {
-        if (Nodes.isIdentifierNode(memberExpression.property)) {
+    private createObjectMembersCallsChain (
+        currentChain: TObjectMembersCallsChain,
+        memberExpression: ESTree.MemberExpression
+    ): TObjectMembersCallsChain {
+        // first step: processing memberExpression `property` property
+        if (Nodes.isIdentifierNode(memberExpression.property) && memberExpression.computed === false) {
             currentChain.unshift(memberExpression.property.name);
-        } else if (Nodes.isLiteralNode(memberExpression.property) && typeof memberExpression.property.value === 'string') {
+        } else if (
+            Nodes.isLiteralNode(memberExpression.property) &&
+            (
+                typeof memberExpression.property.value === 'string' ||
+                typeof memberExpression.property.value === 'number'
+            )
+        ) {
             currentChain.unshift(memberExpression.property.value);
         } else {
             return currentChain;
         }
 
+        // second step: processing memberExpression `object` property
         if (Nodes.isMemberExpressionNode(memberExpression.object)) {
             return this.createObjectMembersCallsChain(currentChain, memberExpression.object);
-        }
-
-        if (Nodes.isIdentifierNode(memberExpression.object)) {
+        } else if (Nodes.isIdentifierNode(memberExpression.object)) {
             currentChain.unshift(memberExpression.object.name);
         }
 
@@ -98,8 +106,15 @@ export class ObjectExpressionCalleeDataExtractor implements ICalleeDataExtractor
      * @param objectMembersCallsChain
      * @returns {ESTree.BlockStatement|null}
      */
-    private getCalleeBlockStatement (node: ESTree.Node, objectMembersCallsChain: string[]): ESTree.BlockStatement|null {
-        const objectName: string = <string>objectMembersCallsChain.shift();
+    private getCalleeBlockStatement (
+        node: ESTree.Node,
+        objectMembersCallsChain: TObjectMembersCallsChain
+    ): ESTree.BlockStatement|null {
+        const objectName: string|number|undefined = objectMembersCallsChain.shift();
+
+        if (!objectName) {
+            return null;
+        }
 
         let calleeBlockStatement: ESTree.BlockStatement|null = null;
 
@@ -129,9 +144,9 @@ export class ObjectExpressionCalleeDataExtractor implements ICalleeDataExtractor
      */
     private findCalleeBlockStatement (
         objectExpressionProperties: ESTree.Property[],
-        objectMembersCallsChain: string[]
+        objectMembersCallsChain: TObjectMembersCallsChain
     ): ESTree.BlockStatement|null {
-        const nextItemInCallsChain: string|undefined = objectMembersCallsChain.shift();
+        const nextItemInCallsChain: string|number|undefined = objectMembersCallsChain.shift();
 
         if (!nextItemInCallsChain) {
             return null;

+ 1 - 0
src/types/TObjectMembersCallsChain.d.ts

@@ -0,0 +1 @@
+export type TObjectMembersCallsChain = (string|number)[];

+ 0 - 0
test/fixtures/stack-trace-analyzer/call-expression-of-object-member.js → test/fixtures/stack-trace-analyzer/call-expression-of-object-member-1.js


+ 28 - 0
test/fixtures/stack-trace-analyzer/call-expression-of-object-member-2.js

@@ -0,0 +1,28 @@
+var object = {
+    foo: {
+        bar: function () {
+
+        },
+    },
+    1: {
+        baz: function () {
+
+        },
+    }
+};
+
+
+var object1 = {
+    foo: {
+        1: function () {
+
+        }
+    }
+};
+
+var foo = 'foo';
+
+object[foo].bar();
+object[1].baz();
+
+object1['foo'][1]();

+ 28 - 3
test/functional-tests/stack-trace-analyzer/StackTraceAnalyzer.spec.ts

@@ -99,7 +99,7 @@ function getFunctionExpressionById (astTree: ESTree.Node, id: string): ESTree.Fu
  * @param name
  * @returns {ESTree.FunctionExpression|null}
  */
-function getObjectFunctionExpressionByName (astTree: ESTree.Node, objectName: string, name: string): ESTree.FunctionExpression|null {
+function getObjectFunctionExpressionByName (astTree: ESTree.Node, objectName: string, name: string|number): ESTree.FunctionExpression|null {
     let functionExpressionNode: ESTree.FunctionExpression|null = null,
         targetObjectExpressionNode: ESTree.ObjectExpression|null = null;
 
@@ -288,10 +288,10 @@ describe('StackTraceAnalyzer', () => {
             assert.deepEqual(stackTraceData, expectedStackTraceData);
         });
 
-        it('should returns correct BlockScopeTraceData - variant #5: call expression of object member', () => {
+        it('should returns correct BlockScopeTraceData - variant #5: call expression of object member #1', () => {
             astTree = NodeMocks.getProgramNode(
                 NodeUtils.convertCodeToStructure(
-                    readFileAsString('./test/fixtures/stack-trace-analyzer/call-expression-of-object-member.js')
+                    readFileAsString('./test/fixtures/stack-trace-analyzer/call-expression-of-object-member-1.js')
                 )
             );
 
@@ -344,6 +344,31 @@ describe('StackTraceAnalyzer', () => {
             assert.deepEqual(stackTraceData, expectedStackTraceData);
         });
 
+        it('should returns correct BlockScopeTraceData - variant #5: call expression of object member #2', () => {
+            astTree = NodeMocks.getProgramNode(
+                NodeUtils.convertCodeToStructure(
+                    readFileAsString('./test/fixtures/stack-trace-analyzer/call-expression-of-object-member-2.js')
+                )
+            );
+
+            expectedStackTraceData = [
+                {
+                    name: 'baz',
+                    callee: (<ESTree.FunctionExpression>getObjectFunctionExpressionByName(astTree, 'object', 'baz')).body,
+                    stackTrace: []
+                },
+                {
+                    name: 1,
+                    callee: (<ESTree.FunctionExpression>getObjectFunctionExpressionByName(astTree, 'object1', 1)).body,
+                    stackTrace: []
+                },
+            ];
+
+            stackTraceData = new StackTraceAnalyzer(astTree.body).analyze();
+
+            assert.deepEqual(stackTraceData, expectedStackTraceData);
+        });
+
         it('should returns correct BlockScopeTraceData - variant #6: no call expressions', () => {
             astTree = NodeMocks.getProgramNode(
                 NodeUtils.convertCodeToStructure(