浏览代码

Fixed errors related to identifiers. Changed self defending helper

sanex3339 5 年之前
父节点
当前提交
a2e9c05ce8
共有 46 个文件被更改,包括 841 次插入304 次删除
  1. 2 2
      CHANGELOG.md
  2. 0 0
      dist/index.browser.js
  3. 0 0
      dist/index.cli.js
  4. 0 0
      dist/index.js
  5. 3 3
      src/container/modules/custom-code-helpers/CustomCodeHelpersModule.ts
  6. 5 5
      src/custom-code-helpers/calls-controller/CallsControllerFunctionCodeHelper.ts
  7. 2 2
      src/custom-code-helpers/common/templates/SingleCallControllerTemplate.ts
  8. 13 5
      src/custom-code-helpers/console-output/ConsoleOutputDisableCodeHelper.ts
  9. 49 27
      src/custom-code-helpers/console-output/group/ConsoleOutputCodeHelperGroup.ts
  10. 1 1
      src/custom-code-helpers/console-output/templates/ConsoleOutputDisableExpressionTemplate.ts
  11. 1 1
      src/custom-code-helpers/debug-protection/DebugProtectionFunctionCallCodeHelper.ts
  12. 67 39
      src/custom-code-helpers/debug-protection/group/DebugProtectionCodeHelperGroup.ts
  13. 1 1
      src/custom-code-helpers/debug-protection/templates/debug-protection-function-call/DebugProtectionFunctionCallTemplate.ts
  14. 13 5
      src/custom-code-helpers/domain-lock/DomainLockCodeHelper.ts
  15. 45 23
      src/custom-code-helpers/domain-lock/group/DomainLockCustomCodeHelperGroup.ts
  16. 1 1
      src/custom-code-helpers/domain-lock/templates/DomainLockTemplate.ts
  17. 13 10
      src/custom-code-helpers/self-defending/SelfDefendingUnicodeCodeHelper.ts
  18. 43 24
      src/custom-code-helpers/self-defending/group/SelfDefendingCodeHelperGroup.ts
  19. 6 45
      src/custom-code-helpers/self-defending/templates/SelfDefendingTemplate.ts
  20. 2 2
      src/custom-code-helpers/string-array/StringArrayRotateFunctionCodeHelper.ts
  21. 18 9
      src/custom-code-helpers/string-array/group/StringArrayCodeHelperGroup.ts
  22. 1 1
      src/custom-nodes/object-expression-keys-transformer-nodes/ObjectExpressionVariableDeclarationHostNode.ts
  23. 1 1
      src/enums/custom-code-helpers/CustomCodeHelper.ts
  24. 14 1
      src/generators/identifier-names-generators/AbstractIdentifierNamesGenerator.ts
  25. 1 1
      src/generators/identifier-names-generators/DictionaryIdentifierNamesGenerator.ts
  26. 4 4
      src/generators/identifier-names-generators/HexadecimalIdentifierNamesGenerator.ts
  27. 1 1
      src/generators/identifier-names-generators/MangledIdentifierNamesGenerator.ts
  28. 8 1
      src/interfaces/generators/identifier-names-generators/IIdentifierNamesGenerator.ts
  29. 10 5
      src/node-transformers/dead-code-injection-transformers/DeadCodeInjectionTransformer.ts
  30. 3 11
      src/node-transformers/obfuscating-transformers/obfuscating-replacers/literal-obfuscating-replacers/StringLiteralObfuscatingReplacer.ts
  31. 2 0
      src/node-transformers/preparing-transformers/VariablePreserveTransformer.ts
  32. 7 7
      src/storages/string-array/StringArrayStorage.ts
  33. 21 9
      test/dev/dev.ts
  34. 40 28
      test/functional-tests/custom-code-helpers/debug-protection/templates/DebugProtectionFunctionCallTemplate.spec.ts
  35. 0 7
      test/functional-tests/custom-code-helpers/debug-protection/templates/workers/evaluation-worker.js
  36. 180 0
      test/functional-tests/custom-code-helpers/self-defending/templates/SelfDefendingTemplate.spec.ts
  37. 3 0
      test/functional-tests/custom-code-helpers/self-defending/templates/fixtures/input.js
  38. 0 1
      test/functional-tests/javascript-obfuscator/JavaScriptObfuscator.spec.ts
  39. 35 0
      test/helpers/evaluateInWorker.ts
  40. 7 0
      test/helpers/workers/evaluation-worker.js
  41. 1 0
      test/index.spec.ts
  42. 120 1
      test/runtime-tests/JavaScriptObfuscatorRuntime.spec.ts
  43. 77 0
      test/runtime-tests/fixtures/webpack-bootstrap.js
  44. 7 7
      test/unit-tests/generators/identifier-names-generators/DictionarylIdentifierNamesGenerator.spec.ts
  45. 2 2
      test/unit-tests/generators/identifier-names-generators/HexadecimalIdentifierNamesGenerator.spec.ts
  46. 11 11
      test/unit-tests/generators/identifier-names-generators/MangledlIdentifierNamesGenerator.spec.ts

+ 2 - 2
CHANGELOG.md

@@ -3,10 +3,10 @@ Change Log
 v0.25.0
 ---
 * Improved `mangled` identifier names generator logic
-* Fixed conflicts between generated names and names from untouched identifiers from source code. Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/550. Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/549
+* Improved `selfDefending` helper logic
+* Fixed a bunch of conflicts between generated identifier names. Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/550. Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/549
 * Prevented transformation of object keys in sequence expression that has `super` call
 
-
 v0.24.6
 ---
 * Fixed support of exponentiation operator. Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/534

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


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


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


+ 3 - 3
src/container/modules/custom-code-helpers/CustomCodeHelpersModule.ts

@@ -16,7 +16,7 @@ import { DomainLockCustomCodeHelperGroup } from '../../../custom-code-helpers/do
 import { SelfDefendingCodeHelperGroup } from '../../../custom-code-helpers/self-defending/group/SelfDefendingCodeHelperGroup';
 import { StringArrayCodeHelperGroup } from '../../../custom-code-helpers/string-array/group/StringArrayCodeHelperGroup';
 
-import { ConsoleOutputDisableExpressionCodeHelper } from '../../../custom-code-helpers/console-output/ConsoleOutputDisableExpressionCodeHelper';
+import { ConsoleOutputDisableCodeHelper } from '../../../custom-code-helpers/console-output/ConsoleOutputDisableCodeHelper';
 import { CustomCodeHelperFormatter } from '../../../custom-code-helpers/CustomCodeHelperFormatter';
 import { CustomCodeHelperObfuscator } from '../../../custom-code-helpers/CustomCodeHelperObfuscator';
 import { DebugProtectionFunctionCallCodeHelper } from '../../../custom-code-helpers/debug-protection/DebugProtectionFunctionCallCodeHelper';
@@ -32,8 +32,8 @@ import { StringArrayRotateFunctionCodeHelper } from '../../../custom-code-helper
 export const customCodeHelpersModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
     // custom code helpers
     bind<ICustomCodeHelper>(ServiceIdentifiers.ICustomCodeHelper)
-        .to(ConsoleOutputDisableExpressionCodeHelper)
-        .whenTargetNamed(CustomCodeHelper.ConsoleOutputDisableExpression);
+        .to(ConsoleOutputDisableCodeHelper)
+        .whenTargetNamed(CustomCodeHelper.ConsoleOutputDisable);
 
     bind<ICustomCodeHelper>(ServiceIdentifiers.ICustomCodeHelper)
         .to(DebugProtectionFunctionCallCodeHelper)

+ 5 - 5
src/custom-code-helpers/calls-controller/CallsControllerFunctionCodeHelper.ts

@@ -13,7 +13,7 @@ import { ObfuscationEvent } from '../../enums/event-emitters/ObfuscationEvent';
 
 import { initializable } from '../../decorators/Initializable';
 
-import { SingleNodeCallControllerTemplate } from '../common/templates/SingleNodeCallControllerTemplate';
+import { SingleCallControllerTemplate } from '../common/templates/SingleCallControllerTemplate';
 
 import { AbstractCustomCodeHelper } from '../AbstractCustomCodeHelper';
 import { NodeUtils } from '../../node/NodeUtils';
@@ -79,14 +79,14 @@ export class CallsControllerFunctionCodeHelper extends AbstractCustomCodeHelper
     protected getCodeHelperTemplate (): string {
         if (this.appendEvent === ObfuscationEvent.AfterObfuscation) {
             return this.customCodeHelperObfuscator.obfuscateTemplate(
-                this.customCodeHelperFormatter.formatTemplate(SingleNodeCallControllerTemplate(), {
-                    singleNodeCallControllerFunctionName: this.callsControllerFunctionName
+                this.customCodeHelperFormatter.formatTemplate(SingleCallControllerTemplate(), {
+                    callControllerFunctionName: this.callsControllerFunctionName
                 })
             );
         }
 
-        return this.customCodeHelperFormatter.formatTemplate(SingleNodeCallControllerTemplate(), {
-            singleNodeCallControllerFunctionName: this.callsControllerFunctionName
+        return this.customCodeHelperFormatter.formatTemplate(SingleCallControllerTemplate(), {
+            callControllerFunctionName: this.callsControllerFunctionName
         });
     }
 }

+ 2 - 2
src/custom-code-helpers/common/templates/SingleNodeCallControllerTemplate.ts → src/custom-code-helpers/common/templates/SingleCallControllerTemplate.ts

@@ -1,9 +1,9 @@
 /**
  * @returns {string}
  */
-export function SingleNodeCallControllerTemplate (): string {
+export function SingleCallControllerTemplate (): string {
     return `
-        const {singleNodeCallControllerFunctionName} = (function(){
+        const {callControllerFunctionName} = (function(){
             let firstCall = true;
             
             return function (context, fn){

+ 13 - 5
src/custom-code-helpers/console-output/ConsoleOutputDisableExpressionCodeHelper.ts → src/custom-code-helpers/console-output/ConsoleOutputDisableCodeHelper.ts

@@ -20,13 +20,19 @@ import { AbstractCustomCodeHelper } from '../AbstractCustomCodeHelper';
 import { NodeUtils } from '../../node/NodeUtils';
 
 @injectable()
-export class ConsoleOutputDisableExpressionCodeHelper extends AbstractCustomCodeHelper {
+export class ConsoleOutputDisableCodeHelper extends AbstractCustomCodeHelper {
     /**
      * @type {string}
      */
     @initializable()
     private callsControllerFunctionName!: string;
 
+    /**
+     * @type {string}
+     */
+    @initializable()
+    private consoleOutputDisableFunctionName!: string;
+
     /**
      * @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
      * @param {ICustomCodeHelperFormatter} customCodeHelperFormatter
@@ -53,9 +59,11 @@ export class ConsoleOutputDisableExpressionCodeHelper extends AbstractCustomCode
 
     /**
      * @param {string} callsControllerFunctionName
+     * @param {StaticRange} consoleOutputDisableFunctionName
      */
-    public initialize (callsControllerFunctionName: string): void {
+    public initialize (callsControllerFunctionName: string, consoleOutputDisableFunctionName: string): void {
         this.callsControllerFunctionName = callsControllerFunctionName;
+        this.consoleOutputDisableFunctionName = consoleOutputDisableFunctionName;
     }
 
     /**
@@ -75,9 +83,9 @@ export class ConsoleOutputDisableExpressionCodeHelper extends AbstractCustomCode
             : GlobalVariableNoEvalTemplate();
 
         return this.customCodeHelperFormatter.formatTemplate(ConsoleOutputDisableExpressionTemplate(), {
-            consoleLogDisableFunctionName: this.identifierNamesGenerator.generate(),
-            globalVariableTemplate,
-            singleNodeCallControllerFunctionName: this.callsControllerFunctionName
+            callControllerFunctionName: this.callsControllerFunctionName,
+            consoleLogDisableFunctionName: this.consoleOutputDisableFunctionName,
+            globalVariableTemplate
         });
     }
 }

+ 49 - 27
src/custom-code-helpers/console-output/group/ConsoleOutputCodeHelperGroup.ts

@@ -4,6 +4,7 @@ import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 import { TCustomCodeHelperFactory } from '../../../types/container/custom-code-helpers/TCustomCodeHelperFactory';
 import { TIdentifierNamesGeneratorFactory } from '../../../types/container/generators/TIdentifierNamesGeneratorFactory';
 import { TInitialData } from '../../../types/TInitialData';
+import { TNodeWithLexicalScope } from '../../../types/node/TNodeWithLexicalScope';
 import { TNodeWithStatements } from '../../../types/node/TNodeWithStatements';
 
 import { ICustomCodeHelper } from '../../../interfaces/custom-code-helpers/ICustomCodeHelper';
@@ -17,9 +18,11 @@ import { CustomCodeHelper } from '../../../enums/custom-code-helpers/CustomCodeH
 import { ObfuscationEvent } from '../../../enums/event-emitters/ObfuscationEvent';
 
 import { AbstractCustomCodeHelperGroup } from '../../AbstractCustomCodeHelperGroup';
-import { ConsoleOutputDisableExpressionCodeHelper } from '../ConsoleOutputDisableExpressionCodeHelper';
-import { NodeAppender } from '../../../node/NodeAppender';
 import { CallsControllerFunctionCodeHelper } from '../../calls-controller/CallsControllerFunctionCodeHelper';
+import { ConsoleOutputDisableCodeHelper } from '../ConsoleOutputDisableCodeHelper';
+import { NodeAppender } from '../../../node/NodeAppender';
+import { NodeLexicalScopeUtils } from '../../../node/NodeLexicalScopeUtils';
+import { NodeGuards } from '../../../node/NodeGuards';
 
 @injectable()
 export class ConsoleOutputCodeHelperGroup extends AbstractCustomCodeHelperGroup {
@@ -62,26 +65,50 @@ export class ConsoleOutputCodeHelperGroup extends AbstractCustomCodeHelperGroup
      * @param {ICallsGraphData[]} callsGraphData
      */
     public appendNodes (nodeWithStatements: TNodeWithStatements, callsGraphData: ICallsGraphData[]): void {
+        if (!this.options.disableConsoleOutput) {
+            return;
+        }
+
         const randomCallsGraphIndex: number = this.getRandomCallsGraphIndex(callsGraphData.length);
 
+        const consoleOutputDisableHostNode: TNodeWithStatements = callsGraphData.length
+            ? NodeAppender.getOptimalBlockScope(callsGraphData, randomCallsGraphIndex)
+            : nodeWithStatements;
+        const callsControllerHostNode: TNodeWithStatements = callsGraphData.length
+            ? NodeAppender.getOptimalBlockScope(callsGraphData, randomCallsGraphIndex, 1)
+            : nodeWithStatements;
+
+        const consoleOutputDisableLexicalScopeNode: TNodeWithLexicalScope | null = NodeLexicalScopeUtils
+            .getLexicalScope(consoleOutputDisableHostNode) ?? null;
+
+        const consoleOutputDisableFunctionName: string = consoleOutputDisableLexicalScopeNode
+            && NodeGuards.isProgramNode(consoleOutputDisableLexicalScopeNode)
+            ? this.identifierNamesGenerator.generate(consoleOutputDisableLexicalScopeNode)
+            : this.randomGenerator.getRandomString(5);
+        const callsControllerFunctionName: string = consoleOutputDisableLexicalScopeNode
+            && NodeGuards.isProgramNode(consoleOutputDisableLexicalScopeNode)
+            ? this.identifierNamesGenerator.generate(consoleOutputDisableLexicalScopeNode)
+            : this.randomGenerator.getRandomString(5);
+
         // consoleOutputDisableExpression helper nodes append
-        this.appendCustomNodeIfExist(CustomCodeHelper.ConsoleOutputDisableExpression, (customCodeHelper: ICustomCodeHelper) => {
-            NodeAppender.appendToOptimalBlockScope(
-                callsGraphData,
-                nodeWithStatements,
-                customCodeHelper.getNode(),
-                randomCallsGraphIndex
-            );
-        });
+        this.appendCustomNodeIfExist(
+            CustomCodeHelper.ConsoleOutputDisable,
+            (customCodeHelper: ICustomCodeHelper<TInitialData<ConsoleOutputDisableCodeHelper>>) => {
+                customCodeHelper.initialize(callsControllerFunctionName, consoleOutputDisableFunctionName);
 
-        // nodeCallsControllerFunction helper nodes append
-        this.appendCustomNodeIfExist(CustomCodeHelper.CallsControllerFunction, (customCodeHelper: ICustomCodeHelper) => {
-            const targetNodeWithStatements: TNodeWithStatements = callsGraphData.length
-                ? NodeAppender.getOptimalBlockScope(callsGraphData, randomCallsGraphIndex, 1)
-                : nodeWithStatements;
+                NodeAppender.prepend(consoleOutputDisableHostNode, customCodeHelper.getNode());
+            }
+        );
 
-            NodeAppender.prepend(targetNodeWithStatements, customCodeHelper.getNode());
-        });
+        // nodeCallsControllerFunction helper nodes append
+        this.appendCustomNodeIfExist(
+            CustomCodeHelper.CallsControllerFunction,
+            (customCodeHelper: ICustomCodeHelper<TInitialData<CallsControllerFunctionCodeHelper>>) => {
+                customCodeHelper.initialize(this.appendEvent, callsControllerFunctionName);
+
+                NodeAppender.prepend(callsControllerHostNode, customCodeHelper.getNode());
+            }
+        );
     }
 
     public initialize (): void {
@@ -91,17 +118,12 @@ export class ConsoleOutputCodeHelperGroup extends AbstractCustomCodeHelperGroup
             return;
         }
 
-        const callsControllerFunctionName: string = this.identifierNamesGenerator.generate();
-
-        const consoleOutputDisableExpressionCodeHelper: ICustomCodeHelper<TInitialData<ConsoleOutputDisableExpressionCodeHelper>> =
-            this.customCodeHelperFactory(CustomCodeHelper.ConsoleOutputDisableExpression);
-        const nodeCallsControllerFunctionCodeHelper: ICustomCodeHelper<TInitialData<CallsControllerFunctionCodeHelper>> =
+        const consoleOutputDisableExpressionCodeHelper: ICustomCodeHelper<TInitialData<ConsoleOutputDisableCodeHelper>> =
+            this.customCodeHelperFactory(CustomCodeHelper.ConsoleOutputDisable);
+        const callsControllerFunctionCodeHelper: ICustomCodeHelper<TInitialData<CallsControllerFunctionCodeHelper>> =
             this.customCodeHelperFactory(CustomCodeHelper.CallsControllerFunction);
 
-        consoleOutputDisableExpressionCodeHelper.initialize(callsControllerFunctionName);
-        nodeCallsControllerFunctionCodeHelper.initialize(this.appendEvent, callsControllerFunctionName);
-
-        this.customCodeHelpers.set(CustomCodeHelper.ConsoleOutputDisableExpression, consoleOutputDisableExpressionCodeHelper);
-        this.customCodeHelpers.set(CustomCodeHelper.CallsControllerFunction, nodeCallsControllerFunctionCodeHelper);
+        this.customCodeHelpers.set(CustomCodeHelper.ConsoleOutputDisable, consoleOutputDisableExpressionCodeHelper);
+        this.customCodeHelpers.set(CustomCodeHelper.CallsControllerFunction, callsControllerFunctionCodeHelper);
     }
 }

+ 1 - 1
src/custom-code-helpers/console-output/templates/ConsoleOutputDisableExpressionTemplate.ts

@@ -3,7 +3,7 @@
  */
 export function ConsoleOutputDisableExpressionTemplate (): string {
     return `
-        const {consoleLogDisableFunctionName} = {singleNodeCallControllerFunctionName}(this, function () {
+        const {consoleLogDisableFunctionName} = {callControllerFunctionName}(this, function () {
             const func = function () {};
             
             {globalVariableTemplate}

+ 1 - 1
src/custom-code-helpers/debug-protection/DebugProtectionFunctionCallCodeHelper.ts

@@ -77,7 +77,7 @@ export class DebugProtectionFunctionCallCodeHelper extends AbstractCustomCodeHel
     protected getCodeHelperTemplate (): string {
         return this.customCodeHelperFormatter.formatTemplate(DebugProtectionFunctionCallTemplate(), {
             debugProtectionFunctionName: this.debugProtectionFunctionName,
-            singleNodeCallControllerFunctionName: this.callsControllerFunctionName
+            callControllerFunctionName: this.callsControllerFunctionName
         });
     }
 }

+ 67 - 39
src/custom-code-helpers/debug-protection/group/DebugProtectionCodeHelperGroup.ts

@@ -4,6 +4,7 @@ import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 import { TCustomCodeHelperFactory } from '../../../types/container/custom-code-helpers/TCustomCodeHelperFactory';
 import { TIdentifierNamesGeneratorFactory } from '../../../types/container/generators/TIdentifierNamesGeneratorFactory';
 import { TInitialData } from '../../../types/TInitialData';
+import { TNodeWithLexicalScope } from '../../../types/node/TNodeWithLexicalScope';
 import { TNodeWithStatements } from '../../../types/node/TNodeWithStatements';
 
 import { ICustomCodeHelper } from '../../../interfaces/custom-code-helpers/ICustomCodeHelper';
@@ -17,12 +18,13 @@ import { CustomCodeHelper } from '../../../enums/custom-code-helpers/CustomCodeH
 import { ObfuscationEvent } from '../../../enums/event-emitters/ObfuscationEvent';
 
 import { AbstractCustomCodeHelperGroup } from '../../AbstractCustomCodeHelperGroup';
+import { CallsControllerFunctionCodeHelper } from '../../calls-controller/CallsControllerFunctionCodeHelper';
 import { DebugProtectionFunctionCodeHelper } from '../DebugProtectionFunctionCodeHelper';
 import { DebugProtectionFunctionCallCodeHelper } from '../DebugProtectionFunctionCallCodeHelper';
 import { DebugProtectionFunctionIntervalCodeHelper } from '../DebugProtectionFunctionIntervalCodeHelper';
 import { NodeAppender } from '../../../node/NodeAppender';
-import { CallsControllerFunctionCodeHelper } from '../../calls-controller/CallsControllerFunctionCodeHelper';
 import { NodeGuards } from '../../../node/NodeGuards';
+import { NodeLexicalScopeUtils } from '../../../node/NodeLexicalScopeUtils';
 
 @injectable()
 export class DebugProtectionCodeHelperGroup extends AbstractCustomCodeHelperGroup {
@@ -65,41 +67,75 @@ export class DebugProtectionCodeHelperGroup extends AbstractCustomCodeHelperGrou
      * @param {ICallsGraphData[]} callsGraphData
      */
     public appendNodes (nodeWithStatements: TNodeWithStatements, callsGraphData: ICallsGraphData[]): void {
+        if (!this.options.debugProtection) {
+            return;
+        }
+
         const randomCallsGraphIndex: number = this.getRandomCallsGraphIndex(callsGraphData.length);
 
+        const debugProtectionFunctionCallHostNode: TNodeWithStatements = callsGraphData.length
+            ? NodeAppender.getOptimalBlockScope(callsGraphData, randomCallsGraphIndex)
+            : nodeWithStatements;
+        const callsControllerHostNode: TNodeWithStatements = callsGraphData.length
+            ? NodeAppender.getOptimalBlockScope(callsGraphData, randomCallsGraphIndex, 1)
+            : nodeWithStatements;
+
+        const debugProtectionFunctionCallScopeNode: TNodeWithLexicalScope | null = NodeLexicalScopeUtils
+            .getLexicalScope(debugProtectionFunctionCallHostNode) ?? null;
+
+        const debugProtectionFunctionName: string = debugProtectionFunctionCallScopeNode
+            && NodeGuards.isProgramNode(debugProtectionFunctionCallScopeNode)
+            ? this.identifierNamesGenerator.generate(debugProtectionFunctionCallScopeNode)
+            : this.randomGenerator.getRandomString(5);
+        const callsControllerFunctionName: string = debugProtectionFunctionCallScopeNode
+            && NodeGuards.isProgramNode(debugProtectionFunctionCallScopeNode)
+            ? this.identifierNamesGenerator.generate(debugProtectionFunctionCallScopeNode)
+            : this.randomGenerator.getRandomString(5);
+
         // debugProtectionFunctionCall helper nodes append
-        this.appendCustomNodeIfExist(CustomCodeHelper.DebugProtectionFunctionCall, (customCodeHelper: ICustomCodeHelper) => {
-            NodeAppender.appendToOptimalBlockScope(
-                callsGraphData,
-                nodeWithStatements,
-                customCodeHelper.getNode(),
-                randomCallsGraphIndex
-            );
-        });
+        this.appendCustomNodeIfExist(
+            CustomCodeHelper.DebugProtectionFunctionCall,
+            (customCodeHelper: ICustomCodeHelper<TInitialData<DebugProtectionFunctionCallCodeHelper>>) => {
+                customCodeHelper.initialize(debugProtectionFunctionName, callsControllerFunctionName);
+
+                NodeAppender.prepend(debugProtectionFunctionCallHostNode, customCodeHelper.getNode());
+            }
+        );
+
+        // nodeCallsControllerFunction helper nodes append
+        this.appendCustomNodeIfExist(
+            CustomCodeHelper.CallsControllerFunction,
+            (customCodeHelper: ICustomCodeHelper<TInitialData<CallsControllerFunctionCodeHelper>>) => {
+                customCodeHelper.initialize(this.appendEvent, callsControllerFunctionName);
+
+                NodeAppender.prepend(callsControllerHostNode, customCodeHelper.getNode());
+            }
+        );
 
         // debugProtectionFunction helper nodes append
-        this.appendCustomNodeIfExist(CustomCodeHelper.DebugProtectionFunction, (customCodeHelper: ICustomCodeHelper) => {
-            NodeAppender.append(nodeWithStatements, customCodeHelper.getNode());
-        });
+        this.appendCustomNodeIfExist(
+            CustomCodeHelper.DebugProtectionFunction,
+                (customCodeHelper: ICustomCodeHelper<TInitialData<DebugProtectionFunctionCodeHelper>>) => {
+                customCodeHelper.initialize(debugProtectionFunctionName);
+
+                NodeAppender.append(nodeWithStatements, customCodeHelper.getNode());
+            }
+        );
 
         // debugProtectionFunctionInterval helper nodes append
-        this.appendCustomNodeIfExist(CustomCodeHelper.DebugProtectionFunctionInterval, (customCodeHelper: ICustomCodeHelper) => {
-            const programBodyLength: number = NodeGuards.isSwitchCaseNode(nodeWithStatements)
-                ? nodeWithStatements.consequent.length
-                : nodeWithStatements.body.length;
-            const randomIndex: number = this.randomGenerator.getRandomInteger(0, programBodyLength);
-
-            NodeAppender.insertAtIndex(nodeWithStatements, customCodeHelper.getNode(), randomIndex);
-        });
-
-        // nodeCallsControllerFunctionNode append
-        this.appendCustomNodeIfExist(CustomCodeHelper.CallsControllerFunction, (customCodeHelper: ICustomCodeHelper) => {
-            const targetNodeWithStatements: TNodeWithStatements = callsGraphData.length
-                ? NodeAppender.getOptimalBlockScope(callsGraphData, randomCallsGraphIndex, 1)
-                : nodeWithStatements;
-
-            NodeAppender.prepend(targetNodeWithStatements, customCodeHelper.getNode());
-        });
+        this.appendCustomNodeIfExist(
+            CustomCodeHelper.DebugProtectionFunctionInterval,
+            (customCodeHelper: ICustomCodeHelper<TInitialData<DebugProtectionFunctionIntervalCodeHelper>>) => {
+                const programBodyLength: number = NodeGuards.isSwitchCaseNode(nodeWithStatements)
+                    ? nodeWithStatements.consequent.length
+                    : nodeWithStatements.body.length;
+                const randomIndex: number = this.randomGenerator.getRandomInteger(0, programBodyLength);
+
+                customCodeHelper.initialize(debugProtectionFunctionName);
+
+                NodeAppender.insertAtIndex(nodeWithStatements, customCodeHelper.getNode(), randomIndex);
+            }
+        );
     }
 
     public initialize (): void {
@@ -109,23 +145,15 @@ export class DebugProtectionCodeHelperGroup extends AbstractCustomCodeHelperGrou
             return;
         }
 
-        const debugProtectionFunctionName: string = this.identifierNamesGenerator.generate();
-        const callsControllerFunctionName: string = this.identifierNamesGenerator.generate();
-
         const debugProtectionFunctionCodeHelper: ICustomCodeHelper<TInitialData<DebugProtectionFunctionCodeHelper>> =
             this.customCodeHelperFactory(CustomCodeHelper.DebugProtectionFunction);
         const debugProtectionFunctionCallCodeHelper: ICustomCodeHelper<TInitialData<DebugProtectionFunctionCallCodeHelper>> =
             this.customCodeHelperFactory(CustomCodeHelper.DebugProtectionFunctionCall);
         const debugProtectionFunctionIntervalCodeHelper: ICustomCodeHelper<TInitialData<DebugProtectionFunctionIntervalCodeHelper>> =
             this.customCodeHelperFactory(CustomCodeHelper.DebugProtectionFunctionInterval);
-        const nodeCallsControllerFunctionCodeHelper: ICustomCodeHelper<TInitialData<CallsControllerFunctionCodeHelper>> =
+        const callsControllerFunctionCodeHelper: ICustomCodeHelper<TInitialData<CallsControllerFunctionCodeHelper>> =
             this.customCodeHelperFactory(CustomCodeHelper.CallsControllerFunction);
 
-        debugProtectionFunctionCodeHelper.initialize(debugProtectionFunctionName);
-        debugProtectionFunctionCallCodeHelper.initialize(debugProtectionFunctionName, callsControllerFunctionName);
-        debugProtectionFunctionIntervalCodeHelper.initialize(debugProtectionFunctionName);
-        nodeCallsControllerFunctionCodeHelper.initialize(this.appendEvent, callsControllerFunctionName);
-
         this.customCodeHelpers.set(CustomCodeHelper.DebugProtectionFunction, debugProtectionFunctionCodeHelper);
         this.customCodeHelpers.set(CustomCodeHelper.DebugProtectionFunctionCall, debugProtectionFunctionCallCodeHelper);
 
@@ -133,6 +161,6 @@ export class DebugProtectionCodeHelperGroup extends AbstractCustomCodeHelperGrou
             this.customCodeHelpers.set(CustomCodeHelper.DebugProtectionFunctionInterval, debugProtectionFunctionIntervalCodeHelper);
         }
 
-        this.customCodeHelpers.set(CustomCodeHelper.CallsControllerFunction, nodeCallsControllerFunctionCodeHelper);
+        this.customCodeHelpers.set(CustomCodeHelper.CallsControllerFunction, callsControllerFunctionCodeHelper);
     }
 }

+ 1 - 1
src/custom-code-helpers/debug-protection/templates/debug-protection-function-call/DebugProtectionFunctionCallTemplate.ts

@@ -4,7 +4,7 @@
 export function DebugProtectionFunctionCallTemplate (): string {
     return `
         (function () {
-            {singleNodeCallControllerFunctionName}(
+            {callControllerFunctionName}(
                 this,
                 function () {
                     const regExp1 = new RegExp('function *\\\\( *\\\\)');

+ 13 - 5
src/custom-code-helpers/domain-lock/DomainLockCodeHelper.ts

@@ -26,13 +26,19 @@ export class DomainLockCodeHelper extends AbstractCustomCodeHelper {
      * @type {string}
      */
     @initializable()
-    protected callsControllerFunctionName!: string;
+    private callsControllerFunctionName!: string;
 
     /**
      * @type {ICryptUtils}
      */
     private readonly cryptUtils: ICryptUtils;
 
+    /**
+     * @type {string}
+     */
+    @initializable()
+    private domainLockFunctionName!: string;
+
     /**
      * @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
      * @param {ICustomCodeHelperFormatter} customCodeHelperFormatter
@@ -63,9 +69,11 @@ export class DomainLockCodeHelper extends AbstractCustomCodeHelper {
 
     /**
      * @param {string} callsControllerFunctionName
+     * @param {string} domainLockFunctionName
      */
-    public initialize (callsControllerFunctionName: string): void {
+    public initialize (callsControllerFunctionName: string, domainLockFunctionName: string): void {
         this.callsControllerFunctionName = callsControllerFunctionName;
+        this.domainLockFunctionName = domainLockFunctionName;
     }
 
     /**
@@ -90,11 +98,11 @@ export class DomainLockCodeHelper extends AbstractCustomCodeHelper {
             : GlobalVariableNoEvalTemplate();
 
         return this.customCodeHelperFormatter.formatTemplate(DomainLockTemplate(), {
-            domainLockFunctionName: this.identifierNamesGenerator.generate(),
+            callControllerFunctionName: this.callsControllerFunctionName,
+            domainLockFunctionName: this.domainLockFunctionName,
             diff,
             domains: hiddenDomainsString,
-            globalVariableTemplate,
-            singleNodeCallControllerFunctionName: this.callsControllerFunctionName
+            globalVariableTemplate
         });
     }
 }

+ 45 - 23
src/custom-code-helpers/domain-lock/group/DomainLockCustomCodeHelperGroup.ts

@@ -4,6 +4,7 @@ import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 import { TCustomCodeHelperFactory } from '../../../types/container/custom-code-helpers/TCustomCodeHelperFactory';
 import { TIdentifierNamesGeneratorFactory } from '../../../types/container/generators/TIdentifierNamesGeneratorFactory';
 import { TInitialData } from '../../../types/TInitialData';
+import { TNodeWithLexicalScope } from '../../../types/node/TNodeWithLexicalScope';
 import { TNodeWithStatements } from '../../../types/node/TNodeWithStatements';
 
 import { ICustomCodeHelper } from '../../../interfaces/custom-code-helpers/ICustomCodeHelper';
@@ -17,9 +18,11 @@ import { CustomCodeHelper } from '../../../enums/custom-code-helpers/CustomCodeH
 import { ObfuscationEvent } from '../../../enums/event-emitters/ObfuscationEvent';
 
 import { AbstractCustomCodeHelperGroup } from '../../AbstractCustomCodeHelperGroup';
+import { CallsControllerFunctionCodeHelper } from '../../calls-controller/CallsControllerFunctionCodeHelper';
 import { DomainLockCodeHelper } from '../DomainLockCodeHelper';
 import { NodeAppender } from '../../../node/NodeAppender';
-import { CallsControllerFunctionCodeHelper } from '../../calls-controller/CallsControllerFunctionCodeHelper';
+import { NodeLexicalScopeUtils } from '../../../node/NodeLexicalScopeUtils';
+import { NodeGuards } from '../../../node/NodeGuards';
 
 @injectable()
 export class DomainLockCustomCodeHelperGroup extends AbstractCustomCodeHelperGroup {
@@ -62,26 +65,50 @@ export class DomainLockCustomCodeHelperGroup extends AbstractCustomCodeHelperGro
      * @param {ICallsGraphData[]} callsGraphData
      */
     public appendNodes (nodeWithStatements: TNodeWithStatements, callsGraphData: ICallsGraphData[]): void {
+        if (!this.options.domainLock.length) {
+            return;
+        }
+
         const randomCallsGraphIndex: number = this.getRandomCallsGraphIndex(callsGraphData.length);
 
+        const domainLockFunctionHostNode: TNodeWithStatements = callsGraphData.length
+            ? NodeAppender.getOptimalBlockScope(callsGraphData, randomCallsGraphIndex)
+            : nodeWithStatements;
+        const callsControllerHostNode: TNodeWithStatements = callsGraphData.length
+            ? NodeAppender.getOptimalBlockScope(callsGraphData, randomCallsGraphIndex, 1)
+            : nodeWithStatements;
+
+        const domainLockFunctionLexicalScopeNode: TNodeWithLexicalScope | null = NodeLexicalScopeUtils
+            .getLexicalScope(domainLockFunctionHostNode) ?? null;
+
+        const domainLockFunctionName: string = domainLockFunctionLexicalScopeNode
+            && NodeGuards.isProgramNode(domainLockFunctionLexicalScopeNode)
+            ? this.identifierNamesGenerator.generate(domainLockFunctionLexicalScopeNode)
+            : this.randomGenerator.getRandomString(5);
+        const callsControllerFunctionName: string = domainLockFunctionLexicalScopeNode
+            && NodeGuards.isProgramNode(domainLockFunctionLexicalScopeNode)
+            ? this.identifierNamesGenerator.generate(domainLockFunctionLexicalScopeNode)
+            : this.randomGenerator.getRandomString(5);
+
         // domainLock helper nodes append
-        this.appendCustomNodeIfExist(CustomCodeHelper.DomainLock, (customCodeHelper: ICustomCodeHelper) => {
-            NodeAppender.appendToOptimalBlockScope(
-                callsGraphData,
-                nodeWithStatements,
-                customCodeHelper.getNode(),
-                randomCallsGraphIndex
-            );
-        });
+        this.appendCustomNodeIfExist(
+            CustomCodeHelper.DomainLock,
+            (customCodeHelper: ICustomCodeHelper<TInitialData<DomainLockCodeHelper>>) => {
+                customCodeHelper.initialize(callsControllerFunctionName, domainLockFunctionName);
 
-        // nodeCallsControllerFunction helper nodes append
-        this.appendCustomNodeIfExist(CustomCodeHelper.CallsControllerFunction, (customCodeHelper: ICustomCodeHelper) => {
-            const targetNodeWithStatements: TNodeWithStatements = callsGraphData.length
-                ? NodeAppender.getOptimalBlockScope(callsGraphData, randomCallsGraphIndex, 1)
-                : nodeWithStatements;
+                NodeAppender.prepend(domainLockFunctionHostNode, customCodeHelper.getNode());
+            }
+        );
 
-            NodeAppender.prepend(targetNodeWithStatements, customCodeHelper.getNode());
-        });
+        // nodeCallsControllerFunction helper nodes append
+        this.appendCustomNodeIfExist(
+            CustomCodeHelper.CallsControllerFunction,
+            (customCodeHelper: ICustomCodeHelper<TInitialData<CallsControllerFunctionCodeHelper>>) => {
+                customCodeHelper.initialize(this.appendEvent, callsControllerFunctionName);
+
+                NodeAppender.prepend(callsControllerHostNode, customCodeHelper.getNode());
+            }
+        );
     }
 
     public initialize (): void {
@@ -91,17 +118,12 @@ export class DomainLockCustomCodeHelperGroup extends AbstractCustomCodeHelperGro
             return;
         }
 
-        const callsControllerFunctionName: string = this.identifierNamesGenerator.generate();
-
         const domainLockCodeHelper: ICustomCodeHelper<TInitialData<DomainLockCodeHelper>> =
             this.customCodeHelperFactory(CustomCodeHelper.DomainLock);
-        const nodeCallsControllerFunctionCodeHelper: ICustomCodeHelper<TInitialData<CallsControllerFunctionCodeHelper>> =
+        const callsControllerFunctionCodeHelper: ICustomCodeHelper<TInitialData<CallsControllerFunctionCodeHelper>> =
             this.customCodeHelperFactory(CustomCodeHelper.CallsControllerFunction);
 
-        domainLockCodeHelper.initialize(callsControllerFunctionName);
-        nodeCallsControllerFunctionCodeHelper.initialize(this.appendEvent, callsControllerFunctionName);
-
         this.customCodeHelpers.set(CustomCodeHelper.DomainLock, domainLockCodeHelper);
-        this.customCodeHelpers.set(CustomCodeHelper.CallsControllerFunction, nodeCallsControllerFunctionCodeHelper);
+        this.customCodeHelpers.set(CustomCodeHelper.CallsControllerFunction, callsControllerFunctionCodeHelper);
     }
 }

+ 1 - 1
src/custom-code-helpers/domain-lock/templates/DomainLockTemplate.ts

@@ -3,7 +3,7 @@
  */
 export function DomainLockTemplate (): string {
     return `
-        const {domainLockFunctionName} = {singleNodeCallControllerFunctionName}(this, function () {
+        const {domainLockFunctionName} = {callControllerFunctionName}(this, function () {
             
             {globalVariableTemplate}
             

+ 13 - 10
src/custom-code-helpers/self-defending/SelfDefendingUnicodeCodeHelper.ts

@@ -30,6 +30,12 @@ export class SelfDefendingUnicodeCodeHelper extends AbstractCustomCodeHelper {
     @initializable()
     private callsControllerFunctionName!: string;
 
+    /**
+     * @type {string}
+     */
+    @initializable()
+    private selfDefendingFunctionName!: string;
+
     /**
      * @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
      * @param {ICustomCodeHelperFormatter} customCodeHelperFormatter
@@ -60,9 +66,11 @@ export class SelfDefendingUnicodeCodeHelper extends AbstractCustomCodeHelper {
 
     /**
      * @param {string} callsControllerFunctionName
+     * @param {string} selfDefendingFunctionName
      */
-    public initialize (callsControllerFunctionName: string): void {
+    public initialize (callsControllerFunctionName: string, selfDefendingFunctionName: string): void {
         this.callsControllerFunctionName = callsControllerFunctionName;
+        this.selfDefendingFunctionName = selfDefendingFunctionName;
     }
 
     /**
@@ -77,14 +85,9 @@ export class SelfDefendingUnicodeCodeHelper extends AbstractCustomCodeHelper {
      * @returns {string}
      */
     protected getCodeHelperTemplate (): string {
-        return this.customCodeHelperObfuscator.obfuscateTemplate(
-            this.customCodeHelperFormatter.formatTemplate(SelfDefendingTemplate(this.escapeSequenceEncoder), {
-                selfDefendingFunctionName: this.identifierNamesGenerator.generate(),
-                singleNodeCallControllerFunctionName: this.callsControllerFunctionName
-            }),
-            {
-                unicodeEscapeSequence: true
-            }
-        );
+        return this.customCodeHelperFormatter.formatTemplate(SelfDefendingTemplate(this.escapeSequenceEncoder), {
+            callControllerFunctionName: this.callsControllerFunctionName,
+            selfDefendingFunctionName: this.selfDefendingFunctionName
+        });
     }
 }

+ 43 - 24
src/custom-code-helpers/self-defending/group/SelfDefendingCodeHelperGroup.ts

@@ -4,6 +4,7 @@ import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
 import { TCustomCodeHelperFactory } from '../../../types/container/custom-code-helpers/TCustomCodeHelperFactory';
 import { TIdentifierNamesGeneratorFactory } from '../../../types/container/generators/TIdentifierNamesGeneratorFactory';
 import { TInitialData } from '../../../types/TInitialData';
+import { TNodeWithLexicalScope } from '../../../types/node/TNodeWithLexicalScope';
 import { TNodeWithStatements } from '../../../types/node/TNodeWithStatements';
 
 import { ICustomCodeHelper } from '../../../interfaces/custom-code-helpers/ICustomCodeHelper';
@@ -17,8 +18,9 @@ import { CustomCodeHelper } from '../../../enums/custom-code-helpers/CustomCodeH
 import { ObfuscationEvent } from '../../../enums/event-emitters/ObfuscationEvent';
 
 import { AbstractCustomCodeHelperGroup } from '../../AbstractCustomCodeHelperGroup';
-import { NodeAppender } from '../../../node/NodeAppender';
 import { CallsControllerFunctionCodeHelper } from '../../calls-controller/CallsControllerFunctionCodeHelper';
+import { NodeAppender } from '../../../node/NodeAppender';
+import { NodeLexicalScopeUtils } from '../../../node/NodeLexicalScopeUtils';
 import { SelfDefendingUnicodeCodeHelper } from '../SelfDefendingUnicodeCodeHelper';
 
 @injectable()
@@ -26,7 +28,7 @@ export class SelfDefendingCodeHelperGroup extends AbstractCustomCodeHelperGroup
     /**
      * @type {ObfuscationEvent}
      */
-    protected appendEvent: ObfuscationEvent = ObfuscationEvent.AfterObfuscation;
+    protected appendEvent: ObfuscationEvent = ObfuscationEvent.BeforeObfuscation;
 
     /**
      * @type {Map<CustomCodeHelper, ICustomCodeHelper>}
@@ -62,26 +64,48 @@ export class SelfDefendingCodeHelperGroup extends AbstractCustomCodeHelperGroup
      * @param {ICallsGraphData[]} callsGraphData
      */
     public appendNodes (nodeWithStatements: TNodeWithStatements, callsGraphData: ICallsGraphData[]): void {
+        if (!this.options.selfDefending) {
+            return;
+        }
+
         const randomCallsGraphIndex: number = this.getRandomCallsGraphIndex(callsGraphData.length);
 
+        const selfDefendingFunctionHostNode: TNodeWithStatements = callsGraphData.length
+            ? NodeAppender.getOptimalBlockScope(callsGraphData, randomCallsGraphIndex)
+            : nodeWithStatements;
+        const callsControllerHostNode: TNodeWithStatements = callsGraphData.length
+            ? NodeAppender.getOptimalBlockScope(callsGraphData, randomCallsGraphIndex, 1)
+            : nodeWithStatements;
+
+        const selfDefendingFunctionLexicalScopeNode: TNodeWithLexicalScope | null = NodeLexicalScopeUtils
+            .getLexicalScope(selfDefendingFunctionHostNode) ?? null;
+
+        const selfDefendingFunctionName: string = selfDefendingFunctionLexicalScopeNode
+            ? this.identifierNamesGenerator.generate(selfDefendingFunctionLexicalScopeNode)
+            : this.identifierNamesGenerator.generateForGlobalScope();
+        const callsControllerFunctionName: string = selfDefendingFunctionLexicalScopeNode
+            ? this.identifierNamesGenerator.generate(selfDefendingFunctionLexicalScopeNode)
+            : this.identifierNamesGenerator.generateForGlobalScope();
+
         // selfDefendingUnicode helper nodes append
-        this.appendCustomNodeIfExist(CustomCodeHelper.SelfDefendingUnicode, (customCodeHelper: ICustomCodeHelper) => {
-            NodeAppender.appendToOptimalBlockScope(
-                callsGraphData,
-                nodeWithStatements,
-                customCodeHelper.getNode(),
-                randomCallsGraphIndex
-            );
-        });
+        this.appendCustomNodeIfExist(
+            CustomCodeHelper.SelfDefendingUnicode,
+            (customCodeHelper: ICustomCodeHelper<TInitialData<SelfDefendingUnicodeCodeHelper>>) => {
+                customCodeHelper.initialize(callsControllerFunctionName, selfDefendingFunctionName);
 
-        // nodeCallsControllerFunction helper nodes append
-        this.appendCustomNodeIfExist(CustomCodeHelper.CallsControllerFunction, (customCodeHelper: ICustomCodeHelper) => {
-            const targetNodeWithStatements: TNodeWithStatements = callsGraphData.length
-                ? NodeAppender.getOptimalBlockScope(callsGraphData, randomCallsGraphIndex, 1)
-                : nodeWithStatements;
+                NodeAppender.prepend(selfDefendingFunctionHostNode, customCodeHelper.getNode());
+            }
+        );
 
-            NodeAppender.prepend(targetNodeWithStatements, customCodeHelper.getNode());
-        });
+        // nodeCallsControllerFunction helper nodes append
+        this.appendCustomNodeIfExist(
+            CustomCodeHelper.CallsControllerFunction,
+            (customCodeHelper: ICustomCodeHelper<TInitialData<CallsControllerFunctionCodeHelper>>) => {
+                customCodeHelper.initialize(this.appendEvent, callsControllerFunctionName);
+
+                NodeAppender.prepend(callsControllerHostNode, customCodeHelper.getNode());
+            }
+        );
     }
 
     public initialize (): void {
@@ -91,17 +115,12 @@ export class SelfDefendingCodeHelperGroup extends AbstractCustomCodeHelperGroup
             return;
         }
 
-        const callsControllerFunctionName: string = this.identifierNamesGenerator.generate();
-
         const selfDefendingUnicodeCodeHelper: ICustomCodeHelper<TInitialData<SelfDefendingUnicodeCodeHelper>> =
             this.customCodeHelperFactory(CustomCodeHelper.SelfDefendingUnicode);
-        const nodeCallsControllerFunctionCodeHelper: ICustomCodeHelper<TInitialData<CallsControllerFunctionCodeHelper>> =
+        const callsControllerFunctionCodeHelper: ICustomCodeHelper<TInitialData<CallsControllerFunctionCodeHelper>> =
             this.customCodeHelperFactory(CustomCodeHelper.CallsControllerFunction);
 
-        selfDefendingUnicodeCodeHelper.initialize(callsControllerFunctionName);
-        nodeCallsControllerFunctionCodeHelper.initialize(this.appendEvent, callsControllerFunctionName);
-
         this.customCodeHelpers.set(CustomCodeHelper.SelfDefendingUnicode, selfDefendingUnicodeCodeHelper);
-        this.customCodeHelpers.set(CustomCodeHelper.CallsControllerFunction, nodeCallsControllerFunctionCodeHelper);
+        this.customCodeHelpers.set(CustomCodeHelper.CallsControllerFunction, callsControllerFunctionCodeHelper);
     }
 }

+ 6 - 45
src/custom-code-helpers/self-defending/templates/SelfDefendingTemplate.ts

@@ -9,54 +9,15 @@ import { IEscapeSequenceEncoder } from '../../../interfaces/utils/IEscapeSequenc
  */
 export function SelfDefendingTemplate (escapeSequenceEncoder: IEscapeSequenceEncoder): string {
     return `
-        const {selfDefendingFunctionName} = {singleNodeCallControllerFunctionName}(this, function () {
-            const func1 = function(){return 'dev';},
-                func2 = function () {
-                    return 'window';
-                };
+        const {selfDefendingFunctionName} = {callControllerFunctionName}(this, function () {
+            const test = function () {
+                const regExp = new RegExp('^([^ ]+( +[^ ]+)+)+[^ ]}');
                 
-            const test1 = function () {
-                const regExp = new RegExp('${
-                    escapeSequenceEncoder.encode('\\w+ *\\(\\) *{\\w+ *[\'|"].+[\'|"];? *}', true)
-                }');
-                
-                return !regExp.test(func1.toString());
-            };
-            
-            const test2 = function () {
-                const regExp = new RegExp('${
-                    escapeSequenceEncoder.encode('(\\\\[x|u](\\w){2,4})+', true)
-                }');
-                
-                return regExp.test(func2.toString());
-            };
-            
-            const recursiveFunc1 = function (string) {
-                const i = ~-1 >> 1 + 255 % 0;
-                                
-                if (string.indexOf('i' === i)) {
-                    recursiveFunc2(string)
-                }
-            };
-            
-            const recursiveFunc2 = function (string) {
-                const i = ~-4 >> 1 + 255 % 0;
-                
-                if (string.indexOf((true+"")[3]) !== i) {
-                    recursiveFunc1(string)
-                }
+                return !regExp.test({selfDefendingFunctionName});
             };
             
-            if (!test1()) {
-                if (!test2()) {
-                    recursiveFunc1('indеxOf');
-                } else {
-                    recursiveFunc1('indexOf');
-                }
-            } else {
-                recursiveFunc1('indеxOf');
-            }
-        })
+            return test();
+        });
         
         {selfDefendingFunctionName}();
     `;

+ 2 - 2
src/custom-code-helpers/string-array/StringArrayRotateFunctionCodeHelper.ts

@@ -90,8 +90,8 @@ export class StringArrayRotateFunctionCodeHelper extends AbstractCustomCodeHelpe
      * @returns {string}
      */
     protected getCodeHelperTemplate (): string {
-        const timesName: string = this.identifierNamesGenerator.generate();
-        const whileFunctionName: string = this.identifierNamesGenerator.generate();
+        const timesName: string = this.identifierNamesGenerator.generateForGlobalScope();
+        const whileFunctionName: string = this.identifierNamesGenerator.generateForGlobalScope();
         const preservedNames: string[] = [this.stringArrayName];
 
         let code: string = '';

+ 18 - 9
src/custom-code-helpers/string-array/group/StringArrayCodeHelperGroup.ts

@@ -77,19 +77,28 @@ export class StringArrayCodeHelperGroup extends AbstractCustomCodeHelperGroup {
         }
 
         // stringArray helper nodes append
-        this.appendCustomNodeIfExist(CustomCodeHelper.StringArray, (customCodeHelper: ICustomCodeHelper) => {
-            NodeAppender.prepend(nodeWithStatements, customCodeHelper.getNode());
-        });
+        this.appendCustomNodeIfExist(
+            CustomCodeHelper.StringArray,
+            (customCodeHelper: ICustomCodeHelper<TInitialData<StringArrayCodeHelper>>) => {
+                NodeAppender.prepend(nodeWithStatements, customCodeHelper.getNode());
+            }
+        );
 
         // stringArrayCallsWrapper helper nodes append
-        this.appendCustomNodeIfExist(CustomCodeHelper.StringArrayCallsWrapper, (customCodeHelper: ICustomCodeHelper) => {
-            NodeAppender.insertAtIndex(nodeWithStatements, customCodeHelper.getNode(), 1);
-        });
+        this.appendCustomNodeIfExist(
+            CustomCodeHelper.StringArrayCallsWrapper,
+            (customCodeHelper: ICustomCodeHelper<TInitialData<StringArrayCallsWrapperCodeHelper>>) => {
+                NodeAppender.insertAtIndex(nodeWithStatements, customCodeHelper.getNode(), 1);
+            }
+        );
 
         // stringArrayRotateFunction helper nodes append
-        this.appendCustomNodeIfExist(CustomCodeHelper.StringArrayRotateFunction, (customCodeHelper: ICustomCodeHelper) => {
-            NodeAppender.insertAtIndex(nodeWithStatements, customCodeHelper.getNode(), 1);
-        });
+        this.appendCustomNodeIfExist(
+            CustomCodeHelper.StringArrayRotateFunction,
+            (customCodeHelper: ICustomCodeHelper<TInitialData<StringArrayRotateFunctionCodeHelper>>) => {
+                NodeAppender.insertAtIndex(nodeWithStatements, customCodeHelper.getNode(), 1);
+            }
+        );
     }
 
     public initialize (): void {

+ 1 - 1
src/custom-nodes/object-expression-keys-transformer-nodes/ObjectExpressionVariableDeclarationHostNode.ts

@@ -57,7 +57,7 @@ export class ObjectExpressionVariableDeclarationHostNode extends AbstractCustomN
      */
     protected getNodeStructure (): TStatement[] {
         const variableDeclarationName: string = NodeGuards.isProgramNode(this.lexicalScopeNode)
-            ? this.identifierNamesGenerator.generate()
+            ? this.identifierNamesGenerator.generateForGlobalScope()
             : this.identifierNamesGenerator.generateForLexicalScope(this.lexicalScopeNode);
 
         const structure: TStatement = NodeFactory.variableDeclarationNode(

+ 1 - 1
src/enums/custom-code-helpers/CustomCodeHelper.ts

@@ -1,6 +1,6 @@
 export enum CustomCodeHelper {
     CallsControllerFunction = 'CallsControllerFunction',
-    ConsoleOutputDisableExpression = 'ConsoleOutputDisableExpression',
+    ConsoleOutputDisable = 'ConsoleOutputDisable',
     DebugProtectionFunctionCall = 'DebugProtectionFunctionCall',
     DebugProtectionFunctionInterval = 'DebugProtectionFunctionInterval',
     DebugProtectionFunction = 'DebugProtectionFunction',

+ 14 - 1
src/generators/identifier-names-generators/AbstractIdentifierNamesGenerator.ts

@@ -7,6 +7,8 @@ import { IIdentifierNamesGenerator } from '../../interfaces/generators/identifie
 import { IOptions } from '../../interfaces/options/IOptions';
 import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
 
+import { NodeGuards } from '../../node/NodeGuards';
+
 @injectable()
 export abstract class AbstractIdentifierNamesGenerator implements IIdentifierNamesGenerator {
     /**
@@ -41,6 +43,17 @@ export abstract class AbstractIdentifierNamesGenerator implements IIdentifierNam
         this.options = options;
     }
 
+    /**
+     * @param {TNodeWithLexicalScope} lexicalScopeNode
+     * @param {number} nameLength
+     * @returns {string}
+     */
+    public generate (lexicalScopeNode: TNodeWithLexicalScope, nameLength?: number): string {
+        return NodeGuards.isProgramNode(lexicalScopeNode)
+            ? this.generateForGlobalScope()
+            : this.generateForLexicalScope(lexicalScopeNode);
+    }
+
     /**
      * @param {string} name
      */
@@ -112,7 +125,7 @@ export abstract class AbstractIdentifierNamesGenerator implements IIdentifierNam
      * @param {number} nameLength
      * @returns {string}
      */
-    public abstract generate (nameLength?: number): string;
+    public abstract generateForGlobalScope (nameLength?: number): string;
 
     /**
      * @param {TNodeWithLexicalScope} lexicalScopeNode

+ 1 - 1
src/generators/identifier-names-generators/DictionaryIdentifierNamesGenerator.ts

@@ -69,7 +69,7 @@ export class DictionaryIdentifierNamesGenerator extends AbstractIdentifierNamesG
         return null;
     }
 
-    public generate (): string {
+    public generateForGlobalScope (): string {
         const identifierName: string = this.generateNewDictionaryName();
 
         this.preserveName(identifierName);

+ 4 - 4
src/generators/identifier-names-generators/HexadecimalIdentifierNamesGenerator.ts

@@ -37,7 +37,7 @@ export class HexadecimalIdentifierNamesGenerator extends AbstractIdentifierNames
      * @param {number} nameLength
      * @returns {string}
      */
-    public generate (nameLength?: number): string {
+    public generateForGlobalScope (nameLength?: number): string {
         const rangeMinInteger: number = 10000;
         const rangeMaxInteger: number = 99_999_999;
         const randomInteger: number = this.randomGenerator.getRandomInteger(rangeMinInteger, rangeMaxInteger);
@@ -50,7 +50,7 @@ export class HexadecimalIdentifierNamesGenerator extends AbstractIdentifierNames
         const identifierName: string = `_${Utils.hexadecimalPrefix}${baseIdentifierName}`;
 
         if (this.randomVariableNameSet.has(identifierName)) {
-            return this.generate(nameLength);
+            return this.generateForGlobalScope(nameLength);
         }
 
         this.randomVariableNameSet.add(identifierName);
@@ -64,7 +64,7 @@ export class HexadecimalIdentifierNamesGenerator extends AbstractIdentifierNames
      * @returns {string}
      */
     public generateForLexicalScope (lexicalScopeNode: TNodeWithLexicalScope, nameLength?: number): string {
-        return this.generate(nameLength);
+        return this.generateForGlobalScope(nameLength);
     }
 
     /**
@@ -72,7 +72,7 @@ export class HexadecimalIdentifierNamesGenerator extends AbstractIdentifierNames
      * @returns {string}
      */
     public generateWithPrefix (nameLength?: number): string {
-        const identifierName: string = this.generate(nameLength);
+        const identifierName: string = this.generateForGlobalScope(nameLength);
 
         return `${this.options.identifiersPrefix}${identifierName}`.replace('__', '_');
     }

+ 1 - 1
src/generators/identifier-names-generators/MangledIdentifierNamesGenerator.ts

@@ -58,7 +58,7 @@ export class MangledIdentifierNamesGenerator extends AbstractIdentifierNamesGene
      * @param {number} nameLength
      * @returns {string}
      */
-    public generate (nameLength?: number): string {
+    public generateForGlobalScope (nameLength?: number): string {
         const identifierName: string = this.generateNewMangledName(this.previousMangledName);
 
         this.previousMangledName = identifierName;

+ 8 - 1
src/interfaces/generators/identifier-names-generators/IIdentifierNamesGenerator.ts

@@ -1,11 +1,18 @@
 import { TNodeWithLexicalScope } from '../../../types/node/TNodeWithLexicalScope';
 
 export interface IIdentifierNamesGenerator {
+    /**
+     * @param {TNodeWithLexicalScope} lexicalScopeNode
+     * @param {number} nameLength
+     * @returns {string}
+     */
+    generate (lexicalScopeNode: TNodeWithLexicalScope, nameLength?: number): string;
+
     /**
      * @param {number} nameLength
      * @returns {string}
      */
-    generate (nameLength?: number): string;
+    generateForGlobalScope (nameLength?: number): string;
 
     /**
      * @param {TNodeWithLexicalScope} lexicalScopeNode

+ 10 - 5
src/node-transformers/dead-code-injection-transformers/DeadCodeInjectionTransformer.ts

@@ -351,17 +351,22 @@ export class DeadCodeInjectionTransformer extends AbstractNodeTransformer {
      */
     private makeClonedBlockStatementNodeUnique (clonedBlockStatementNode: ESTree.BlockStatement): ESTree.BlockStatement {
         // should wrap cloned block statement node into function node for correct scope encapsulation
-        const hostNode: ESTree.FunctionExpression = NodeFactory
-            .functionExpressionNode([], clonedBlockStatementNode);
+        const hostNode: ESTree.Program = NodeFactory.programNode([
+            NodeFactory.expressionStatementNode(
+                NodeFactory.functionExpressionNode([], clonedBlockStatementNode)
+            )
+        ]);
 
+        NodeUtils.parentizeAst(hostNode);
         NodeUtils.parentizeNode(hostNode, hostNode);
-        NodeUtils.parentizeNode(clonedBlockStatementNode, hostNode);
 
-        return this.transformersRunner.transform(
+        this.transformersRunner.transform(
             hostNode,
             DeadCodeInjectionTransformer.transformersToRenameBlockScopeIdentifiers,
             TransformationStage.Obfuscating
-        ).body;
+        );
+
+        return clonedBlockStatementNode;
     }
 
     /**

+ 3 - 11
src/node-transformers/obfuscating-transformers/obfuscating-replacers/literal-obfuscating-replacers/StringLiteralObfuscatingReplacer.ts

@@ -9,8 +9,6 @@ import { IStringArrayStorage } from '../../../../interfaces/storages/string-arra
 import { IStringArrayStorageAnalyzer } from '../../../../interfaces/analyzers/string-array-storage-analyzer/IStringArrayStorageAnalyzer';
 import { IStringArrayStorageItemData } from '../../../../interfaces/storages/string-array-storage/IStringArrayStorageItem';
 
-import { initializable } from '../../../../decorators/Initializable';
-
 import { StringArrayEncoding } from '../../../../enums/StringArrayEncoding';
 
 import { AbstractObfuscatingReplacer } from '../AbstractObfuscatingReplacer';
@@ -36,12 +34,6 @@ export class StringLiteralObfuscatingReplacer extends AbstractObfuscatingReplace
      */
     private readonly stringArrayStorageAnalyzer: IStringArrayStorageAnalyzer;
 
-    /**
-     * @type {string}
-     */
-    @initializable()
-    private stringArrayStorageCallsWrapperName!: string;
-
     /**
      * @param {IStringArrayStorage} stringArrayStorage
      * @param {IStringArrayStorageAnalyzer} stringArrayStorageAnalyzer
@@ -84,8 +76,6 @@ export class StringLiteralObfuscatingReplacer extends AbstractObfuscatingReplace
 
     @postConstruct()
     public initialize (): void {
-        this.stringArrayStorageCallsWrapperName = this.stringArrayStorage.getStorageCallsWrapperName();
-
         if (this.options.shuffleStringArray) {
             this.stringArrayStorage.shuffleStorage();
         }
@@ -148,7 +138,9 @@ export class StringLiteralObfuscatingReplacer extends AbstractObfuscatingReplace
             callExpressionArgs.push(StringLiteralObfuscatingReplacer.getRc4KeyLiteralNode(decodeKey));
         }
 
-        const stringArrayIdentifierNode: ESTree.Identifier = NodeFactory.identifierNode(this.stringArrayStorageCallsWrapperName);
+        const stringArrayIdentifierNode: ESTree.Identifier = NodeFactory.identifierNode(
+            this.stringArrayStorage.getStorageCallsWrapperName()
+        );
 
         return NodeFactory.callExpressionNode(
             stringArrayIdentifierNode,

+ 2 - 0
src/node-transformers/preparing-transformers/VariablePreserveTransformer.ts

@@ -62,6 +62,8 @@ export class VariablePreserveTransformer extends AbstractNodeTransformer {
     public getVisitor (transformationStage: TransformationStage): IVisitor | null {
         switch (transformationStage) {
             case TransformationStage.Preparing:
+            case TransformationStage.Converting:
+            case TransformationStage.Obfuscating:
                 return {
                     enter: (node: ESTree.Node, parentNode: ESTree.Node | null): ESTree.Node | undefined => {
                         if (parentNode && NodeGuards.isProgramNode(node)) {

+ 7 - 7
src/storages/string-array/StringArrayStorage.ts

@@ -149,6 +149,13 @@ export class StringArrayStorage extends MapStorage <string, IStringArrayStorageI
         return this.rotationAmount;
     }
 
+    /**
+     * @returns {string}
+     */
+    public getStorageName (): string {
+        return this.getStorageId();
+    }
+
     /**
      * @returns {string}
      */
@@ -161,13 +168,6 @@ export class StringArrayStorage extends MapStorage <string, IStringArrayStorageI
         return this.stringArrayStorageName;
     }
 
-    /**
-     * @returns {string}
-     */
-    public getStorageName (): string {
-        return this.getStorageId();
-    }
-
     /**
      * @returns {string}
      */

+ 21 - 9
test/dev/dev.ts

@@ -7,20 +7,32 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../src/options/presets/NoCustomNo
 
     let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
         `
-            const a = '123';
-            const b = '234';
-            const c = '345';
-            
-            console.log(a, b, c);
+            (function () {
+                function foo () {
+                     const f = {f: 1};
+                     const g = {g: 2};
+                     const h = {h: 3};
+                     const i = {i: 4};
+                     const j = {j: 5};
+                }
+                
+                function bar () {
+                     const a = 11;
+                     const b = 12;
+                     const c = 13;
+                     const d = 14;
+                     const e = 15;
+                }
+            })();
         `,
         {
             ...NO_ADDITIONAL_NODES_PRESET,
             compact: false,
+            deadCodeInjection: true,
+            deadCodeInjectionThreshold: 1,
             identifierNamesGenerator: 'mangled',
-            selfDefending: true,
-            stringArray: true,
-            stringArrayThreshold: 1,
-            log: true
+            log: true,
+            transformObjectKeys: true
         }
     ).getObfuscatedCode();
 

+ 40 - 28
test/functional-tests/custom-code-helpers/debug-protection/templates/DebugProtectionFunctionCallTemplate.spec.ts

@@ -1,5 +1,4 @@
 import { assert } from 'chai';
-import { spawn, Thread, Worker } from 'threads/dist';
 
 import { readFileAsString } from '../../../../helpers/readFileAsString';
 
@@ -8,24 +7,13 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/N
 import { IdentifierNamesGenerator } from '../../../../../src/enums/generators/identifier-names-generators/IdentifierNamesGenerator';
 import { ObfuscationTarget } from '../../../../../src/enums/ObfuscationTarget';
 
-import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade';
-
-async function spawnThread(obfuscatedCode: string, threadCallback: Function, timeoutCallback: Function): Promise<void> {
-    const evaluationWorker = await spawn(new Worker('./workers/evaluation-worker'));
-
-    const timeout = setTimeout(() => {
-        Thread.terminate(evaluationWorker);
-        timeoutCallback();
-    }, 1500);
+import { evaluateInWorker } from '../../../../helpers/evaluateInWorker';
 
-    const result: string = await evaluationWorker.evaluate(obfuscatedCode);
-
-    clearTimeout(timeout);
-    Thread.terminate(evaluationWorker);
-    threadCallback(result);
-}
+import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade';
 
 describe('DebugProtectionFunctionCallTemplate', function () {
+    const evaluationTimeout: number = 1500;
+
     this.timeout(10000);
 
     describe('Variant #1: correctly obfuscate code with `HexadecimalIdentifierNamesGenerator``', () => {
@@ -46,7 +34,7 @@ describe('DebugProtectionFunctionCallTemplate', function () {
                 }
             ).getObfuscatedCode();
 
-            spawnThread(
+            evaluateInWorker(
                 obfuscatedCode,
                 (response: number) => {
                     evaluationResult = response;
@@ -54,7 +42,11 @@ describe('DebugProtectionFunctionCallTemplate', function () {
                 },
                 () => {
                     done();
-                }
+                },
+                () => {
+                    done();
+                },
+                evaluationTimeout
             );
         });
 
@@ -81,7 +73,7 @@ describe('DebugProtectionFunctionCallTemplate', function () {
                 }
             ).getObfuscatedCode();
 
-            spawnThread(
+            evaluateInWorker(
                 obfuscatedCode,
                 (response: number) => {
                     evaluationResult = response;
@@ -89,7 +81,11 @@ describe('DebugProtectionFunctionCallTemplate', function () {
                 },
                 () => {
                     done();
-                }
+                },
+                () => {
+                    done();
+                },
+                evaluationTimeout
             );
         });
 
@@ -117,7 +113,7 @@ describe('DebugProtectionFunctionCallTemplate', function () {
                 }
             ).getObfuscatedCode();
 
-            spawnThread(
+            evaluateInWorker(
                 obfuscatedCode,
                 (response: number) => {
                     evaluationResult = response;
@@ -125,7 +121,11 @@ describe('DebugProtectionFunctionCallTemplate', function () {
                 },
                 () => {
                     done();
-                }
+                },
+                () => {
+                    done();
+                },
+                evaluationTimeout
             );
         });
 
@@ -152,7 +152,7 @@ describe('DebugProtectionFunctionCallTemplate', function () {
                 }
             ).getObfuscatedCode();
 
-            spawnThread(
+            evaluateInWorker(
                 obfuscatedCode,
                 (response: number) => {
                     evaluationResult = response;
@@ -160,7 +160,11 @@ describe('DebugProtectionFunctionCallTemplate', function () {
                 },
                 () => {
                     done();
-                }
+                },
+                () => {
+                    done();
+                },
+                evaluationTimeout
             );
         });
 
@@ -187,7 +191,7 @@ describe('DebugProtectionFunctionCallTemplate', function () {
             ).getObfuscatedCode();
             obfuscatedCode = obfuscatedCode.replace(/\+\+ *_0x([a-f0-9]){4,6}/, '');
 
-            spawnThread(
+            evaluateInWorker(
                 obfuscatedCode,
                 (response: number) => {
                     evaluationResult = response;
@@ -195,7 +199,11 @@ describe('DebugProtectionFunctionCallTemplate', function () {
                 },
                 () => {
                     done();
-                }
+                },
+                () => {
+                    done();
+                },
+                evaluationTimeout
             );
         });
 
@@ -221,7 +229,7 @@ describe('DebugProtectionFunctionCallTemplate', function () {
                 }
             ).getObfuscatedCode();
 
-            spawnThread(
+            evaluateInWorker(
                 obfuscatedCode,
                 (response: number) => {
                     evaluationResult = response;
@@ -229,7 +237,11 @@ describe('DebugProtectionFunctionCallTemplate', function () {
                 },
                 () => {
                     done();
-                }
+                },
+                () => {
+                    done();
+                },
+                evaluationTimeout
             );
         });
 

+ 0 - 7
test/functional-tests/custom-code-helpers/debug-protection/templates/workers/evaluation-worker.js

@@ -1,7 +0,0 @@
-const expose = require('threads/worker').expose;
-
-expose({
-    evaluate: (obfuscatedCode) => {
-        return eval(obfuscatedCode);
-    }
-});

+ 180 - 0
test/functional-tests/custom-code-helpers/self-defending/templates/SelfDefendingTemplate.spec.ts

@@ -0,0 +1,180 @@
+import { assert } from 'chai';
+
+import { readFileAsString } from '../../../../helpers/readFileAsString';
+
+import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes';
+
+import { IdentifierNamesGenerator } from '../../../../../src/enums/generators/identifier-names-generators/IdentifierNamesGenerator';
+
+import { evaluateInWorker } from '../../../../helpers/evaluateInWorker';
+
+import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade';
+
+describe('SelfDefendingTemplate', function () {
+    const evaluationTimeout: number = 3500;
+
+    this.timeout(10000);
+
+    describe('Variant #1: correctly obfuscate code with `HexadecimalIdentifierNamesGenerator``', () => {
+        const expectedEvaluationResult: number = 1;
+
+        let obfuscatedCode: string,
+            evaluationResult: number = 0;
+
+        beforeEach((done) => {
+            const code: string = readFileAsString(__dirname + '/fixtures/input.js');
+
+            obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                code,
+                {
+                    ...NO_ADDITIONAL_NODES_PRESET,
+                    selfDefending: true,
+                    identifierNamesGenerator: IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator
+                }
+            ).getObfuscatedCode();
+
+            evaluateInWorker(
+                obfuscatedCode,
+                (response: number) => {
+                    evaluationResult = response;
+                    done();
+                },
+                () => {
+                    done();
+                },
+                () => {
+                    done();
+                },
+                evaluationTimeout
+            );
+        });
+
+        it('should correctly evaluate code with enabled self defending', () => {
+            assert.equal(evaluationResult, expectedEvaluationResult);
+        });
+    });
+
+    describe('Variant #2: correctly obfuscate code with `MangledIdentifierNamesGenerator` option', () => {
+        const expectedEvaluationResult: number = 1;
+
+        let obfuscatedCode: string,
+            evaluationResult: number = 0;
+
+        beforeEach((done) => {
+            const code: string = readFileAsString(__dirname + '/fixtures/input.js');
+
+            obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                code,
+                {
+                    ...NO_ADDITIONAL_NODES_PRESET,
+                    selfDefending: true,
+                    identifierNamesGenerator: IdentifierNamesGenerator.MangledIdentifierNamesGenerator
+                }
+            ).getObfuscatedCode();
+
+            evaluateInWorker(
+                obfuscatedCode,
+                (response: number) => {
+                    evaluationResult = response;
+                    done();
+                },
+                () => {
+                    done();
+                },
+                () => {
+                    done();
+                },
+                evaluationTimeout
+            );
+        });
+
+        it('should correctly evaluate code with enabled self defending', () => {
+            assert.equal(evaluationResult, expectedEvaluationResult);
+        });
+    });
+
+    describe('Variant #3: correctly obfuscate code with `DictionaryIdentifierNamesGenerator` option', () => {
+        const expectedEvaluationResult: number = 1;
+
+        let obfuscatedCode: string,
+            evaluationResult: number = 0;
+
+        beforeEach((done) => {
+            const code: string = readFileAsString(__dirname + '/fixtures/input.js');
+
+            obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                code,
+                {
+                    ...NO_ADDITIONAL_NODES_PRESET,
+                    selfDefending: true,
+                    identifierNamesGenerator: IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator,
+                    identifiersDictionary: ['foo', 'bar', 'baz', 'bark', 'hawk', 'eagle']
+                }
+            ).getObfuscatedCode();
+
+            evaluateInWorker(
+                obfuscatedCode,
+                (response: number) => {
+                    evaluationResult = response;
+                    done();
+                },
+                () => {
+                    done();
+                },
+                () => {
+                    done();
+                },
+                evaluationTimeout
+            );
+        });
+
+        it('should correctly evaluate code with enabled self defending', () => {
+            assert.equal(evaluationResult, expectedEvaluationResult);
+        });
+    });
+
+    describe('Variant #4: obfuscated code with beautified self defending code', () => {
+        const expectedEvaluationResult: number = 0;
+
+        let obfuscatedCode: string,
+            evaluationResult: number = 0;
+
+        beforeEach((done) => {
+            const code: string = readFileAsString(__dirname + '/fixtures/input.js');
+
+            obfuscatedCode = JavaScriptObfuscator.obfuscate(
+                code,
+                {
+                    ...NO_ADDITIONAL_NODES_PRESET,
+                    selfDefending: true
+                }
+            ).getObfuscatedCode();
+            obfuscatedCode = obfuscatedCode
+                .replace(/function\(\){/g, 'function () {')
+                .replace(/=/g, ' = ')
+                .replace(/,/g, ', ')
+                .replace(/;/g, '; ')
+                .replace(/{/g, '{\n')
+                .replace(/}/g, '}\n');
+
+            evaluateInWorker(
+                obfuscatedCode,
+                (response: number) => {
+                    evaluationResult = response;
+                    done();
+                },
+                () => {
+                    done();
+                },
+                () => {
+                    done();
+                },
+                evaluationTimeout
+            );
+        });
+
+        it('should enter code in infinity loop', () => {
+            assert.equal(evaluationResult, expectedEvaluationResult);
+        });
+    });
+});

+ 3 - 0
test/functional-tests/custom-code-helpers/self-defending/templates/fixtures/input.js

@@ -0,0 +1,3 @@
+(function () {
+    return 1;
+})();

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

@@ -844,7 +844,6 @@ describe('JavaScriptObfuscator', () => {
                                 stringArrayEncoding: StringArrayEncoding.Rc4
                             }
                         ).getObfuscatedCode();
-
                     });
 
                     it('does not break on run', () => {

+ 35 - 0
test/helpers/evaluateInWorker.ts

@@ -0,0 +1,35 @@
+import { spawn, Thread, Worker } from 'threads/dist';
+
+/**
+ * @param {string} code
+ * @param {(result: any, code: string) => void} resultCallback
+ * @param {(error: Error, code: string) => void} errorCallback
+ * @param {() => void} timeoutCallback
+ * @param {number} waitTimeout
+ * @returns {Promise<void>}
+ */
+export async function evaluateInWorker(
+    code: string,
+    resultCallback: (result: any, code: string) => void,
+    errorCallback: (error: Error, code: string) => void,
+    timeoutCallback: () => void,
+    waitTimeout: number
+): Promise<void> {
+    const evaluationWorker = await spawn(new Worker('./workers/evaluation-worker'));
+
+    const timeout = setTimeout(() => {
+        Thread.terminate(evaluationWorker);
+        timeoutCallback();
+    }, waitTimeout);
+
+    try {
+        const result: string = await evaluationWorker.evaluate(code);
+
+        resultCallback(result, code);
+    } catch (error) {
+        errorCallback(error, code);
+    } finally {
+        clearTimeout(timeout);
+        Thread.terminate(evaluationWorker);
+    }
+}

+ 7 - 0
test/helpers/workers/evaluation-worker.js

@@ -0,0 +1,7 @@
+const expose = require('threads/worker').expose;
+
+expose({
+    evaluate: (code) => {
+        return eval(code);
+    }
+});

+ 1 - 0
test/index.spec.ts

@@ -55,6 +55,7 @@ import './functional-tests/analyzers/calls-graph-analyzer/CallsGraphAnalyzer.spe
 import './functional-tests/cli/JavaScriptObfuscatorCLI.spec';
 import './functional-tests/custom-code-helpers/console-output/ConsoleOutputDisableExpressionCodeHelper.spec';
 import './functional-tests/custom-code-helpers/domain-lock/DomainLockCodeHelper.spec';
+import './functional-tests/custom-code-helpers/self-defending/templates/SelfDefendingTemplate.spec';
 import './functional-tests/custom-code-helpers/string-array/StringArrayCallsWrapperCodeHelper.spec';
 import './functional-tests/custom-code-helpers/string-array/StringArrayRotateFunctionCodeHelper.spec';
 import './functional-tests/custom-code-helpers/string-array/StringArrayCodeHelper.spec';

+ 120 - 1
test/runtime-tests/JavaScriptObfuscatorRuntime.spec.ts

@@ -5,6 +5,7 @@ import { TInputOptions } from '../../src/types/options/TInputOptions';
 import { StringArrayEncoding } from '../../src/enums/StringArrayEncoding';
 import { IdentifierNamesGenerator } from '../../src/enums/generators/identifier-names-generators/IdentifierNamesGenerator';
 
+import { evaluateInWorker } from '../helpers/evaluateInWorker';
 import { readFileAsString } from '../helpers/readFileAsString';
 
 import { JavaScriptObfuscator } from '../../src/JavaScriptObfuscatorFacade';
@@ -36,7 +37,7 @@ describe('JavaScriptObfuscator runtime eval', function () {
         unicodeEscapeSequence: true
     };
 
-    this.timeout(100000);
+    this.timeout(200000);
 
     [
         {
@@ -164,5 +165,123 @@ describe('JavaScriptObfuscator runtime eval', function () {
                 );
             });
         });
+
+        describe(`Obfuscator. ${detailedDescription}`, () => {
+            const evaluationTimeout: number = 10000;
+
+            let evaluationResult: string;
+
+            beforeEach((done) => {
+                const code: string = readFileAsString(process.cwd() + '/dist/index.js');
+
+                const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
+                    code,
+                    {
+                        ...baseOptions,
+                        ...options
+                    }
+                ).getObfuscatedCode();
+
+                evaluateInWorker(
+                    `
+                        ${getEnvironmentCode()}
+                        ${obfuscatedCode}
+                        module.exports.obfuscate('var foo = 1;').getObfuscatedCode();
+                    `,
+                    (response: string) => {
+                        evaluationResult = response;
+                        done();
+                    },
+                    (error: Error) => {
+                        evaluationResult = error.message;
+                        done();
+                    },
+                    () => {
+                        done();
+                    },
+                    evaluationTimeout
+                );
+            });
+
+            it('should obfuscate code without any runtime errors after obfuscation: Variant #3 obfuscator', () => {
+                assert.equal(
+                    evaluationResult,
+                    'var foo=0x1;'
+                );
+            });
+        });
+
+        [
+            {
+                debugProtection: false,
+                selfDefending: false,
+                stringArray: true
+            },
+            {
+                debugProtection: false,
+                selfDefending: true,
+                stringArray: false
+            },
+            {
+                debugProtection: true,
+                selfDefending: false,
+                stringArray: false
+            },
+            {
+                debugProtection: true,
+                selfDefending: true,
+                stringArray: false
+            },
+            {
+                debugProtection: true,
+                selfDefending: true,
+                stringArray: true
+            }
+        ].forEach((webpackBootstrapOptions: Partial<TInputOptions>) => {
+            describe(`Webpack bootstrap code. ${detailedDescription}. ${JSON.stringify(webpackBootstrapOptions)}`, () => {
+                const evaluationTimeout: number = 10000;
+
+                let evaluationResult: string;
+
+                beforeEach((done) => {
+                    const code: string = readFileAsString(__dirname + '/fixtures/webpack-bootstrap.js');
+
+                    const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
+                        code,
+                        {
+                            ...baseOptions,
+                            ...options,
+                            ...webpackBootstrapOptions
+                        }
+                    ).getObfuscatedCode();
+
+                    evaluateInWorker(
+                        `
+                        ${getEnvironmentCode()}
+                        ${obfuscatedCode}
+                    `,
+                        (response: string) => {
+                            evaluationResult = response;
+                            done();
+                        },
+                        (error: Error) => {
+                            evaluationResult = error.message;
+                            done();
+                        },
+                        () => {
+                            done();
+                        },
+                        evaluationTimeout
+                    );
+                });
+
+                it('should obfuscate code without any runtime errors after obfuscation: Variant #4 webpack bootstrap', () => {
+                    assert.equal(
+                        evaluationResult,
+                        'foo'
+                    );
+                });
+            });
+        });
     });
 });

+ 77 - 0
test/runtime-tests/fixtures/webpack-bootstrap.js

@@ -0,0 +1,77 @@
+const module =
+    (function(modules) {
+        var installedModules = {};
+
+        function __webpack_require__(moduleId) {
+            if (installedModules[moduleId]) {
+                return installedModules[moduleId].exports;
+            }
+            var module = installedModules[moduleId] = {
+                i: moduleId,
+                l: false,
+                exports: {}
+            };
+            modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
+            module.l = true;
+            return module.exports;
+        }
+        __webpack_require__.m = modules;
+        __webpack_require__.c = installedModules;
+        __webpack_require__.d = function(exports, name, getter) {
+            if (!__webpack_require__.o(exports, name)) {
+                Object.defineProperty(exports, name, {
+                    enumerable: true,
+                    get: getter
+                });
+            }
+        };
+        __webpack_require__.r = function(exports) {
+            if (typeof Symbol !== 'undefined' && Symbol.toStringTag) {
+                Object.defineProperty(exports, Symbol.toStringTag, {
+                    value: 'Module'
+                });
+            }
+            Object.defineProperty(exports, '__esModule', {
+                value: true
+            });
+        };
+        __webpack_require__.t = function(value, mode) {
+            if (mode & 1) value = __webpack_require__(value);
+            if (mode & 8) return value;
+            if ((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
+            var ns = Object.create(null);
+            __webpack_require__.r(ns);
+            Object.defineProperty(ns, 'default', {
+                enumerable: true,
+                value: value
+            });
+            if (mode & 2 && typeof value != 'string')
+                for (var key in value) __webpack_require__.d(ns, key, function(key) {
+                    return value[key];
+                }.bind(null, key));
+            return ns;
+        };
+        __webpack_require__.n = function(module) {
+            var getter = module && module.__esModule ?
+                function getDefault() {
+                    return module['default'];
+                } :
+                function getModuleExports() {
+                    return module;
+                };
+            __webpack_require__.d(getter, 'a', getter);
+            return getter;
+        };
+        __webpack_require__.o = function(object, property) {
+            return Object.prototype.hasOwnProperty.call(object, property);
+        };
+        __webpack_require__.p = "";
+        return __webpack_require__(__webpack_require__.s = "foo");
+    })
+    ({
+        "foo": (function(module, exports) {
+            module.exports = 'foo';
+        })
+    });
+
+module;

+ 7 - 7
test/unit-tests/generators/identifier-names-generators/DictionarylIdentifierNamesGenerator.spec.ts

@@ -12,7 +12,7 @@ import { IdentifierNamesGenerator } from '../../../../src/enums/generators/ident
 import { InversifyContainerFacade } from '../../../../src/container/InversifyContainerFacade';
 
 describe('DictionaryIdentifierNamesGenerator', () => {
-    describe('generate', () => {
+    describe('generateForGlobalScope', () => {
         let identifierNamesGenerator: IIdentifierNamesGenerator,
             dictionaryIdentifierName: string;
 
@@ -33,7 +33,7 @@ describe('DictionaryIdentifierNamesGenerator', () => {
                 const expectedDictionaryIdentifierNameRegExp: RegExp = /[a|b]/;
 
                 beforeEach(() => {
-                    dictionaryIdentifierName = identifierNamesGenerator.generate();
+                    dictionaryIdentifierName = identifierNamesGenerator.generateForGlobalScope();
                 });
 
                 it('Match #1: should return first identifier name', () => {
@@ -49,7 +49,7 @@ describe('DictionaryIdentifierNamesGenerator', () => {
                 const expectedDictionaryIdentifierNameRegExp: RegExp = /[A|B]/;
 
                 beforeEach(() => {
-                    dictionaryIdentifierName = identifierNamesGenerator.generate();
+                    dictionaryIdentifierName = identifierNamesGenerator.generateForGlobalScope();
                 });
 
                 it('Match #1: should return third identifier name', () => {
@@ -79,7 +79,7 @@ describe('DictionaryIdentifierNamesGenerator', () => {
                 const expectedDictionaryIdentifierNameRegExp: RegExp = /[a|A]/;
 
                 beforeEach(() => {
-                    dictionaryIdentifierName = identifierNamesGenerator.generate();
+                    dictionaryIdentifierName = identifierNamesGenerator.generateForGlobalScope();
                 });
 
                 it('Match #1: should return first identifier name', () => {
@@ -112,7 +112,7 @@ describe('DictionaryIdentifierNamesGenerator', () => {
                 const expectedFourthIterationIdentifierName: string = 'AA';
 
                 beforeEach(() => {
-                    dictionaryIdentifierName = identifierNamesGenerator.generate();
+                    dictionaryIdentifierName = identifierNamesGenerator.generateForGlobalScope();
                 });
 
                 it('Match #1: should return first identifier name', () => {
@@ -185,7 +185,7 @@ describe('DictionaryIdentifierNamesGenerator', () => {
                         IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator
                     );
 
-                    testFunc = () => identifierNamesGenerator.generate();
+                    testFunc = () => identifierNamesGenerator.generateForGlobalScope();
                 });
 
                 it('Match #1: should return first identifier name', () => {
@@ -215,7 +215,7 @@ describe('DictionaryIdentifierNamesGenerator', () => {
                         IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator
                     );
 
-                    testFunc = () => identifierNamesGenerator.generate();
+                    testFunc = () => identifierNamesGenerator.generateForGlobalScope();
                 });
 
                 it('Should throw an error when identifiers dictionary is empty', () => {

+ 2 - 2
test/unit-tests/generators/identifier-names-generators/HexadecimalIdentifierNamesGenerator.spec.ts

@@ -12,7 +12,7 @@ import { IdentifierNamesGenerator } from '../../../../src/enums/generators/ident
 import { InversifyContainerFacade } from '../../../../src/container/InversifyContainerFacade';
 
 describe('HexadecimalIdentifierNamesGenerator', () => {
-    describe('generate', () => {
+    describe('generateForGlobalScope', () => {
         let identifierNamesGenerator: IIdentifierNamesGenerator,
             hexadecimalIdentifierName: string,
             regExp: RegExp;
@@ -26,7 +26,7 @@ describe('HexadecimalIdentifierNamesGenerator', () => {
                 IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator
             );
 
-            hexadecimalIdentifierName = identifierNamesGenerator.generate();
+            hexadecimalIdentifierName = identifierNamesGenerator.generateForGlobalScope();
             regExp = /^_0x(\w){4,6}$/;
         });
 

+ 11 - 11
test/unit-tests/generators/identifier-names-generators/MangledlIdentifierNamesGenerator.spec.ts

@@ -12,7 +12,7 @@ import { IdentifierNamesGenerator } from '../../../../src/enums/generators/ident
 import { InversifyContainerFacade } from '../../../../src/container/InversifyContainerFacade';
 
 describe('MangledIdentifierNamesGenerator', () => {
-    describe('generate', () => {
+    describe('generateForGlobalScope', () => {
         let identifierNamesGenerator: IIdentifierNamesGenerator,
             mangledIdentifierName: string;
 
@@ -30,7 +30,7 @@ describe('MangledIdentifierNamesGenerator', () => {
             const expectedMangledIdentifierName: string = 'a';
 
             beforeEach(() => {
-                mangledIdentifierName = identifierNamesGenerator.generate();
+                mangledIdentifierName = identifierNamesGenerator.generateForGlobalScope();
             });
 
             it('should return mangled name', () => {
@@ -44,7 +44,7 @@ describe('MangledIdentifierNamesGenerator', () => {
 
             beforeEach(() => {
                 for (let i: number = 0; i <= expectedMangledIdentifierPosition; i++) {
-                    mangledIdentifierName = identifierNamesGenerator.generate();
+                    mangledIdentifierName = identifierNamesGenerator.generateForGlobalScope();
                 }
             });
 
@@ -59,7 +59,7 @@ describe('MangledIdentifierNamesGenerator', () => {
 
             beforeEach(() => {
                 for (let i: number = 0; i <= expectedMangledIdentifierPosition; i++) {
-                    mangledIdentifierName = identifierNamesGenerator.generate();
+                    mangledIdentifierName = identifierNamesGenerator.generateForGlobalScope();
                 }
             });
 
@@ -74,7 +74,7 @@ describe('MangledIdentifierNamesGenerator', () => {
 
             beforeEach(() => {
                 for (let i: number = 0; i <= expectedMangledIdentifierPosition; i++) {
-                    mangledIdentifierName = identifierNamesGenerator.generate();
+                    mangledIdentifierName = identifierNamesGenerator.generateForGlobalScope();
                 }
             });
 
@@ -89,7 +89,7 @@ describe('MangledIdentifierNamesGenerator', () => {
 
             beforeEach(() => {
                 for (let i: number = 0; i <= expectedMangledIdentifierPosition; i++) {
-                    mangledIdentifierName = identifierNamesGenerator.generate();
+                    mangledIdentifierName = identifierNamesGenerator.generateForGlobalScope();
                 }
             });
 
@@ -109,7 +109,7 @@ describe('MangledIdentifierNamesGenerator', () => {
 
             beforeEach(() => {
                 for (let i: number = 0; i <= expectedMangledIdentifierPosition2; i++) {
-                    mangledIdentifierName = identifierNamesGenerator.generate();
+                    mangledIdentifierName = identifierNamesGenerator.generateForGlobalScope();
 
                     if (i === expectedMangledIdentifierPosition1) {
                         mangledIdentifierName1 = mangledIdentifierName;
@@ -189,8 +189,8 @@ describe('MangledIdentifierNamesGenerator', () => {
                     IdentifierNamesGenerator.MangledIdentifierNamesGenerator
                 );
 
-                firstMangledIdentifierName = identifierNamesGenerator.generate();
-                secondMangledIdentifierName = identifierNamesGenerator.generate();
+                firstMangledIdentifierName = identifierNamesGenerator.generateForGlobalScope();
+                secondMangledIdentifierName = identifierNamesGenerator.generateForGlobalScope();
             });
 
             it('should generate first identifier', () => {
@@ -220,8 +220,8 @@ describe('MangledIdentifierNamesGenerator', () => {
                     IdentifierNamesGenerator.MangledIdentifierNamesGenerator
                 );
 
-                firstMangledIdentifierName = identifierNamesGenerator.generate();
-                secondMangledIdentifierName = identifierNamesGenerator.generate();
+                firstMangledIdentifierName = identifierNamesGenerator.generateForGlobalScope();
+                secondMangledIdentifierName = identifierNamesGenerator.generateForGlobalScope();
             });
 
             it('should generate first identifier', () => {

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