Bläddra i källkod

Merge pull request #951 from javascript-obfuscator/transform-object-keys-call-expression

To increase performance and prevent possible runtime errors `transfor…
Timofey Kachalov 3 år sedan
förälder
incheckning
985cb7e0ba
17 ändrade filer med 358 tillägg och 1 borttagningar
  1. 4 0
      CHANGELOG.md
  2. 0 0
      dist/index.browser.js
  3. 0 0
      dist/index.cli.js
  4. 0 0
      dist/index.js
  5. 1 1
      package.json
  6. 1 0
      src/enums/node/NodeType.ts
  7. 28 0
      src/node-transformers/converting-transformers/ObjectExpressionKeysTransformer.ts
  8. 24 0
      src/node/NodeGuards.ts
  9. 234 0
      test/functional-tests/node-transformers/converting-transformers/object-expression-keys-transformer/ObjectExpressionKeysTransformer.spec.ts
  10. 7 0
      test/functional-tests/node-transformers/converting-transformers/object-expression-keys-transformer/fixtures/call-expression-1.js
  11. 7 0
      test/functional-tests/node-transformers/converting-transformers/object-expression-keys-transformer/fixtures/call-expression-2.js
  12. 9 0
      test/functional-tests/node-transformers/converting-transformers/object-expression-keys-transformer/fixtures/call-expression-3.js
  13. 10 0
      test/functional-tests/node-transformers/converting-transformers/object-expression-keys-transformer/fixtures/call-expression-4.js
  14. 7 0
      test/functional-tests/node-transformers/converting-transformers/object-expression-keys-transformer/fixtures/new-expression-1.js
  15. 7 0
      test/functional-tests/node-transformers/converting-transformers/object-expression-keys-transformer/fixtures/new-expression-2.js
  16. 9 0
      test/functional-tests/node-transformers/converting-transformers/object-expression-keys-transformer/fixtures/new-expression-3.js
  17. 10 0
      test/functional-tests/node-transformers/converting-transformers/object-expression-keys-transformer/fixtures/new-expression-4.js

+ 4 - 0
CHANGELOG.md

@@ -1,5 +1,9 @@
 Change Log
 
+v2.15.6
+---
+* To increase performance and prevent possible runtime errors `transformObjectKeys` option now completely ignores objects with `CallExpression` or `NewExpression` nodes. Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/948
+
 v2.15.5
 ---
 * Improved `stringArray` calls wrapper decode code

Filskillnaden har hållts tillbaka eftersom den är för stor
+ 0 - 0
dist/index.browser.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 0 - 0
dist/index.cli.js


Filskillnaden har hållts tillbaka eftersom den är för stor
+ 0 - 0
dist/index.js


+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "javascript-obfuscator",
-  "version": "2.15.5",
+  "version": "2.15.6",
   "description": "JavaScript obfuscator",
   "keywords": [
     "obfuscator",

+ 1 - 0
src/enums/node/NodeType.ts

@@ -35,6 +35,7 @@ export enum NodeType {
     LogicalExpression = 'LogicalExpression',
     MemberExpression = 'MemberExpression',
     MethodDefinition = 'MethodDefinition',
+    NewExpression = 'NewExpression',
     ObjectExpression = 'ObjectExpression',
     ObjectPattern = 'ObjectPattern',
     Program = 'Program',

+ 28 - 0
src/node-transformers/converting-transformers/ObjectExpressionKeysTransformer.ts

@@ -72,6 +72,9 @@ export class ObjectExpressionKeysTransformer extends AbstractNodeTransformer {
                 objectExpressionNode,
                 objectExpressionParentNode
             )
+            || ObjectExpressionKeysTransformer.isObjectExpressionWithCallExpression(
+                objectExpressionNode,
+            )
             || ObjectExpressionKeysTransformer.isProhibitedSequenceExpression(
                 objectExpressionNode,
                 objectExpressionHostStatement
@@ -154,6 +157,31 @@ export class ObjectExpressionKeysTransformer extends AbstractNodeTransformer {
             && objectExpressionNodeParentNode.body === objectExpressionNode;
     }
 
+    /**
+     * @param {ObjectExpression} objectExpressionNode
+     * @returns {boolean}
+     */
+    private static isObjectExpressionWithCallExpression (objectExpressionNode: ESTree.ObjectExpression): boolean {
+        let isCallExpressionLikeNodeFound: boolean = false;
+
+        estraverse.traverse(objectExpressionNode, {
+            enter: (node: ESTree.Node): void | estraverse.VisitorOption => {
+                const isCallExpressionLikeNode = NodeGuards.isCallExpressionNode(node)
+                    || NodeGuards.isNewExpressionNode(node);
+
+                if (!isCallExpressionLikeNode) {
+                    return;
+                }
+
+                isCallExpressionLikeNodeFound = true;
+
+                return estraverse.VisitorOption.Break;
+            }
+        });
+
+        return isCallExpressionLikeNodeFound;
+    }
+
     /**
      * @param {ObjectExpression} objectExpressionNode
      * @param {Node} objectExpressionHostNode

+ 24 - 0
src/node/NodeGuards.ts

@@ -101,6 +101,14 @@ export class NodeGuards {
         return node.type === NodeType.ClassDeclaration && node.id !== null;
     }
 
+    /**
+     * @param {Node} node
+     * @returns {boolean}
+     */
+    public static isConditionalExpressionNode (node: ESTree.Node): node is ESTree.ConditionalExpression {
+        return node.type === NodeType.ConditionalExpression;
+    }
+
     /**
      * @param {Node} node
      * @returns {boolean}
@@ -285,6 +293,14 @@ export class NodeGuards {
         return node.type === NodeType.Literal;
     }
 
+    /**
+     * @param {Node} node
+     * @returns {boolean}
+     */
+    public static isLogicalExpressionNode (node: ESTree.Node): node is ESTree.LogicalExpression {
+        return node.type === NodeType.LogicalExpression;
+    }
+
     /**
      * @param {Node} node
      * @returns {boolean}
@@ -301,6 +317,14 @@ export class NodeGuards {
         return node.type === NodeType.MethodDefinition;
     }
 
+    /**
+     * @param {Node} node
+     * @returns {boolean}
+     */
+    public static isNewExpressionNode (node: ESTree.Node): node is ESTree.NewExpression {
+        return node.type === NodeType.NewExpression;
+    }
+
     /**
      * @param {Object} object
      * @returns {boolean}

+ 234 - 0
test/functional-tests/node-transformers/converting-transformers/object-expression-keys-transformer/ObjectExpressionKeysTransformer.spec.ts

@@ -2310,5 +2310,239 @@ describe('ObjectExpressionKeysTransformer', () => {
                 assert.match(obfuscatedCode,  regExp);
             });
         });
+
+        describe('Variant #18: call expression as property value', () => {
+            describe('Variant #1: call expression as a direct property value', () => {
+                const match: string = `` +
+                    `var ${variableMatch} *= *{` +
+                        `'foo': *'bar',` +
+                        `'baz': *${variableMatch}\\(\\)` +
+                    `}` +
+                ``;
+                const regExp: RegExp = new RegExp(match);
+
+                let obfuscatedCode: string;
+
+                before(() => {
+                    const code: string = readFileAsString(__dirname + '/fixtures/call-expression-1.js');
+
+                    obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                        code,
+                        {
+                            ...NO_ADDITIONAL_NODES_PRESET,
+                            transformObjectKeys: true
+                        }
+                    ).getObfuscatedCode();
+                });
+
+                it('shouldn ignore object expression if it contains a call expression as a direct property value', () => {
+                    assert.match(obfuscatedCode,  regExp);
+                });
+            });
+
+            describe('Variant #2: call expression as an indirect property value', () => {
+                const match: string = `` +
+                    `var ${variableMatch} *= *{` +
+                        `'foo': *'bar',` +
+                        `'baz': *'call' *\\+ *${variableMatch}\\(\\)` +
+                    `}` +
+                ``;
+                const regExp: RegExp = new RegExp(match);
+
+                let obfuscatedCode: string;
+
+                before(() => {
+                    const code: string = readFileAsString(__dirname + '/fixtures/call-expression-2.js');
+
+                    obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                        code,
+                        {
+                            ...NO_ADDITIONAL_NODES_PRESET,
+                            transformObjectKeys: true
+                        }
+                    ).getObfuscatedCode();
+                });
+
+                it('shouldn ignore object expression if it contains a call expression as an indirect property value', () => {
+                    assert.match(obfuscatedCode,  regExp);
+                });
+            });
+
+            describe('Variant #3: call expression as a nested object expression as property value', () => {
+                const match: string = `` +
+                    `var ${variableMatch} *= *{` +
+                        `'foo': *'bar',` +
+                        `'baz': *{` +
+                            `'bark': *${variableMatch}\\(\\)` +
+                        `}` +
+                    `}` +
+                ``;
+                const regExp: RegExp = new RegExp(match);
+
+                let obfuscatedCode: string;
+
+                before(() => {
+                    const code: string = readFileAsString(__dirname + '/fixtures/call-expression-3.js');
+
+                    obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                        code,
+                        {
+                            ...NO_ADDITIONAL_NODES_PRESET,
+                            transformObjectKeys: true
+                        }
+                    ).getObfuscatedCode();
+                });
+
+                it('shouldn ignore object expression if it contains a call expression as a nested object expression as property value', () => {
+                    assert.match(obfuscatedCode,  regExp);
+                });
+            });
+
+            describe('Variant #4: call expression as a a property value after object expression property', () => {
+                const match: string = `` +
+                    `var ${variableMatch} *= *{` +
+                        `'foo': *'bar',` +
+                        `'baz': *${variableMatch},` +
+                        `'eagle': *${variableMatch}\\(\\)` +
+                    `}` +
+                ``;
+                const regExp: RegExp = new RegExp(match);
+
+                let obfuscatedCode: string;
+
+                before(() => {
+                    const code: string = readFileAsString(__dirname + '/fixtures/call-expression-4.js');
+
+                    obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                        code,
+                        {
+                            ...NO_ADDITIONAL_NODES_PRESET,
+                            transformObjectKeys: true
+                        }
+                    ).getObfuscatedCode();
+                });
+
+                it('shouldn ignore object expression if it contains a call expression and the previous property value is object expression', () => {
+                    assert.match(obfuscatedCode,  regExp);
+                });
+            });
+        });
+
+        describe('Variant #19: new expression as property value', () => {
+            describe('Variant #1: new expression as a direct property value', () => {
+                const match: string = `` +
+                    `var ${variableMatch} *= *{` +
+                        `'foo': *'bar',` +
+                        `'baz': *new ${variableMatch}\\(\\)` +
+                    `}` +
+                ``;
+                const regExp: RegExp = new RegExp(match);
+
+                let obfuscatedCode: string;
+
+                before(() => {
+                    const code: string = readFileAsString(__dirname + '/fixtures/new-expression-1.js');
+
+                    obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                        code,
+                        {
+                            ...NO_ADDITIONAL_NODES_PRESET,
+                            transformObjectKeys: true
+                        }
+                    ).getObfuscatedCode();
+                });
+
+                it('shouldn ignore object expression if it contains a new expression as a direct property value', () => {
+                    assert.match(obfuscatedCode,  regExp);
+                });
+            });
+
+            describe('Variant #2: new expression as an indirect property value', () => {
+                const match: string = `` +
+                    `var ${variableMatch} *= *{` +
+                        `'foo': *'bar',` +
+                        `'baz': *'call' *\\+ *new ${variableMatch}\\(\\)` +
+                    `}` +
+                ``;
+                const regExp: RegExp = new RegExp(match);
+
+                let obfuscatedCode: string;
+
+                before(() => {
+                    const code: string = readFileAsString(__dirname + '/fixtures/new-expression-2.js');
+
+                    obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                        code,
+                        {
+                            ...NO_ADDITIONAL_NODES_PRESET,
+                            transformObjectKeys: true
+                        }
+                    ).getObfuscatedCode();
+                });
+
+                it('shouldn ignore object expression if it contains a new expression as an indirect property value', () => {
+                    assert.match(obfuscatedCode,  regExp);
+                });
+            });
+
+            describe('Variant #3: new expression as a nested object expression as property value', () => {
+                const match: string = `` +
+                    `var ${variableMatch} *= *{` +
+                        `'foo': *'bar',` +
+                        `'baz': *{` +
+                            `'bark': *new ${variableMatch}\\(\\)` +
+                        `}` +
+                    `}` +
+                ``;
+                const regExp: RegExp = new RegExp(match);
+
+                let obfuscatedCode: string;
+
+                before(() => {
+                    const code: string = readFileAsString(__dirname + '/fixtures/new-expression-3.js');
+
+                    obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                        code,
+                        {
+                            ...NO_ADDITIONAL_NODES_PRESET,
+                            transformObjectKeys: true
+                        }
+                    ).getObfuscatedCode();
+                });
+
+                it('shouldn ignore object expression if it contains a new expression as a nested object expression as property value', () => {
+                    assert.match(obfuscatedCode,  regExp);
+                });
+            });
+
+            describe('Variant #4: new expression as a a property value after object expression property', () => {
+                const match: string = `` +
+                    `var ${variableMatch} *= *{` +
+                        `'foo': *'bar',` +
+                        `'baz': *${variableMatch},` +
+                        `'eagle': *new ${variableMatch}\\(\\)` +
+                    `}` +
+                ``;
+                const regExp: RegExp = new RegExp(match);
+
+                let obfuscatedCode: string;
+
+                before(() => {
+                    const code: string = readFileAsString(__dirname + '/fixtures/new-expression-4.js');
+
+                    obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                        code,
+                        {
+                            ...NO_ADDITIONAL_NODES_PRESET,
+                            transformObjectKeys: true
+                        }
+                    ).getObfuscatedCode();
+                });
+
+                it('shouldn ignore object expression if it contains a new expression and the previous property value is object expression', () => {
+                    assert.match(obfuscatedCode,  regExp);
+                });
+            });
+        });
     });
 });

+ 7 - 0
test/functional-tests/node-transformers/converting-transformers/object-expression-keys-transformer/fixtures/call-expression-1.js

@@ -0,0 +1,7 @@
+(function(){
+    var func = () => {};
+    var object = {
+        foo: 'bar',
+        baz: func()
+    };
+})();

+ 7 - 0
test/functional-tests/node-transformers/converting-transformers/object-expression-keys-transformer/fixtures/call-expression-2.js

@@ -0,0 +1,7 @@
+(function(){
+    var func = () => {};
+    var object = {
+        foo: 'bar',
+        baz: `call${func()}`
+    };
+})();

+ 9 - 0
test/functional-tests/node-transformers/converting-transformers/object-expression-keys-transformer/fixtures/call-expression-3.js

@@ -0,0 +1,9 @@
+(function(){
+    var func = () => {};
+    var object = {
+        foo: 'bar',
+        baz: {
+            bark: func()
+        }
+    };
+})();

+ 10 - 0
test/functional-tests/node-transformers/converting-transformers/object-expression-keys-transformer/fixtures/call-expression-4.js

@@ -0,0 +1,10 @@
+(function(){
+    var func = () => {};
+    var object = {
+        foo: 'bar',
+        baz: {
+            bark: 'hawk'
+        },
+        eagle: func()
+    };
+})();

+ 7 - 0
test/functional-tests/node-transformers/converting-transformers/object-expression-keys-transformer/fixtures/new-expression-1.js

@@ -0,0 +1,7 @@
+(function(){
+    var func = () => {};
+    var object = {
+        foo: 'bar',
+        baz: new func()
+    };
+})();

+ 7 - 0
test/functional-tests/node-transformers/converting-transformers/object-expression-keys-transformer/fixtures/new-expression-2.js

@@ -0,0 +1,7 @@
+(function(){
+    var func = () => {};
+    var object = {
+        foo: 'bar',
+        baz: `call${new func()}`
+    };
+})();

+ 9 - 0
test/functional-tests/node-transformers/converting-transformers/object-expression-keys-transformer/fixtures/new-expression-3.js

@@ -0,0 +1,9 @@
+(function(){
+    var func = () => {};
+    var object = {
+        foo: 'bar',
+        baz: {
+            bark: new func()
+        }
+    };
+})();

+ 10 - 0
test/functional-tests/node-transformers/converting-transformers/object-expression-keys-transformer/fixtures/new-expression-4.js

@@ -0,0 +1,10 @@
+(function(){
+    var func = () => {};
+    var object = {
+        foo: 'bar',
+        baz: {
+            bark: 'hawk'
+        },
+        eagle: new func()
+    };
+})();

Vissa filer visades inte eftersom för många filer har ändrats