浏览代码

Added logic and tests to partial simplify consequent only if statements with prohibited nodes

sanex3339 4 年之前
父节点
当前提交
edba004651

文件差异内容过多而无法显示
+ 0 - 0
dist/index.browser.js


文件差异内容过多而无法显示
+ 0 - 0
dist/index.cli.js


文件差异内容过多而无法显示
+ 0 - 0
dist/index.js


+ 0 - 6
src/interfaces/node-transformers/minification-transformers/IIfStatementExpressionData.ts

@@ -1,6 +0,0 @@
-import * as ESTree from 'estree';
-
-export interface IIfStatementExpressionData {
-    expression: ESTree.Expression;
-    hasReturnStatement: boolean;
-}

+ 28 - 0
src/interfaces/node-transformers/minification-transformers/IIfStatementSimplifyData.ts

@@ -0,0 +1,28 @@
+import * as ESTree from 'estree';
+
+export interface IIfStatementSimplifyData {
+    /**
+     * @type {ESTree.Statement[]}
+     */
+    leadingStatements: ESTree.Statement[];
+
+    /**
+     * @type {ESTree.Statement}
+     */
+    statement: ESTree.Statement;
+
+    /**
+     * @type {ESTree.Expression}
+     */
+    expression: ESTree.Expression;
+
+    /**
+     * @type {boolean}
+     */
+    hasReturnStatement: boolean;
+
+    /**
+     * @type {boolean}
+     */
+    hasSingleExpression: boolean;
+}

+ 125 - 72
src/node-transformers/minification-transformers/IfStatementSimplifyTransformer.ts

@@ -3,7 +3,7 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 
 import * as ESTree from 'estree';
 
-import { IIfStatementExpressionData } from '../../interfaces/node-transformers/minification-transformers/IIfStatementExpressionData';
+import { IIfStatementSimplifyData } from '../../interfaces/node-transformers/minification-transformers/IIfStatementSimplifyData';
 import { IOptions } from '../../interfaces/options/IOptions';
 import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
 import { IVisitor } from '../../interfaces/node-transformers/IVisitor';
@@ -62,75 +62,58 @@ export class IfStatementSimplifyTransformer extends AbstractNodeTransformer {
         ifStatementNode: ESTree.IfStatement,
         parentNode: ESTree.Node
     ): ESTree.Node {
-        const consequentExpressionData: IIfStatementExpressionData | null = this.getIfStatementExpressionData(ifStatementNode.consequent);
+        const consequentSimplifyData: IIfStatementSimplifyData | null = this.getIfStatementSimplifyData(ifStatementNode.consequent);
 
         // Variant #1: no valid consequent expression
-        if (!consequentExpressionData) {
+        if (!consequentSimplifyData) {
             return ifStatementNode;
         }
 
         // Variant #2: valid consequent expression only
         if (!ifStatementNode.alternate) {
-            /**
-             * Converts:
-             * if (true) {
-             *     return 1;
-             * }
-             *
-             * to:
-             * if (true)
-             *     return 1;
-             */
-            if (consequentExpressionData.hasReturnStatement) {
-                return NodeFactory.ifStatementNode(
-                    ifStatementNode.test,
-                    NodeFactory.returnStatementNode(consequentExpressionData.expression)
-                );
-            }
-
-            /**
-             * Converts:
-             * if (true) {
-             *     console.log(1);
-             * }
-             *
-             * to:
-             * true && console.log(1);
-             */
-            return NodeFactory.expressionStatementNode(
-                NodeFactory.logicalExpressionNode(
-                    '&&',
-                    ifStatementNode.test,
-                    consequentExpressionData.expression,
-                )
-            );
+            return this.getConsequentNode(ifStatementNode, consequentSimplifyData);
         }
 
-        const alternateExpressionData: IIfStatementExpressionData | null = this.getIfStatementExpressionData(ifStatementNode.alternate);
+        const alternateSimplifyData: IIfStatementSimplifyData | null = this.getIfStatementSimplifyData(ifStatementNode.alternate);
 
-        if (!alternateExpressionData) {
+        if (!alternateSimplifyData) {
             return ifStatementNode;
         }
 
         // Variant #3: valid consequent and alternate expressions
+        return this.getConsequentAndAlternateNode(ifStatementNode, consequentSimplifyData, alternateSimplifyData);
+    }
+
+    /**
+     * @param {ESTree.IfStatement} ifStatementNode
+     * @param {IIfStatementSimplifyData} consequentSimplifyData
+     * @returns {ESTree.Node}
+     */
+    private getConsequentNode (
+        ifStatementNode: ESTree.IfStatement,
+        consequentSimplifyData: IIfStatementSimplifyData
+    ): ESTree.Node {
         /**
          * Converts:
          * if (true) {
+         *     const foo = 1;
+         *     console.log(1);
          *     return 1;
-         * } else {
-         *     return 2;
          * }
          *
          * to:
-         * return true ? 1 : 2;
+         * if (true) {
+         *     const foo = 1;
+         *     return console.log(1), 1;
+         * }
          */
-        if (consequentExpressionData.hasReturnStatement && alternateExpressionData.hasReturnStatement) {
-            return NodeFactory.returnStatementNode(
-                NodeFactory.conditionalExpressionNode(
-                    ifStatementNode.test,
-                    consequentExpressionData.expression,
-                    alternateExpressionData.expression
-                )
+        if (consequentSimplifyData.leadingStatements.length) {
+            return NodeFactory.ifStatementNode(
+                ifStatementNode.test,
+                NodeFactory.blockStatementNode([
+                    ...consequentSimplifyData.leadingStatements,
+                    consequentSimplifyData.statement
+                ])
             );
         }
 
@@ -138,21 +121,16 @@ export class IfStatementSimplifyTransformer extends AbstractNodeTransformer {
          * Converts:
          * if (true) {
          *     return 1;
-         * } else {
-         *     console.log(2);
          * }
          *
          * to:
          * if (true)
          *     return 1;
-         * else
-         *     console.log(2);
          */
-        if (consequentExpressionData.hasReturnStatement) {
+        if (consequentSimplifyData.hasReturnStatement) {
             return NodeFactory.ifStatementNode(
                 ifStatementNode.test,
-                NodeFactory.returnStatementNode(consequentExpressionData.expression),
-                NodeFactory.expressionStatementNode(alternateExpressionData.expression)
+                consequentSimplifyData.statement
             );
         }
 
@@ -160,21 +138,71 @@ export class IfStatementSimplifyTransformer extends AbstractNodeTransformer {
          * Converts:
          * if (true) {
          *     console.log(1);
+         * }
+         *
+         * to:
+         * true && console.log(1);
+         */
+        return NodeFactory.expressionStatementNode(
+            NodeFactory.logicalExpressionNode(
+                '&&',
+                ifStatementNode.test,
+                consequentSimplifyData.expression,
+            )
+        );
+    }
+
+    /**
+     * @param {ESTree.IfStatement} ifStatementNode
+     * @param {IIfStatementSimplifyData} consequentSimplifyData
+     * @param {IIfStatementSimplifyData} alternateSimplifyData
+     * @returns {ESTree.Node}
+     */
+    private getConsequentAndAlternateNode (
+        ifStatementNode: ESTree.IfStatement,
+        consequentSimplifyData: IIfStatementSimplifyData,
+        alternateSimplifyData: IIfStatementSimplifyData
+    ): ESTree.Node {
+        /**
+         * Converts:
+         * if (true) {
+         *     return 1;
          * } else {
          *     return 2;
          * }
          *
          * to:
+         * return true ? 1 : 2;
+         */
+        if (consequentSimplifyData.hasReturnStatement && alternateSimplifyData.hasReturnStatement) {
+            return NodeFactory.returnStatementNode(
+                NodeFactory.conditionalExpressionNode(
+                    ifStatementNode.test,
+                    consequentSimplifyData.expression,
+                    alternateSimplifyData.expression
+                )
+            );
+        }
+
+        /**
+         * Converts:
+         * if (true) {
+         *     return 1;
+         * } else {
+         *     console.log(2);
+         * }
+         *
+         * to:
          * if (true)
-         *     console.log(1);
+         *     return 1;
          * else
-         *     return 2;
+         *     console.log(2);
          */
-        if (alternateExpressionData.hasReturnStatement) {
+        if (consequentSimplifyData.hasReturnStatement || alternateSimplifyData.hasReturnStatement) {
             return NodeFactory.ifStatementNode(
                 ifStatementNode.test,
-                NodeFactory.expressionStatementNode(consequentExpressionData.expression),
-                NodeFactory.returnStatementNode(alternateExpressionData.expression)
+                consequentSimplifyData.statement,
+                alternateSimplifyData.statement
             );
         }
 
@@ -192,27 +220,37 @@ export class IfStatementSimplifyTransformer extends AbstractNodeTransformer {
         return NodeFactory.expressionStatementNode(
             NodeFactory.conditionalExpressionNode(
                 ifStatementNode.test,
-                consequentExpressionData.expression,
-                alternateExpressionData.expression
+                consequentSimplifyData.expression,
+                alternateSimplifyData.expression
             )
         );
     }
 
     /**
      * @param {ESTree.Statement | null | undefined} statementNode
-     * @returns {IIfStatementExpressionData | null}
+     * @returns {IIfStatementSimplifyData | null}
      */
-    private getIfStatementExpressionData (
+    // eslint-disable-next-line complexity
+    private getIfStatementSimplifyData (
         statementNode: ESTree.Statement | null | undefined
-    ): IIfStatementExpressionData | null {
+    ): IIfStatementSimplifyData | null {
         if (!statementNode || !NodeGuards.isBlockStatementNode(statementNode)) {
             return null;
         }
 
+        const statementNodeBodyLength: number = statementNode.body.length;
         const unwrappedExpressions: ESTree.Expression[] = [];
+
         let hasReturnStatement: boolean = false;
+        let startIndex: number | null = 0;
+
+        for (let i = 0; i < statementNodeBodyLength; i++) {
+            const statementBodyStatementNode: ESTree.Statement = statementNode.body[i];
+
+            if (startIndex === null) {
+                startIndex = i;
+            }
 
-        for (const statementBodyStatementNode of statementNode.body) {
             if (NodeGuards.isExpressionStatementNode(statementBodyStatementNode)) {
                 unwrappedExpressions.push(statementBodyStatementNode.expression);
                 continue;
@@ -227,18 +265,33 @@ export class IfStatementSimplifyTransformer extends AbstractNodeTransformer {
                 continue;
             }
 
-            return null;
+            startIndex = null;
+            unwrappedExpressions.length = 0;
         }
 
-        if (!unwrappedExpressions.length) {
+        if (startIndex === null || !unwrappedExpressions.length) {
             return null;
         }
 
+        const hasSingleExpression: boolean = unwrappedExpressions.length === 1;
+
+        const expression: ESTree.Expression = hasSingleExpression
+            ? unwrappedExpressions[0]
+            : NodeFactory.sequenceExpressionNode(unwrappedExpressions);
+
+        const leadingStatements: ESTree.Statement[] = startIndex > 0
+            ? statementNode.body.slice(0, startIndex)
+            : [];
+        const statement: ESTree.Statement = hasReturnStatement
+            ? NodeFactory.returnStatementNode(expression)
+            : NodeFactory.expressionStatementNode(expression);
+
         return {
-            expression: unwrappedExpressions.length === 1
-                ? unwrappedExpressions[0]
-                : NodeFactory.sequenceExpressionNode(unwrappedExpressions),
-            hasReturnStatement
+            leadingStatements,
+            statement,
+            expression,
+            hasReturnStatement,
+            hasSingleExpression
         };
     }
 }

+ 32 - 3
test/functional-tests/node-transformers/minification-transformers/if-statement-simplify-transformer/IfStatementSimplifyTransformer.spec.ts

@@ -381,8 +381,7 @@ describe('IfStatementSimplifyTransformer', () => {
                     const regExp: RegExp = new RegExp(
                         'if *\\(!!\\[]\\) *{ *' +
                             'const _0x([a-f0-9]){4,6} *= *baz\\(\\); *' +
-                            'bark\\(\\); *' +
-                            'return hawk\\(\\);' +
+                            'bark\\(\\), *hawk\\(\\);' +
                         '}'
                     );
 
@@ -401,7 +400,37 @@ describe('IfStatementSimplifyTransformer', () => {
                         ).getObfuscatedCode();
                     });
 
-                    it('should not simplify if statement', () => {
+                    it('should simplify if statement', () => {
+                        assert.match(obfuscatedCode, regExp);
+                    });
+                });
+            });
+
+            describe('With `ReturnStatement`', () => {
+                describe('Variant #1: multiple statements', () => {
+                    const regExp: RegExp = new RegExp(
+                        'if *\\(!!\\[]\\) *{ *' +
+                            'const _0x([a-f0-9]){4,6} *= *baz\\(\\); *' +
+                            'return bark\\(\\), *hawk\\(\\);' +
+                        '}'
+                    );
+
+
+                    let obfuscatedCode: string;
+
+                    before(() => {
+                        const code: string = readFileAsString(__dirname + '/fixtures/partial-consequent-only-return-multiple-statements.js');
+
+                        obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                            code,
+                            {
+                                ...NO_ADDITIONAL_NODES_PRESET,
+                                minify: true
+                            }
+                        ).getObfuscatedCode();
+                    });
+
+                    it('should simplify if statement', () => {
                         assert.match(obfuscatedCode, regExp);
                     });
                 });

+ 1 - 2
test/functional-tests/node-transformers/minification-transformers/if-statement-simplify-transformer/fixtures/partial-consequent-only-no-return-multiple-statements.js

@@ -3,7 +3,6 @@ function foo () {
         const bar = baz();
 
         bark();
-
-        return hawk();
+        hawk();
     }
 }

+ 9 - 0
test/functional-tests/node-transformers/minification-transformers/if-statement-simplify-transformer/fixtures/partial-consequent-only-return-multiple-statements.js

@@ -0,0 +1,9 @@
+function foo () {
+    if (true) {
+        const bar = baz();
+
+        bark();
+
+        return hawk();
+    }
+}

部分文件因为文件数量过多而无法显示