Przeglądaj źródła

Merge pull request #848 from javascript-obfuscator/directive-placement-refactoring

Directive placement refactoring
Timofey Kachalov 4 lat temu
rodzic
commit
10c7bf26ee

Plik diff jest za duży
+ 0 - 0
dist/index.browser.js


Plik diff jest za duży
+ 0 - 0
dist/index.cli.js


Plik diff jest za duży
+ 0 - 0
dist/index.js


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

@@ -13,25 +13,13 @@ declare module 'estree' {
         ignoredNode?: boolean;
     }
 
-    export interface FunctionNodeMetadata extends BaseNodeMetadata {
-        directiveNode?: Directive | null;
-    }
-
     export interface LiteralNodeMetadata extends BaseNodeMetadata {
         replacedLiteral?: boolean;
     }
 
-    export interface ProgramNodeMetadata extends BaseNodeMetadata {
-        directiveNode?: Directive | null;
-    }
-
     /**
      * Nodes
      */
-    interface ArrowFunctionExpression extends BaseNode {
-        metadata?: FunctionNodeMetadata;
-    }
-
     interface BaseNode {
         metadata?: BaseNodeMetadata;
         parentNode?: Node;
@@ -47,16 +35,7 @@ declare module 'estree' {
         loc?: acorn.SourceLocation;
     }
 
-    interface FunctionExpression extends BaseNode {
-        metadata?: FunctionNodeMetadata;
-    }
-
-    interface FunctionDeclaration extends BaseNode {
-        metadata?: FunctionNodeMetadata;
-    }
-
     interface Program extends BaseNode {
-        metadata?: ProgramNodeMetadata;
         scope?: eslintScope.Scope | null;
     }
 

+ 11 - 3
src/node-transformers/finalizing-transformers/DirectivePlacementTransformer.ts

@@ -4,6 +4,7 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
 import * as estraverse from 'estraverse';
 import * as ESTree from 'estree';
 
+import { TNodeWithLexicalScope } from '../../types/node/TNodeWithLexicalScope';
 import { TNodeWithLexicalScopeStatements } from '../../types/node/TNodeWithLexicalScopeStatements';
 
 import { IOptions } from '../../interfaces/options/IOptions';
@@ -16,7 +17,6 @@ import { NodeTransformer } from '../../enums/node-transformers/NodeTransformer';
 import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
 import { NodeAppender } from '../../node/NodeAppender';
 import { NodeGuards } from '../../node/NodeGuards';
-import { NodeMetadata } from '../../node/NodeMetadata';
 import { NodeUtils } from '../../node/NodeUtils';
 
 /**
@@ -32,6 +32,14 @@ export class DirectivePlacementTransformer extends AbstractNodeTransformer {
         NodeTransformer.CustomCodeHelpersTransformer
     ];
 
+    /**
+     * @type {WeakMap<TNodeWithLexicalScope, Directive>}
+     */
+    private readonly lexicalScopeDirectives: WeakMap<
+        TNodeWithLexicalScope,
+        ESTree.Directive
+    > = new WeakMap<TNodeWithLexicalScope, ESTree.Directive>();
+
     /**
      * @param {IRandomGenerator} randomGenerator
      * @param {IOptions} options
@@ -94,7 +102,7 @@ export class DirectivePlacementTransformer extends AbstractNodeTransformer {
         const firstStatementNode = nodeWithLexicalScopeStatements.body[0] ?? null;
 
         if (firstStatementNode && NodeGuards.isDirectiveNode(firstStatementNode)) {
-            NodeMetadata.set(parentNode, {directiveNode: firstStatementNode});
+            this.lexicalScopeDirectives.set(parentNode, firstStatementNode);
         }
 
         return nodeWithLexicalScopeStatements;
@@ -113,7 +121,7 @@ export class DirectivePlacementTransformer extends AbstractNodeTransformer {
             return nodeWithLexicalScopeStatements;
         }
 
-        const directiveNode: ESTree.Directive | null | undefined = NodeMetadata.getDirectiveNode(parentNode);
+        const directiveNode: ESTree.Directive | undefined = this.lexicalScopeDirectives.get(parentNode);
 
         if (directiveNode) {
             const newDirectiveNode: ESTree.Directive = NodeUtils.clone(directiveNode);

+ 0 - 13
src/node/NodeMetadata.ts

@@ -1,5 +1,4 @@
 import * as ESTree from 'estree';
-import { TNodeWithLexicalScope } from '../types/node/TNodeWithLexicalScope';
 
 export class NodeMetadata {
     /**
@@ -47,16 +46,4 @@ export class NodeMetadata {
     public static isReplacedLiteral (literalNode: ESTree.Literal): boolean {
         return NodeMetadata.get<ESTree.LiteralNodeMetadata, 'replacedLiteral'>(literalNode, 'replacedLiteral') === true;
     }
-
-    /**
-     * @param {TNodeWithLexicalScope} nodeWithLexicalScope
-     * @returns {Directive | null | undefined}
-     */
-    public static getDirectiveNode (nodeWithLexicalScope: TNodeWithLexicalScope): ESTree.Directive | null | undefined {
-        return NodeMetadata.get<
-            ESTree.ProgramNodeMetadata
-            | ESTree.FunctionNodeMetadata,
-            'directiveNode'
-        >(nodeWithLexicalScope, 'directiveNode');
-    }
 }

+ 128 - 8
test/functional-tests/node-transformers/finalizing-transformers/directive-placement-transformer/DirectivePlacementTransformer.spec.ts

@@ -9,7 +9,7 @@ import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFac
 describe('DirectivePlacementTransformer', function () {
     this.timeout(120000);
 
-    describe('Program lexical scope', () => {
+    describe('Variant #1: program scope', () => {
         describe('Variant #1: directive at the top of program scope', () => {
             const directiveRegExp: RegExp = /^'use strict'; *var _0x([a-f0-9]){4} *= *\['test'];/;
 
@@ -62,8 +62,8 @@ describe('DirectivePlacementTransformer', function () {
         });
     });
 
-    describe('Function lexical scope', () => {
-        describe('Variant #1: directive at the top of function scope', () => {
+    describe('Variant #2: function declaration scope', () => {
+        describe('Variant #1: directive at the top of function declaration scope', () => {
             const directiveRegExp: RegExp = new RegExp(
                 'function test\\(\\) *{ *' +
                     '\'use strict\'; *' +
@@ -74,7 +74,7 @@ describe('DirectivePlacementTransformer', function () {
             let obfuscatedCode: string;
 
             before(() => {
-                const code: string = readFileAsString(__dirname + '/fixtures/top-of-function-scope.js');
+                const code: string = readFileAsString(__dirname + '/fixtures/top-of-function-declaration-scope.js');
 
                 obfuscatedCode = JavaScriptObfuscator.obfuscate(
                     code,
@@ -87,12 +87,12 @@ describe('DirectivePlacementTransformer', function () {
                 ).getObfuscatedCode();
             });
 
-            it('should keep directive at the top of function scope', () => {
+            it('should keep directive at the top of function declaration scope', () => {
                 assert.match(obfuscatedCode, directiveRegExp);
             });
         });
 
-        describe('Variant #2: directive-like string literal at the middle of function scope', () => {
+        describe('Variant #2: directive-like string literal at the middle of function-declaration scope', () => {
             const directiveRegExp: RegExp = new RegExp(
                 'function test\\(\\) *{ *' +
                     'var _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4}; *' +
@@ -103,7 +103,7 @@ describe('DirectivePlacementTransformer', function () {
             let obfuscatedCode: string;
 
             before(() => {
-                const code: string = readFileAsString(__dirname + '/fixtures/middle-of-function-scope.js');
+                const code: string = readFileAsString(__dirname + '/fixtures/middle-of-function-declaration-scope.js');
 
                 obfuscatedCode = JavaScriptObfuscator.obfuscate(
                     code,
@@ -116,7 +116,127 @@ describe('DirectivePlacementTransformer', function () {
                 ).getObfuscatedCode();
             });
 
-            it('should keep directive-like string literal at the middle of function scope', () => {
+            it('should keep directive-like string literal at the middle of function declaration scope', () => {
+                assert.match(obfuscatedCode, directiveRegExp);
+            });
+        })
+    });
+
+    describe('Variant #3: function expression scope', () => {
+        describe('Variant #1: directive at the top of function expression scope', () => {
+            const directiveRegExp: RegExp = new RegExp(
+                'var test *= *function *\\(\\) *{ *' +
+                    '\'use strict\'; *' +
+                    'var _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4}; *' +
+                    'var _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(0x0\\);'
+            );
+
+            let obfuscatedCode: string;
+
+            before(() => {
+                const code: string = readFileAsString(__dirname + '/fixtures/top-of-function-expression-scope.js');
+
+                obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                    code,
+                    {
+                        ...NO_ADDITIONAL_NODES_PRESET,
+                        stringArray: true,
+                        stringArrayThreshold: 1,
+                        stringArrayWrappersCount: 1
+                    }
+                ).getObfuscatedCode();
+            });
+
+            it('should keep directive at the top of function expression scope', () => {
+                assert.match(obfuscatedCode, directiveRegExp);
+            });
+        });
+
+        describe('Variant #2: directive-like string literal at the middle of function-expression scope', () => {
+            const directiveRegExp: RegExp = new RegExp(
+                'var test *= *function *\\(\\) *{ *' +
+                    'var _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4}; *' +
+                    'var _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(0x0\\);' +
+                    '_0x([a-f0-9]){4,6}\\(0x1\\);'
+            );
+
+            let obfuscatedCode: string;
+
+            before(() => {
+                const code: string = readFileAsString(__dirname + '/fixtures/middle-of-function-expression-scope.js');
+
+                obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                    code,
+                    {
+                        ...NO_ADDITIONAL_NODES_PRESET,
+                        stringArray: true,
+                        stringArrayThreshold: 1,
+                        stringArrayWrappersCount: 1
+                    }
+                ).getObfuscatedCode();
+            });
+
+            it('should keep directive-like string literal at the middle of function expression scope', () => {
+                assert.match(obfuscatedCode, directiveRegExp);
+            });
+        })
+    });
+
+    describe('Variant #4: arrow function expression scope', () => {
+        describe('Variant #1: directive at the top of arrow function expression scope', () => {
+            const directiveRegExp: RegExp = new RegExp(
+                'var test *= *\\(\\) *=> *{ *' +
+                    '\'use strict\'; *' +
+                    'var _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4}; *' +
+                    'var _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(0x0\\);'
+            );
+
+            let obfuscatedCode: string;
+
+            before(() => {
+                const code: string = readFileAsString(__dirname + '/fixtures/top-of-arrow-function-expression-scope.js');
+
+                obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                    code,
+                    {
+                        ...NO_ADDITIONAL_NODES_PRESET,
+                        stringArray: true,
+                        stringArrayThreshold: 1,
+                        stringArrayWrappersCount: 1
+                    }
+                ).getObfuscatedCode();
+            });
+
+            it('should keep directive at the top of arrow function expression scope', () => {
+                assert.match(obfuscatedCode, directiveRegExp);
+            });
+        });
+
+        describe('Variant #2: directive-like string literal at the middle of arrow function-expression scope', () => {
+            const directiveRegExp: RegExp = new RegExp(
+                'var test *= *\\(\\) *=> *{ *' +
+                    'var _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4}; *' +
+                    'var _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(0x0\\);' +
+                    '_0x([a-f0-9]){4,6}\\(0x1\\);'
+            );
+
+            let obfuscatedCode: string;
+
+            before(() => {
+                const code: string = readFileAsString(__dirname + '/fixtures/middle-of-arrow-function-expression-scope.js');
+
+                obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                    code,
+                    {
+                        ...NO_ADDITIONAL_NODES_PRESET,
+                        stringArray: true,
+                        stringArrayThreshold: 1,
+                        stringArrayWrappersCount: 1
+                    }
+                ).getObfuscatedCode();
+            });
+
+            it('should keep directive-like string literal at the middle of arrow function expression scope', () => {
                 assert.match(obfuscatedCode, directiveRegExp);
             });
         })

+ 4 - 0
test/functional-tests/node-transformers/finalizing-transformers/directive-placement-transformer/fixtures/middle-of-arrow-function-expression-scope.js

@@ -0,0 +1,4 @@
+var test = () => {
+    var test = 'test';
+    'use strict';
+};

+ 0 - 0
test/functional-tests/node-transformers/finalizing-transformers/directive-placement-transformer/fixtures/middle-of-function-scope.js → test/functional-tests/node-transformers/finalizing-transformers/directive-placement-transformer/fixtures/middle-of-function-declaration-scope.js


+ 4 - 0
test/functional-tests/node-transformers/finalizing-transformers/directive-placement-transformer/fixtures/middle-of-function-expression-scope.js

@@ -0,0 +1,4 @@
+var test = function () {
+    var test = 'test';
+    'use strict';
+};

+ 4 - 0
test/functional-tests/node-transformers/finalizing-transformers/directive-placement-transformer/fixtures/top-of-arrow-function-expression-scope.js

@@ -0,0 +1,4 @@
+var test = () => {
+    'use strict';
+    var test = 'test';
+};

+ 0 - 0
test/functional-tests/node-transformers/finalizing-transformers/directive-placement-transformer/fixtures/top-of-function-scope.js → test/functional-tests/node-transformers/finalizing-transformers/directive-placement-transformer/fixtures/top-of-function-declaration-scope.js


+ 4 - 0
test/functional-tests/node-transformers/finalizing-transformers/directive-placement-transformer/fixtures/top-of-function-expression-scope.js

@@ -0,0 +1,4 @@
+var test = function () {
+    'use strict';
+    var test = 'test';
+};

Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików