Browse Source

Dead code injection transformer ignores PrivateIdentifier nodes (#1057)

Timofey Kachalov 3 năm trước cách đây
mục cha
commit
2095d47058

+ 4 - 0
CHANGELOG.md

@@ -1,5 +1,9 @@
 Change Log
 
+v3.2.5
+---
+* Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1056
+
 v3.2.4
 ---
 * Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/1052

+ 1 - 1
package.json

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

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

@@ -40,6 +40,7 @@ export enum NodeType {
     NewExpression = 'NewExpression',
     ObjectExpression = 'ObjectExpression',
     ObjectPattern = 'ObjectPattern',
+    PrivateIdentifier = 'PrivateIdentifier',
     Program = 'Program',
     Property = 'Property',
     PropertyDefinition = 'PropertyDefinition',

+ 2 - 1
src/node-transformers/dead-code-injection-transformers/DeadCodeInjectionTransformer.ts

@@ -107,7 +107,8 @@ export class DeadCodeInjectionTransformer extends AbstractNodeTransformer {
             || NodeGuards.isAwaitExpressionNode(targetNode)
             || NodeGuards.isYieldExpressionNode(targetNode)
             || NodeGuards.isSuperNode(targetNode)
-            || (NodeGuards.isForOfStatementNode(targetNode) && targetNode.await);
+            || (NodeGuards.isForOfStatementNode(targetNode) && targetNode.await)
+            || NodeGuards.isPrivateIdentifierNode(targetNode);
     }
 
     /**

+ 8 - 0
src/node/NodeGuards.ts

@@ -447,6 +447,14 @@ export class NodeGuards {
         return node.type === NodeType.ObjectExpression;
     }
 
+    /**
+     * @param {Node} node
+     * @returns {boolean}
+     */
+    public static isPrivateIdentifierNode (node: ESTree.Node): node is ESTree.PrivateIdentifier {
+        return node.type === NodeType.PrivateIdentifier;
+    }
+
     /**
      * @param {Node} node
      * @returns {boolean}

+ 51 - 0
test/functional-tests/node-transformers/dead-code-injection-transformers/DeadCodeInjectionTransformer.spec.ts

@@ -489,6 +489,57 @@ describe('DeadCodeInjectionTransformer', () => {
                     assert.equal(awaitExpressionMatchesLength, expectedAwaitExpressionMatchesLength);
                 });
             });
+
+            describe('Variant #7 - private identifier in block statement', () => {
+                const functionRegExp: RegExp = new RegExp(
+                    `var ${variableMatch} *= *function *\\(\\) *\\{` +
+                        `console\\[${variableMatch}\\(${hexMatch}\\)\\]\\(${variableMatch}\\(${hexMatch}\\)\\);` +
+                    `\\};`,
+                    'g'
+                );
+                const privateIdentifierRegExp: RegExp = new RegExp(
+                    `this\.#private *= *0x1;`,
+                    'g'
+                );
+                const expectedFunctionMatchesLength: number = 4;
+                const expectedPrivateIdentifierMatchesLength: number = 1;
+
+                let functionMatchesLength: number = 0,
+                    privateIdentifierMatchesLength: number = 0;
+
+                before(() => {
+                    const code: string = readFileAsString(__dirname + '/fixtures/private-identifier.js');
+
+                    const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
+                        code,
+                        {
+                            ...NO_ADDITIONAL_NODES_PRESET,
+                            deadCodeInjection: true,
+                            deadCodeInjectionThreshold: 1,
+                            stringArray: true,
+                            stringArrayThreshold: 1
+                        }
+                    ).getObfuscatedCode();
+                    const functionMatches: RegExpMatchArray = <RegExpMatchArray>obfuscatedCode.match(functionRegExp);
+                    const privateIdentifierMatches: RegExpMatchArray = <RegExpMatchArray>obfuscatedCode.match(privateIdentifierRegExp);
+
+                    if (functionMatches) {
+                        functionMatchesLength = functionMatches.length;
+                    }
+
+                    if (privateIdentifierMatches) {
+                        privateIdentifierMatchesLength = privateIdentifierMatches.length;
+                    }
+                });
+
+                it('match #1: shouldn\'t add dead code', () => {
+                    assert.equal(functionMatchesLength, expectedFunctionMatchesLength);
+                });
+
+                it('match #2: shouldn\'t add dead code', () => {
+                    assert.equal(privateIdentifierMatchesLength, expectedPrivateIdentifierMatchesLength);
+                });
+            });
         });
 
         describe('Variant #5 - chance of `IfStatement` variant', () => {

+ 29 - 0
test/functional-tests/node-transformers/dead-code-injection-transformers/fixtures/private-identifier.js

@@ -0,0 +1,29 @@
+class Foo {
+    #private;
+
+    constructor(props) {
+        if (true) {
+            var foo = function () {
+                console.log('abc');
+            };
+            var bar = function () {
+                console.log('def');
+            };
+            var baz = function () {
+                console.log('ghi');
+            };
+            var bark = function () {
+                console.log('jkl');
+            };
+
+            if (true) {
+                this.#private = 1;
+            }
+
+            foo();
+            bar();
+            baz();
+            bark();
+        }
+    }
+}