瀏覽代碼

To increase performance and prevent possible runtime errors `transformObjectKeys` option now completely ignores objects with `CallExpression` nodes

sanex 3 年之前
父節點
當前提交
d62bf3d377

+ 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` nodes. Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/948
+
 v2.15.5
 ---
 * Improved `stringArray` calls wrapper decode code

File diff suppressed because it is too large
+ 0 - 0
dist/index.browser.js


File diff suppressed because it is too large
+ 0 - 0
dist/index.cli.js


File diff suppressed because it is too large
+ 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",

+ 25 - 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,28 @@ export class ObjectExpressionKeysTransformer extends AbstractNodeTransformer {
             && objectExpressionNodeParentNode.body === objectExpressionNode;
     }
 
+    /**
+     * @param {ObjectExpression} objectExpressionNode
+     * @returns {boolean}
+     */
+    private static isObjectExpressionWithCallExpression (objectExpressionNode: ESTree.ObjectExpression): boolean {
+        let isObjectExpressionWithCallExpressionValue: boolean = false;
+
+        estraverse.traverse(objectExpressionNode, {
+            enter: (node: ESTree.Node): void | estraverse.VisitorOption => {
+                if (!NodeGuards.isCallExpressionNode(node)) {
+                    return;
+                }
+
+                isObjectExpressionWithCallExpressionValue = true;
+
+                return estraverse.VisitorOption.Break;
+            }
+        });
+
+        return isObjectExpressionWithCallExpressionValue;
+    }
+
     /**
      * @param {ObjectExpression} objectExpressionNode
      * @param {Node} objectExpressionHostNode

+ 16 - 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}

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

@@ -2310,5 +2310,122 @@ 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);
+                });
+            });
+        });
     });
 });

+ 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()
+    };
+})();

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