瀏覽代碼

Merge pull request #1043 from javascript-obfuscator/class-static-block-support

Class static block support
Timofey Kachalov 3 年之前
父節點
當前提交
c59453603d

+ 4 - 0
CHANGELOG.md

@@ -1,5 +1,9 @@
 Change Log
 
+v3.1.0
+---
+* Added support of `es2022` features: class static block
+
 v3.0.1
 ---
 * Dependencies update

+ 28 - 26
package.json

@@ -1,6 +1,6 @@
 {
   "name": "javascript-obfuscator",
-  "version": "3.0.1",
+  "version": "3.1.0",
   "description": "JavaScript obfuscator",
   "keywords": [
     "obfuscator",
@@ -21,16 +21,17 @@
   },
   "types": "typings/index.d.ts",
   "dependencies": {
-    "@javascript-obfuscator/escodegen": "2.2.2",
-    "@javascript-obfuscator/estraverse": "5.3.0",
+    "@javascript-obfuscator/escodegen": "2.3.0",
+    "@javascript-obfuscator/estraverse": "5.4.0",
     "@nuxtjs/opencollective": "0.3.2",
-    "acorn": "8.5.0",
+    "acorn": "8.7.0",
     "assert": "2.0.0",
     "chalk": "4.1.2",
     "chance": "1.1.8",
     "class-validator": "0.13.2",
-    "commander": "8.3.0",
-    "eslint-scope": "6.0.0",
+    "commander": "9.0.0",
+    "eslint-scope": "7.1.0",
+    "eslint-visitor-keys": "3.2.0",
     "fast-deep-equal": "3.1.3",
     "inversify": "6.0.1",
     "js-string-escape": "1.0.1",
@@ -39,58 +40,59 @@
     "multimatch": "5.0.0",
     "process": "0.11.10",
     "reflect-metadata": "0.1.13",
-    "source-map-support": "0.5.20",
+    "source-map-support": "0.5.21",
     "string-template": "1.0.0",
     "stringz": "2.1.0",
     "tslib": "2.3.1"
   },
   "devDependencies": {
-    "@istanbuljs/nyc-config-typescript": "1.0.1",
-    "@types/chai": "4.2.22",
+    "@istanbuljs/nyc-config-typescript": "1.0.2",
+    "@types/chai": "4.3.0",
     "@types/chance": "1.1.3",
     "@types/escodegen": "0.0.7",
-    "@types/eslint-scope": "3.7.1",
+    "@types/eslint-scope": "3.7.3",
+    "@types/eslint-visitor-keys": "1.0.0",
     "@types/estraverse": "5.1.1",
     "@types/estree": "0.0.50",
     "@types/js-beautify": "1.13.3",
     "@types/js-string-escape": "1.0.1",
     "@types/md5": "2.3.1",
     "@types/mkdirp": "1.0.2",
-    "@types/mocha": "9.0.0",
+    "@types/mocha": "9.1.0",
     "@types/multimatch": "4.0.0",
-    "@types/node": "16.11.6",
+    "@types/node": "17.0.13",
     "@types/rimraf": "3.0.2",
-    "@types/sinon": "10.0.6",
+    "@types/sinon": "10.0.9",
     "@types/string-template": "1.0.2",
     "@types/webpack-env": "1.16.3",
-    "@typescript-eslint/eslint-plugin": "5.2.0",
-    "@typescript-eslint/parser": "5.2.0",
-    "chai": "4.3.4",
+    "@typescript-eslint/eslint-plugin": "5.10.1",
+    "@typescript-eslint/parser": "5.10.1",
+    "chai": "4.3.6",
     "chai-exclude": "2.1.0",
     "cross-env": "7.0.3",
-    "eslint": "8.1.0",
-    "eslint-plugin-import": "2.25.2",
-    "eslint-plugin-jsdoc": "37.0.3",
+    "eslint": "8.8.0",
+    "eslint-plugin-import": "2.25.4",
+    "eslint-plugin-jsdoc": "37.7.0",
     "eslint-plugin-no-null": "1.0.2",
     "eslint-plugin-prefer-arrow": "1.2.3",
-    "eslint-plugin-unicorn": "37.0.1",
+    "eslint-plugin-unicorn": "40.1.0",
     "fork-ts-checker-notifier-webpack-plugin": "4.0.0",
     "fork-ts-checker-webpack-plugin": "6.4.0",
     "husky": "7.0.4",
     "js-beautify": "1.14.0",
-    "mocha": "9.1.3",
+    "mocha": "9.2.0",
     "nyc": "15.1.0",
     "pjson": "1.0.9",
     "rimraf": "3.0.2",
-    "sinon": "11.1.2",
+    "sinon": "13.0.0",
     "source-map-resolve": "0.6.0",
-    "terser": "5.9.0",
+    "terser": "5.10.0",
     "threads": "1.7.0",
     "ts-loader": "9.2.6",
     "ts-node": "10.4.0",
-    "typescript": "4.4.4",
-    "webpack": "5.61.0",
-    "webpack-cli": "4.9.1",
+    "typescript": "4.5.5",
+    "webpack": "5.67.0",
+    "webpack-cli": "4.9.2",
     "webpack-node-externals": "3.0.0"
   },
   "repository": {

+ 5 - 1
src/analyzers/scope-analyzer/ScopeAnalyzer.ts

@@ -2,6 +2,7 @@ import { injectable, } from 'inversify';
 
 import * as eslintScope from 'eslint-scope';
 import * as estraverse from '@javascript-obfuscator/estraverse';
+import { KEYS, VisitorKeys } from 'eslint-visitor-keys';
 import * as ESTree from 'estree';
 
 import { IScopeAnalyzer } from '../../interfaces/analyzers/scope-analyzer/IScopeAnalyzer';
@@ -15,8 +16,11 @@ export class ScopeAnalyzer implements IScopeAnalyzer {
     /**
      * @type {eslintScope.AnalysisOptions}
      */
-    private static readonly eslintScopeOptions: eslintScope.AnalysisOptions = {
+    private static readonly eslintScopeOptions: eslintScope.AnalysisOptions & {
+        childVisitorKeys: VisitorKeys;
+    } = {
         ecmaVersion,
+        childVisitorKeys: KEYS,
         optimistic: true
     };
 

+ 5 - 0
src/declarations/ESTree.d.ts

@@ -3,6 +3,7 @@
 import * as acorn from 'acorn';
 import * as escodegen from '@javascript-obfuscator/escodegen';
 import * as eslintScope from 'eslint-scope';
+import { BlockStatement } from 'estree';
 
 declare module 'estree' {
     /**
@@ -53,4 +54,8 @@ declare module 'estree' {
         metadata?: LiteralNodeMetadata;
         'x-verbatim-property'?: escodegen.XVerbatimProperty;
     }
+
+    interface StaticBlock extends Omit<BlockStatement, 'type'> {
+        type: 'StaticBlock'
+    }
 }

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

@@ -47,6 +47,7 @@ export enum NodeType {
     ReturnStatement = 'ReturnStatement',
     SequenceExpression = 'SequenceExpression',
     SpreadElement = 'SpreadElement',
+    StaticBlock = 'StaticBlock',
     Super = 'Super',
     SwitchCase = 'SwitchCase',
     SwitchStatement = 'SwitchStatement',

+ 12 - 0
src/node/NodeFactory.ts

@@ -544,6 +544,18 @@ export class NodeFactory {
         };
     }
 
+    /**
+     * @param {Statement[]} body
+     * @returns {StaticBlock}
+     */
+    public static staticBlockNode (body: ESTree.Statement[] = []): ESTree.StaticBlock {
+        return {
+            type: NodeType.StaticBlock,
+            body,
+            metadata: { ignoredNode: false }
+        };
+    }
+
     /**
      * @param {Expression} discriminant
      * @param {SwitchCase[]} cases

+ 14 - 1
src/node/NodeGuards.ts

@@ -365,7 +365,9 @@ export class NodeGuards {
      * @returns {boolean}
      */
     public static isNodeWithBlockLexicalScope (node: ESTree.Node): node is TNodeWithLexicalScope {
-        return NodeGuards.isNodeWithLexicalScope(node) || NodeGuards.isBlockStatementNode(node);
+        return NodeGuards.isNodeWithLexicalScope(node)
+            || NodeGuards.isBlockStatementNode(node)
+            || NodeGuards.isStaticBlockNode(node);
     }
 
     /**
@@ -417,6 +419,7 @@ export class NodeGuards {
     public static isNodeWithStatements (node: ESTree.Node): node is TNodeWithStatements {
         return NodeGuards.isProgramNode(node)
             || NodeGuards.isBlockStatementNode(node)
+            || NodeGuards.isStaticBlockNode(node)
             || NodeGuards.isSwitchCaseNode(node);
     }
 
@@ -500,6 +503,16 @@ export class NodeGuards {
         return node.type === NodeType.SpreadElement;
     }
 
+    /**
+     * @param {Node} node
+     * @returns {boolean}
+     */
+    // TODO: add type guard after @types/estree update
+    public static isStaticBlockNode (node: ESTree.Node): boolean {
+        // TODO: Update @types/estree
+        return (<any>node).type === NodeType.StaticBlock;
+    }
+
     /**
      * @param {Node} node
      * @returns {boolean}

+ 4 - 7
test/dev/dev.ts

@@ -1,18 +1,15 @@
 'use strict';
 
-import { readFileAsString } from '../helpers/readFileAsString';
-
 (function () {
     const JavaScriptObfuscator: any = require('../../index');
-    const code: string = readFileAsString(__dirname + '/../functional-tests/javascript-obfuscator/fixtures/custom-nodes-identifier-names-collision.js');
+    const code: string = `
+        class Foo {}
+    `;
 
     let obfuscationResult = JavaScriptObfuscator.obfuscate(
         code,
         {
-            identifierNamesGenerator: 'mangled',
-            compact: false,
-            stringArray: true,
-            seed: 429105580
+            compact: false
         }
     );
 

+ 36 - 0
test/functional-tests/javascript-obfuscator/JavaScriptObfuscator.spec.ts

@@ -984,6 +984,42 @@ describe('JavaScriptObfuscator', () => {
             });
         });
 
+        describe('Class static block support', () => {
+            const regExp: RegExp = new RegExp(
+                'let _0x(\\w){4,6} *= *0x1; *' +
+                'class _0x(\\w){4,6} *{ *' +
+                    'static *\\[\'_0x(\\w){4,6}\']; *' +
+                    'static *{ *' +
+                        'let _0x(\\w){4,6} *= *0x2; *' +
+                        '_0x(\\w){4,6}\\[\'_0x(\\w){4,6}\'] *= *0x3; *' +
+                        '_0x(\\w){4,6} *= *0x4; *' +
+                        '_0x(\\w){4,6} *= *0x5; *' +
+                    '} *' +
+                '}'
+            );
+
+            let obfuscatedCode: string;
+
+            beforeEach(() => {
+                const code: string = readFileAsString(__dirname + '/fixtures/class-static-block-support-1.js');
+
+                obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                    code,
+                    {
+                        ...NO_ADDITIONAL_NODES_PRESET,
+                        renameGlobals: true,
+                        renameProperties: true
+                    }
+                ).getObfuscatedCode();
+
+                console.log(obfuscatedCode);
+            });
+
+            it('should support class static block await', () => {
+                assert.match(obfuscatedCode, regExp);
+            });
+        });
+
         describe('Private identifiers support', () => {
             const regExp: RegExp = new RegExp(
                 'class Foo *{ *' +

+ 11 - 0
test/functional-tests/javascript-obfuscator/fixtures/class-static-block-support-1.js

@@ -0,0 +1,11 @@
+let foo = 1;
+class Foo {
+    static abc;
+
+    static {
+        let bar = 2;
+        Foo.abc = 3;
+        foo = 4;
+        bar = 5;
+    }
+}

+ 17 - 1
test/unit-tests/node/node-guards/NodeGuards.spec.ts

@@ -705,7 +705,23 @@ describe('NodeGuards', () => {
                 });
             });
 
-            describe('Variant #3: switch case node', () => {
+            describe('Variant #3: static block node', () => {
+                const expectedResult: boolean = true;
+                // TODO: remove typecast after @types/estree update
+                const node: ESTree.Node = <any>NodeFactory.staticBlockNode();
+
+                let result: boolean;
+
+                before(() => {
+                    result = NodeGuards.isNodeWithStatements(node);
+                });
+
+                it('should check if node has statements', () => {
+                    assert.equal(result, expectedResult);
+                });
+            });
+
+            describe('Variant #4: switch case node', () => {
                 const expectedResult: boolean = true;
                 const node: ESTree.Node = NodeFactory.switchCaseNode(
                     NodeFactory.literalNode(1),

文件差異過大導致無法顯示
+ 188 - 417
yarn.lock


部分文件因文件數量過多而無法顯示