SB-6.1-PRE

This commit is contained in:
ItzEmerald committed 2021-02-02 13:50:53 +00:00
1 parent 690169a409
commit 358a25f522
3760 files changed
+300059 -36

No files matched your search

+116
View File
@@ -0,0 +1,116 @@
import * as acorn from 'acorn';
import * as ESTree from 'estree';
import chalk, { Chalk } from 'chalk';
/**
* Facade over AST parser `acorn`
*/
export class ASTParserFacade {
/**
* @type {Chalk}
*/
private static readonly colorError: Chalk = chalk.red;
/**
* @type {number}
*/
private static readonly nearestSymbolsCount: number = 15;
/**
* @type {acorn.Options['sourceType'][]}
*/
private static readonly sourceTypes: acorn.Options['sourceType'][] = [
'script',
'module'
];
/**
* @param {string} sourceCode
* @param {Options} config
* @returns {Program}
*/
public static parse (sourceCode: string, config: acorn.Options): ESTree.Program | never {
const sourceTypeLength: number = ASTParserFacade.sourceTypes.length;
for (let i: number = 0; i < sourceTypeLength; i++) {
try {
return ASTParserFacade.parseType(sourceCode, config, ASTParserFacade.sourceTypes[i]);
} catch (error) {
if (i < sourceTypeLength - 1) {
continue;
}
throw new Error(ASTParserFacade.processParsingError(
sourceCode,
error.message,
error.loc
));
}
}
throw new Error('Acorn parsing error');
}
/**
* @param {string} sourceCode
* @param {acorn.Options} inputConfig
* @param {acorn.Options["sourceType"]} sourceType
* @returns {Program}
*/
private static parseType (
sourceCode: string,
inputConfig: acorn.Options,
sourceType: acorn.Options['sourceType']
): ESTree.Program {
const comments: ESTree.Comment[] = [];
const config: acorn.Options = {
...inputConfig,
onComment: comments,
sourceType
};
const program: ESTree.Program = <any>acorn
.parse(sourceCode, config);
if (comments.length) {
program.comments = comments;
}
return program;
}
/**
* @param {string} sourceCode
* @param {string} errorMessage
* @param {Position | null} position
* @returns {never}
*/
private static processParsingError (
sourceCode: string,
errorMessage: string,
position: ESTree.Position | null
): never {
if (!position || !position.line || !position.column) {
throw new Error(errorMessage);
}
const sourceCodeLines: string[] = sourceCode.split(/\r?\n/);
const errorLine: string | undefined = sourceCodeLines[position.line - 1];
if (!errorLine) {
throw new Error(errorMessage);
}
const startErrorIndex: number = Math.max(0, position.column - ASTParserFacade.nearestSymbolsCount);
const endErrorIndex: number = Math.min(errorLine.length, position.column + ASTParserFacade.nearestSymbolsCount);
const formattedPointer: string = ASTParserFacade.colorError('>');
const formattedCodeSlice: string = `...${
errorLine.slice(startErrorIndex, endErrorIndex).replace(/^\s+/, '')
}...`;
throw new Error(
`ERROR at line ${position.line}: ${errorMessage}\n${formattedPointer} ${formattedCodeSlice}`
);
}
}
+304
View File
@@ -0,0 +1,304 @@
import { inject, injectable, } from 'inversify';
import { ServiceIdentifiers } from './container/ServiceIdentifiers';
import * as acorn from 'acorn';
import * as escodegen from '@javascript-obfuscator/escodegen';
import * as ESTree from 'estree';
import { TObfuscatedCodeFactory } from './types/container/source-code/TObfuscatedCodeFactory';
import { ICodeTransformersRunner } from './interfaces/code-transformers/ICodeTransformersRunner';
import { IGeneratorOutput } from './interfaces/IGeneratorOutput';
import { IJavaScriptObfuscator } from './interfaces/IJavaScriptObfsucator';
import { ILogger } from './interfaces/logger/ILogger';
import { IObfuscatedCode } from './interfaces/source-code/IObfuscatedCode';
import { IOptions } from './interfaces/options/IOptions';
import { IRandomGenerator } from './interfaces/utils/IRandomGenerator';
import { INodeTransformersRunner } from './interfaces/node-transformers/INodeTransformersRunner';
import { CodeTransformer } from './enums/code-transformers/CodeTransformer';
import { CodeTransformationStage } from './enums/code-transformers/CodeTransformationStage';
import { LoggingMessage } from './enums/logger/LoggingMessage';
import { NodeTransformer } from './enums/node-transformers/NodeTransformer';
import { NodeTransformationStage } from './enums/node-transformers/NodeTransformationStage';
import { ecmaVersion } from './constants/EcmaVersion';
import { ASTParserFacade } from './ASTParserFacade';
import { NodeGuards } from './node/NodeGuards';
import { Utils } from './utils/Utils';
@injectable()
export class JavaScriptObfuscator implements IJavaScriptObfuscator {
/**
* @type {Options}
*/
private static readonly parseOptions: acorn.Options = {
ecmaVersion,
allowHashBang: true,
allowImportExportEverywhere: true,
allowReturnOutsideFunction: true,
locations: true,
ranges: true
};
/**
* @type {GenerateOptions}
*/
private static readonly escodegenParams: escodegen.GenerateOptions = {
comment: true,
verbatim: 'x-verbatim-property',
sourceMapWithCode: true
};
/**
* @type {CodeTransformer[]}
*/
private static readonly codeTransformersList: CodeTransformer[] = [
CodeTransformer.HashbangOperatorTransformer
];
/**
* @type {NodeTransformer[]}
*/
private static readonly nodeTransformersList: NodeTransformer[] = [
NodeTransformer.BooleanLiteralTransformer,
NodeTransformer.BlockStatementControlFlowTransformer,
NodeTransformer.BlockStatementSimplifyTransformer,
NodeTransformer.CommentsTransformer,
NodeTransformer.CustomCodeHelpersTransformer,
NodeTransformer.DeadCodeInjectionTransformer,
NodeTransformer.EscapeSequenceTransformer,
NodeTransformer.EvalCallExpressionTransformer,
NodeTransformer.ExportSpecifierTransformer,
NodeTransformer.ExpressionStatementsMergeTransformer,
NodeTransformer.FunctionControlFlowTransformer,
NodeTransformer.IfStatementSimplifyTransformer,
NodeTransformer.LabeledStatementTransformer,
NodeTransformer.RenamePropertiesTransformer,
NodeTransformer.MemberExpressionTransformer,
NodeTransformer.MetadataTransformer,
NodeTransformer.MethodDefinitionTransformer,
NodeTransformer.NumberLiteralTransformer,
NodeTransformer.NumberToNumericalExpressionTransformer,
NodeTransformer.ObfuscatingGuardsTransformer,
NodeTransformer.ObjectExpressionKeysTransformer,
NodeTransformer.ObjectExpressionTransformer,
NodeTransformer.ObjectPatternPropertiesTransformer,
NodeTransformer.ParentificationTransformer,
NodeTransformer.ScopeIdentifiersTransformer,
NodeTransformer.SplitStringTransformer,
NodeTransformer.StringArrayScopeCallsWrapperTransformer,
NodeTransformer.StringArrayTransformer,
NodeTransformer.TemplateLiteralTransformer,
NodeTransformer.VariableDeclarationsMergeTransformer,
NodeTransformer.VariablePreserveTransformer
];
/**
* @type {ICodeTransformersRunner}
*/
private readonly codeTransformersRunner: ICodeTransformersRunner;
/**
* @type {ILogger}
*/
private readonly logger: ILogger;
/**
* @type {TObfuscatedCodeFactory}
*/
private readonly obfuscatedCodeFactory: TObfuscatedCodeFactory;
/**
* @type {IOptions}
*/
private readonly options: IOptions;
/**
* @type {IRandomGenerator}
*/
private readonly randomGenerator: IRandomGenerator;
/**
* @type {INodeTransformersRunner}
*/
private readonly nodeTransformersRunner: INodeTransformersRunner;
/**
* @param {ICodeTransformersRunner} codeTransformersRunner
* @param {INodeTransformersRunner} nodeTransformersRunner
* @param {IRandomGenerator} randomGenerator
* @param {TObfuscatedCodeFactory} obfuscatedCodeFactory
* @param {ILogger} logger
* @param {IOptions} options
*/
public constructor (
@inject(ServiceIdentifiers.ICodeTransformersRunner) codeTransformersRunner: ICodeTransformersRunner,
@inject(ServiceIdentifiers.INodeTransformersRunner) nodeTransformersRunner: INodeTransformersRunner,
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.Factory__IObfuscatedCode) obfuscatedCodeFactory: TObfuscatedCodeFactory,
@inject(ServiceIdentifiers.ILogger) logger: ILogger,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
this.codeTransformersRunner = codeTransformersRunner;
this.nodeTransformersRunner = nodeTransformersRunner;
this.randomGenerator = randomGenerator;
this.obfuscatedCodeFactory = obfuscatedCodeFactory;
this.logger = logger;
this.options = options;
}
/**
* @param {string} sourceCode
* @returns {IObfuscatedCode}
*/
public obfuscate (sourceCode: string): IObfuscatedCode {
if (typeof sourceCode !== 'string') {
sourceCode = '';
}
const timeStart: number = Date.now();
this.logger.info(LoggingMessage.Version, Utils.buildVersionMessage(process.env.VERSION, process.env.BUILD_TIMESTAMP));
this.logger.info(LoggingMessage.ObfuscationStarted);
this.logger.info(LoggingMessage.RandomGeneratorSeed, this.randomGenerator.getInputSeed());
// preparing code transformations
sourceCode = this.runCodeTransformationStage(sourceCode, CodeTransformationStage.PreparingTransformers);
// parse AST tree
const astTree: ESTree.Program = this.parseCode(sourceCode);
// obfuscate AST tree
const obfuscatedAstTree: ESTree.Program = this.transformAstTree(astTree);
// generate code
const generatorOutput: IGeneratorOutput = this.generateCode(sourceCode, obfuscatedAstTree);
// finalizing code transformations
generatorOutput.code = this.runCodeTransformationStage(generatorOutput.code, CodeTransformationStage.FinalizingTransformers);
const obfuscationTime: number = (Date.now() - timeStart) / 1000;
this.logger.success(LoggingMessage.ObfuscationCompleted, obfuscationTime);
return this.getObfuscatedCode(generatorOutput);
}
/**
* @param {string} sourceCode
* @returns {Program}
*/
private parseCode (sourceCode: string): ESTree.Program {
return ASTParserFacade.parse(sourceCode, JavaScriptObfuscator.parseOptions);
}
/**
* @param {Program} astTree
* @returns {Program}
*/
private transformAstTree (astTree: ESTree.Program): ESTree.Program {
astTree = this.runNodeTransformationStage(astTree, NodeTransformationStage.Initializing);
const isEmptyAstTree: boolean = NodeGuards.isProgramNode(astTree)
&& !astTree.body.length
&& !astTree.leadingComments
&& !astTree.trailingComments;
if (isEmptyAstTree) {
this.logger.warn(LoggingMessage.EmptySourceCode);
return astTree;
}
astTree = this.runNodeTransformationStage(astTree, NodeTransformationStage.Preparing);
if (this.options.deadCodeInjection) {
astTree = this.runNodeTransformationStage(astTree, NodeTransformationStage.DeadCodeInjection);
}
if (this.options.controlFlowFlattening) {
astTree = this.runNodeTransformationStage(astTree, NodeTransformationStage.ControlFlowFlattening);
}
if (this.options.renameProperties) {
astTree = this.runNodeTransformationStage(astTree, NodeTransformationStage.RenameProperties);
}
astTree = this.runNodeTransformationStage(astTree, NodeTransformationStage.Converting);
astTree = this.runNodeTransformationStage(astTree, NodeTransformationStage.RenameIdentifiers);
astTree = this.runNodeTransformationStage(astTree, NodeTransformationStage.StringArray);
if (this.options.simplify) {
astTree = this.runNodeTransformationStage(astTree, NodeTransformationStage.Simplifying);
}
astTree = this.runNodeTransformationStage(astTree, NodeTransformationStage.Finalizing);
return astTree;
}
/**
* @param {string} sourceCode
* @param {Program} astTree
* @returns {IGeneratorOutput}
*/
private generateCode (sourceCode: string, astTree: ESTree.Program): IGeneratorOutput {
const escodegenParams: escodegen.GenerateOptions = {
...JavaScriptObfuscator.escodegenParams
};
if (this.options.sourceMap) {
escodegenParams.sourceMap = this.options.inputFileName || 'sourceMap';
escodegenParams.sourceContent = sourceCode;
}
const generatorOutput: IGeneratorOutput = escodegen.generate(astTree, {
...escodegenParams,
format: {
compact: this.options.compact
}
});
generatorOutput.map = generatorOutput.map ? generatorOutput.map.toString() : '';
return generatorOutput;
}
/**
* @param {IGeneratorOutput} generatorOutput
* @returns {IObfuscatedCode}
*/
private getObfuscatedCode (generatorOutput: IGeneratorOutput): IObfuscatedCode {
return this.obfuscatedCodeFactory(generatorOutput.code, generatorOutput.map);
}
/**
* @param {string} code
* @param {CodeTransformationStage} codeTransformationStage
* @returns {string}
*/
private runCodeTransformationStage (code: string, codeTransformationStage: CodeTransformationStage): string {
this.logger.info(LoggingMessage.CodeTransformationStage, codeTransformationStage);
return this.codeTransformersRunner.transform(
code,
JavaScriptObfuscator.codeTransformersList,
codeTransformationStage
);
}
/**
* @param {Program} astTree
* @param {NodeTransformationStage} nodeTransformationStage
* @returns {Program}
*/
private runNodeTransformationStage (astTree: ESTree.Program, nodeTransformationStage: NodeTransformationStage): ESTree.Program {
this.logger.info(LoggingMessage.NodeTransformationStage, nodeTransformationStage);
return this.nodeTransformersRunner.transform(
astTree,
JavaScriptObfuscator.nodeTransformersList,
nodeTransformationStage
);
}
}
@@ -0,0 +1,17 @@
import 'reflect-metadata';
import { JavaScriptObfuscatorCLI } from './cli/JavaScriptObfuscatorCLI';
class JavaScriptObfuscatorCLIFacade {
/**
* @param {string[]} argv
*/
public static obfuscate (argv: string[]): void {
const javaScriptObfuscatorCLI: JavaScriptObfuscatorCLI = new JavaScriptObfuscatorCLI(argv);
javaScriptObfuscatorCLI.initialize();
javaScriptObfuscatorCLI.run();
}
}
export { JavaScriptObfuscatorCLIFacade as JavaScriptObfuscatorCLI };
+93
View File
@@ -0,0 +1,93 @@
import 'reflect-metadata';
import { ServiceIdentifiers } from './container/ServiceIdentifiers';
import { TDictionary } from './types/TDictionary';
import { TInputOptions } from './types/options/TInputOptions';
import { TObfuscationResultsObject } from './types/TObfuscationResultsObject';
import { TOptionsPreset } from './types/options/TOptionsPreset';
import { IInversifyContainerFacade } from './interfaces/container/IInversifyContainerFacade';
import { IJavaScriptObfuscator } from './interfaces/IJavaScriptObfsucator';
import { IObfuscatedCode } from './interfaces/source-code/IObfuscatedCode';
import { InversifyContainerFacade } from './container/InversifyContainerFacade';
import { Options } from './options/Options';
import { Utils } from './utils/Utils';
class JavaScriptObfuscatorFacade {
/**
* @type {string | undefined}
*/
public static version: string = process.env.VERSION ?? 'unknown';
/**
* @param {string} sourceCode
* @param {TInputOptions} inputOptions
* @returns {IObfuscatedCode}
*/
public static obfuscate (sourceCode: string, inputOptions: TInputOptions = {}): IObfuscatedCode {
const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade();
inversifyContainerFacade.load(sourceCode, '', inputOptions);
const javaScriptObfuscator: IJavaScriptObfuscator = inversifyContainerFacade
.get<IJavaScriptObfuscator>(ServiceIdentifiers.IJavaScriptObfuscator);
const obfuscatedCode: IObfuscatedCode = javaScriptObfuscator.obfuscate(sourceCode);
inversifyContainerFacade.unload();
return obfuscatedCode;
}
/**
* @param {TSourceCodesObject} sourceCodesObject
* @param {TInputOptions} inputOptions
* @returns {TObfuscationResultsObject<TSourceCodesObject>}
*/
public static obfuscateMultiple <TSourceCodesObject extends TDictionary<string>> (
sourceCodesObject: TSourceCodesObject,
inputOptions: TInputOptions = {}
): TObfuscationResultsObject<TSourceCodesObject> {
if (typeof sourceCodesObject !== 'object') {
throw new Error('Source codes object should be a plain object');
}
return Object
.keys(sourceCodesObject)
.reduce(
(
acc: TObfuscationResultsObject<TSourceCodesObject>,
sourceCodeIdentifier: keyof TSourceCodesObject,
index: number
) => {
const identifiersPrefix: string = Utils.getIdentifiersPrefixForMultipleSources(
inputOptions.identifiersPrefix,
index
);
const sourceCode: string = sourceCodesObject[sourceCodeIdentifier];
const sourceCodeOptions: TInputOptions = {
...inputOptions,
identifiersPrefix
};
return {
...acc,
[sourceCodeIdentifier]: JavaScriptObfuscatorFacade.obfuscate(sourceCode, sourceCodeOptions)
};
},
<TObfuscationResultsObject<TSourceCodesObject>>{}
);
}
/**
* @param {TOptionsPreset} optionsPreset
* @returns {TInputOptions}
*/
public static getOptionsByPreset (optionsPreset: TOptionsPreset): TInputOptions {
return Options.getOptionsByPreset(optionsPreset);
}
}
export { JavaScriptObfuscatorFacade as JavaScriptObfuscator };
@@ -0,0 +1,170 @@
import { inject, injectable, } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import * as estraverse from 'estraverse';
import * as ESTree from 'estree';
import { TCalleeDataExtractorFactory } from '../../types/container/calls-graph-analyzer/TCalleeDataExtractorFactory';
import { ICalleeData } from '../../interfaces/analyzers/calls-graph-analyzer/ICalleeData';
import { ICallsGraphAnalyzer } from '../../interfaces/analyzers/calls-graph-analyzer/ICallsGraphAnalyzer';
import { ICallsGraphData } from '../../interfaces/analyzers/calls-graph-analyzer/ICallsGraphData';
import { CalleeDataExtractor } from '../../enums/analyzers/calls-graph-analyzer/CalleeDataExtractor';
import { NodeGuards } from '../../node/NodeGuards';
import { NodeStatementUtils } from '../../node/NodeStatementUtils';
/**
* This class generates a data with a graph of functions calls
*
* For example:
*
* function Foo () {
* var baz = function () {
*
* }
*
* baz();
* }
*
* foo();
*
* Will generate a structure like:
*
* [
* {
* callee: FOO_FUNCTION_NODE
* name: 'Foo',
* trace: [
* {
* callee: BAZ_FUNCTION_NODE,
* name: 'baz,
* trace: []
* }
* ]
* }
* ]
*/
@injectable()
export class CallsGraphAnalyzer implements ICallsGraphAnalyzer {
/**
* @type {CalleeDataExtractor[]}
*/
private static readonly calleeDataExtractorsList: CalleeDataExtractor[] = [
CalleeDataExtractor.FunctionDeclarationCalleeDataExtractor,
CalleeDataExtractor.FunctionExpressionCalleeDataExtractor,
CalleeDataExtractor.ObjectExpressionCalleeDataExtractor
];
/**
* @type {number}
*/
private static readonly limitThresholdActivationLength: number = 25;
/**
* @type {number}
*/
private static readonly limitThreshold: number = 0.002;
/**
* @type {TCalleeDataExtractorFactory}
*/
private readonly calleeDataExtractorFactory: TCalleeDataExtractorFactory;
public constructor (
@inject(ServiceIdentifiers.Factory__ICalleeDataExtractor) calleeDataExtractorFactory: TCalleeDataExtractorFactory
) {
this.calleeDataExtractorFactory = calleeDataExtractorFactory;
}
/**
* @param {number} blockScopeBodyLength
* @returns {number}
*/
public static getLimitIndex (blockScopeBodyLength: number): number {
const lastIndex: number = blockScopeBodyLength - 1;
const limitThresholdActivationIndex: number = CallsGraphAnalyzer.limitThresholdActivationLength - 1;
let limitIndex: number = lastIndex;
if (lastIndex > limitThresholdActivationIndex) {
limitIndex = Math.round(
limitThresholdActivationIndex + (lastIndex * CallsGraphAnalyzer.limitThreshold)
);
if (limitIndex > lastIndex) {
limitIndex = lastIndex;
}
}
return limitIndex;
}
/**
* @param {Program} astTree
* @returns {ICallsGraphData[]}
*/
public analyze (astTree: ESTree.Program): ICallsGraphData[] {
return this.analyzeRecursive(astTree.body);
}
/**
* @param {NodeGuards[]} blockScopeBody
* @returns {ICallsGraphData[]}
*/
private analyzeRecursive (blockScopeBody: ESTree.Node[]): ICallsGraphData[] {
const limitIndex: number = CallsGraphAnalyzer.getLimitIndex(blockScopeBody.length);
const callsGraphData: ICallsGraphData[] = [];
const blockScopeBodyLength: number = blockScopeBody.length;
for (let index: number = 0; index < blockScopeBodyLength; index++) {
if (index > limitIndex) {
break;
}
const blockScopeBodyNode: ESTree.Node = blockScopeBody[index];
estraverse.traverse(blockScopeBodyNode, {
enter: (node: ESTree.Node): estraverse.VisitorOption | void => {
if (!NodeGuards.isCallExpressionNode(node)) {
return;
}
if (blockScopeBodyNode.parentNode !== NodeStatementUtils.getParentNodeWithStatements(node)) {
return estraverse.VisitorOption.Skip;
}
this.analyzeCallExpressionNode(callsGraphData, blockScopeBody, node);
}
});
}
return callsGraphData;
}
/**
* @param {ICallsGraphData[]} callsGraphData
* @param {NodeGuards[]} blockScopeBody
* @param {CallExpression} callExpressionNode
*/
private analyzeCallExpressionNode (
callsGraphData: ICallsGraphData[],
blockScopeBody: ESTree.Node[],
callExpressionNode: ESTree.CallExpression
): void {
CallsGraphAnalyzer.calleeDataExtractorsList.forEach((calleeDataExtractorName: CalleeDataExtractor) => {
const calleeData: ICalleeData | null = this.calleeDataExtractorFactory(calleeDataExtractorName)
.extract(blockScopeBody, callExpressionNode.callee);
if (!calleeData) {
return;
}
callsGraphData.push({
...calleeData,
callsGraph: this.analyzeRecursive(calleeData.callee.body)
});
});
}
}
@@ -0,0 +1,16 @@
import { injectable } from 'inversify';
import * as ESTree from 'estree';
import { ICalleeData } from '../../../interfaces/analyzers/calls-graph-analyzer/ICalleeData';
import { ICalleeDataExtractor } from '../../../interfaces/analyzers/calls-graph-analyzer/ICalleeDataExtractor';
@injectable()
export abstract class AbstractCalleeDataExtractor implements ICalleeDataExtractor {
/**
* @param {Node[]} blockScopeBody
* @param {Node} callee
* @returns {ICalleeData}
*/
public abstract extract (blockScopeBody: ESTree.Node[], callee: ESTree.Node): ICalleeData | null;
}
@@ -0,0 +1,59 @@
import { injectable } from 'inversify';
import * as estraverse from 'estraverse';
import * as ESTree from 'estree';
import { ICalleeData } from '../../../interfaces/analyzers/calls-graph-analyzer/ICalleeData';
import { AbstractCalleeDataExtractor } from './AbstractCalleeDataExtractor';
import { NodeGuards } from '../../../node/NodeGuards';
import { NodeStatementUtils } from '../../../node/NodeStatementUtils';
@injectable()
export class FunctionDeclarationCalleeDataExtractor extends AbstractCalleeDataExtractor {
/**
* @param {NodeGuards[]} blockScopeBody
* @param {Identifier} callee
* @returns {ICalleeData}
*/
public extract (blockScopeBody: ESTree.Node[], callee: ESTree.Identifier): ICalleeData | null {
if (!NodeGuards.isIdentifierNode(callee)) {
return null;
}
const calleeBlockStatement: ESTree.BlockStatement | null = this.getCalleeBlockStatement(
NodeStatementUtils.getParentNodeWithStatements(blockScopeBody[0]),
callee.name
);
if (!calleeBlockStatement) {
return null;
}
return {
callee: calleeBlockStatement,
name: callee.name
};
}
/**
* @param {NodeGuards} targetNode
* @param {string} name
* @returns {BlockStatement}
*/
private getCalleeBlockStatement (targetNode: ESTree.Node, name: string): ESTree.BlockStatement | null {
let calleeBlockStatement: ESTree.BlockStatement | null = null;
estraverse.traverse(targetNode, {
enter: (node: ESTree.Node): estraverse.VisitorOption | void => {
if (NodeGuards.isFunctionDeclarationNode(node) && node.id.name === name) {
calleeBlockStatement = node.body;
return estraverse.VisitorOption.Break;
}
}
});
return calleeBlockStatement;
}
}
@@ -0,0 +1,70 @@
import { injectable } from 'inversify';
import * as estraverse from 'estraverse';
import * as ESTree from 'estree';
import { ICalleeData } from '../../../interfaces/analyzers/calls-graph-analyzer/ICalleeData';
import { AbstractCalleeDataExtractor } from './AbstractCalleeDataExtractor';
import { NodeGuards } from '../../../node/NodeGuards';
import { NodeStatementUtils } from '../../../node/NodeStatementUtils';
@injectable()
export class FunctionExpressionCalleeDataExtractor extends AbstractCalleeDataExtractor {
/**
* @param {NodeGuards[]} blockScopeBody
* @param {Identifier} callee
* @returns {ICalleeData}
*/
public extract (blockScopeBody: ESTree.Node[], callee: ESTree.Identifier | ESTree.FunctionExpression): ICalleeData | null {
let calleeName: string | null = null;
let calleeBlockStatement: ESTree.BlockStatement | null = null;
if (NodeGuards.isIdentifierNode(callee)) {
calleeName = callee.name;
calleeBlockStatement = this.getCalleeBlockStatement(
NodeStatementUtils.getParentNodeWithStatements(blockScopeBody[0]),
callee.name
);
} else if (NodeGuards.isFunctionExpressionNode(callee)) {
calleeName = null;
calleeBlockStatement = callee.body;
}
if (!calleeBlockStatement) {
return null;
}
return {
callee: calleeBlockStatement,
name: calleeName
};
}
/**
* @param {NodeGuards} targetNode
* @param {string} name
* @returns {BlockStatement}
*/
private getCalleeBlockStatement (targetNode: ESTree.Node, name: string): ESTree.BlockStatement | null {
let calleeBlockStatement: ESTree.BlockStatement | null = null;
estraverse.traverse(targetNode, {
enter: (node: ESTree.Node, parentNode: ESTree.Node | null): estraverse.VisitorOption | void => {
if (
NodeGuards.isFunctionExpressionNode(node) &&
parentNode &&
NodeGuards.isVariableDeclaratorNode(parentNode) &&
NodeGuards.isIdentifierNode(parentNode.id) &&
parentNode.id.name === name
) {
calleeBlockStatement = node.body;
return estraverse.VisitorOption.Break;
}
}
});
return calleeBlockStatement;
}
}
@@ -0,0 +1,177 @@
import { injectable } from 'inversify';
import * as estraverse from 'estraverse';
import * as ESTree from 'estree';
import { TObjectMembersCallsChain } from '../../../types/analyzers/calls-graph-analyzer/TObjectMembersCallsChain';
import { ICalleeData } from '../../../interfaces/analyzers/calls-graph-analyzer/ICalleeData';
import { AbstractCalleeDataExtractor } from './AbstractCalleeDataExtractor';
import { NodeGuards } from '../../../node/NodeGuards';
import { NodeStatementUtils } from '../../../node/NodeStatementUtils';
@injectable()
export class ObjectExpressionCalleeDataExtractor extends AbstractCalleeDataExtractor {
/**
* @param {Property} propertyNode
* @param {string | number} nextItemInCallsChain
* @returns {boolean}
*/
private static isValidTargetPropertyNode (propertyNode: ESTree.Property, nextItemInCallsChain: string | number): boolean {
if (!propertyNode.key) {
return false;
}
const isTargetPropertyNodeWithIdentifierKey: boolean =
NodeGuards.isIdentifierNode(propertyNode.key) && propertyNode.key.name === nextItemInCallsChain;
const isTargetPropertyNodeWithLiteralKey: boolean =
NodeGuards.isLiteralNode(propertyNode.key) &&
Boolean(propertyNode.key.value) &&
propertyNode.key.value === nextItemInCallsChain;
return isTargetPropertyNodeWithIdentifierKey || isTargetPropertyNodeWithLiteralKey;
}
/**
* @param {NodeGuards[]} blockScopeBody
* @param {MemberExpression} callee
* @returns {ICalleeData}
*/
public extract (blockScopeBody: ESTree.Node[], callee: ESTree.MemberExpression): ICalleeData | null {
if (!NodeGuards.isMemberExpressionNode(callee)) {
return null;
}
const objectMembersCallsChain: TObjectMembersCallsChain = this.createObjectMembersCallsChain([], callee);
if (!objectMembersCallsChain.length) {
return null;
}
const functionExpressionName: string | number | null = objectMembersCallsChain[objectMembersCallsChain.length - 1];
const calleeBlockStatement: ESTree.BlockStatement | null = this.getCalleeBlockStatement(
NodeStatementUtils.getParentNodeWithStatements(blockScopeBody[0]),
objectMembersCallsChain
);
if (!calleeBlockStatement) {
return null;
}
return {
callee: calleeBlockStatement,
name: functionExpressionName
};
}
/**
* Creates array with MemberExpression calls chain.
*
* Example: object.foo.bar(); // ['object', 'foo', 'bar']
*
* @param {TObjectMembersCallsChain} currentChain
* @param {MemberExpression} memberExpression
* @returns {TObjectMembersCallsChain}
*/
private createObjectMembersCallsChain (
currentChain: TObjectMembersCallsChain,
memberExpression: ESTree.MemberExpression
): TObjectMembersCallsChain {
// first step: processing memberExpression `property` property
if (NodeGuards.isIdentifierNode(memberExpression.property) && !memberExpression.computed) {
currentChain.unshift(memberExpression.property.name);
} else if (
NodeGuards.isLiteralNode(memberExpression.property) &&
(
typeof memberExpression.property.value === 'string' ||
typeof memberExpression.property.value === 'number'
)
) {
currentChain.unshift(memberExpression.property.value);
} else {
return currentChain;
}
// second step: processing memberExpression `object` property
if (NodeGuards.isMemberExpressionNode(memberExpression.object)) {
return this.createObjectMembersCallsChain(currentChain, memberExpression.object);
} else if (NodeGuards.isIdentifierNode(memberExpression.object)) {
currentChain.unshift(memberExpression.object.name);
}
return currentChain;
}
/**
* @param {NodeGuards} targetNode
* @param {TObjectMembersCallsChain} objectMembersCallsChain
* @returns {BlockStatement}
*/
private getCalleeBlockStatement (
targetNode: ESTree.Node,
objectMembersCallsChain: TObjectMembersCallsChain
): ESTree.BlockStatement | null {
const objectName: string | number | undefined = objectMembersCallsChain.shift();
if (!objectName) {
return null;
}
let calleeBlockStatement: ESTree.BlockStatement | null = null;
estraverse.traverse(targetNode, {
enter: (node: ESTree.Node): estraverse.VisitorOption | void => {
if (
NodeGuards.isVariableDeclaratorNode(node) &&
NodeGuards.isIdentifierNode(node.id) &&
node.init &&
NodeGuards.isObjectExpressionNode(node.init) &&
node.id.name === objectName
) {
calleeBlockStatement = this.findCalleeBlockStatement(node.init.properties, objectMembersCallsChain);
return estraverse.VisitorOption.Break;
}
}
});
return calleeBlockStatement;
}
/**
* @param {Property[]} objectExpressionProperties
* @param {TObjectMembersCallsChain} objectMembersCallsChain
* @returns {BlockStatement}
*/
private findCalleeBlockStatement (
objectExpressionProperties: (ESTree.Property | ESTree.SpreadElement)[],
objectMembersCallsChain: TObjectMembersCallsChain
): ESTree.BlockStatement | null {
const nextItemInCallsChain: string | number | undefined = objectMembersCallsChain.shift();
if (!nextItemInCallsChain) {
return null;
}
for (const propertyNode of objectExpressionProperties) {
if (!NodeGuards.isPropertyNode(propertyNode)) {
continue;
}
if (!ObjectExpressionCalleeDataExtractor.isValidTargetPropertyNode(propertyNode, nextItemInCallsChain)) {
continue;
}
if (NodeGuards.isObjectExpressionNode(propertyNode.value)) {
return this.findCalleeBlockStatement(propertyNode.value.properties, objectMembersCallsChain);
}
if (NodeGuards.isFunctionExpressionNode(propertyNode.value)) {
return propertyNode.value.body;
}
}
return null;
}
}
@@ -0,0 +1,130 @@
import { injectable, inject } from 'inversify';
import { TNumberNumericalExpressionData } from '../../types/analyzers/number-numerical-expression-analyzer/TNumberNumericalExpressionData';
import { INumberNumericalExpressionAnalyzer } from '../../interfaces/analyzers/number-numerical-expression-analyzer/INumberNumericalExpressionAnalyzer';
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import { NumberUtils } from '../../utils/NumberUtils';
/**
* Based on https://gist.github.com/da411d/0e59f79dcf4603cdabf0024a10eeb6fe
*/
@injectable()
export class NumberNumericalExpressionAnalyzer implements INumberNumericalExpressionAnalyzer {
/**
* @type {number}
*/
private static readonly additionalParts: number = 3;
/**
* @type {Map<number, number[]>}
*/
private readonly numberFactorsMap: Map<number, number[]> = new Map();
/**
* @type {IRandomGenerator}
*/
private readonly randomGenerator: IRandomGenerator;
/**
* @param {IRandomGenerator} randomGenerator
*/
public constructor (
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator
) {
this.randomGenerator = randomGenerator;
}
/**
* @param {number} number
* @returns {TNumberNumericalExpressionData}
*/
public analyze (number: number): TNumberNumericalExpressionData {
if (isNaN(number)) {
throw new Error('Given value is NaN');
}
if (NumberUtils.isUnsafeNumber(number)) {
return [number];
}
const additionParts: number[] = this.generateAdditionParts(number);
return additionParts.map((addition: number) => this.mixWithMultiplyParts(addition));
}
/**
* @param {number} number
* @returns {number[]}
*/
private generateAdditionParts (number: number): number[] {
const additionParts = [];
const upperNumberLimit: number = Math.min(Math.abs(number * 2), Number.MAX_SAFE_INTEGER);
const from: number = Math.min(-10000, -upperNumberLimit);
const to: number = Math.max(10000, upperNumberLimit);
let temporarySum = 0;
for (let i = 0; i < NumberNumericalExpressionAnalyzer.additionalParts; i++) {
if (i < NumberNumericalExpressionAnalyzer.additionalParts - 1) {
// trailing parts
let addition: number = this.randomGenerator.getRandomInteger(from, to);
const isUnsafeCombination: boolean = NumberUtils.isUnsafeNumber(temporarySum + addition);
// we have to flip sign if total expression sum overflows over safe integer limits
if (isUnsafeCombination) {
addition = -addition;
}
additionParts.push(addition);
temporarySum += addition;
} else {
const combination: number = number - temporarySum;
const isUnsafeCombination: boolean = NumberUtils.isUnsafeNumber(combination);
// last part
if (isUnsafeCombination) {
additionParts.push(0 - temporarySum);
additionParts.push(number);
} else {
additionParts.push(combination);
}
}
}
return additionParts;
}
/**
* @param {number} number
* @returns {number | number[]}
*/
private mixWithMultiplyParts (number: number): number | number[] {
const shouldMixWithMultiplyParts: boolean = this.randomGenerator.getMathRandom() > 0.5;
if (!shouldMixWithMultiplyParts || number === 0) {
return number;
}
let factors: number[] | null = this.numberFactorsMap.get(number) ?? null;
if (!factors) {
factors = NumberUtils.getFactors(number);
this.numberFactorsMap.set(number, factors);
}
if (!factors.length) {
return number;
}
const factor: number = factors[this.randomGenerator.getRandomInteger(0, factors.length - 1)];
return [factor, number / factor];
}
}
@@ -0,0 +1,61 @@
import { inject, injectable, } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import * as estraverse from 'estraverse';
import * as ESTree from 'estree';
import { IArrayUtils } from '../../interfaces/utils/IArrayUtils';
import { IPrevailingKindOfVariablesAnalyzer } from '../../interfaces/analyzers/calls-graph-analyzer/IPrevailingKindOfVariablesAnalyzer';
import { NodeGuards } from '../../node/NodeGuards';
@injectable()
export class PrevailingKindOfVariablesAnalyzer implements IPrevailingKindOfVariablesAnalyzer {
/**
* @type {ESTree.VariableDeclaration['kind']}
*/
private static readonly defaultKindOfVariables: ESTree.VariableDeclaration['kind'] = 'var';
/**
* @type {IArrayUtils}
*/
private readonly arrayUtils: IArrayUtils;
/**
* @type {ESTree.VariableDeclaration['kind']}
*/
private prevailingKindOfVariables: ESTree.VariableDeclaration['kind'] = PrevailingKindOfVariablesAnalyzer.defaultKindOfVariables;
public constructor (
@inject(ServiceIdentifiers.IArrayUtils) arrayUtils: IArrayUtils
) {
this.arrayUtils = arrayUtils;
}
/**
* @param {Program} astTree
*/
public analyze (astTree: ESTree.Program): void {
const variableKinds: ESTree.VariableDeclaration['kind'][] = [];
estraverse.traverse(astTree, {
enter: (node: ESTree.Node): estraverse.VisitorOption | void => {
if (!NodeGuards.isVariableDeclarationNode(node)) {
return;
}
variableKinds.push(node.kind);
}
});
this.prevailingKindOfVariables = this.arrayUtils.findMostOccurringElement(variableKinds)
?? PrevailingKindOfVariablesAnalyzer.defaultKindOfVariables;
}
/**
* @returns {VariableDeclaration["kind"]}
*/
public getPrevailingKind (): ESTree.VariableDeclaration['kind'] {
return this.prevailingKindOfVariables;
}
}
@@ -0,0 +1,152 @@
import { injectable, } from 'inversify';
import * as eslintScope from 'eslint-scope';
import * as estraverse from 'estraverse';
import * as ESTree from 'estree';
import { IScopeAnalyzer } from '../../interfaces/analyzers/scope-analyzer/IScopeAnalyzer';
import { ecmaVersion } from '../../constants/EcmaVersion';
import { NodeGuards } from '../../node/NodeGuards';
@injectable()
export class ScopeAnalyzer implements IScopeAnalyzer {
/**
* @type {eslintScope.AnalysisOptions}
*/
private static readonly eslintScopeOptions: eslintScope.AnalysisOptions = {
ecmaVersion,
optimistic: true
};
/**
* @type {acorn.Options['sourceType'][]}
*/
private static readonly sourceTypes: acorn.Options['sourceType'][] = [
'script',
'module'
];
/**
* @type {number}
*/
private static readonly emptyRangeValue: number = 0;
/**
* @type {eslintScope.ScopeManager | null}
*/
private scopeManager: eslintScope.ScopeManager | null = null;
/**
* `eslint-scope` reads `ranges` property of a nodes
* Should attach that property to the some custom nodes
*
* @param {Node} astTree
*/
private static attachMissingRanges (astTree: ESTree.Node): void {
estraverse.replace(astTree, {
enter: (node: ESTree.Node, parentNode: ESTree.Node | null): ESTree.Node => {
if (!node.range) {
node.range = [
parentNode?.range?.[0] ?? ScopeAnalyzer.emptyRangeValue,
parentNode?.range?.[1] ?? ScopeAnalyzer.emptyRangeValue
];
}
return node;
}
});
}
/**
* @param {Node} node
* @returns {boolean}
*/
private static isRootNode (node: ESTree.Node): boolean {
return NodeGuards.isProgramNode(node) || node.parentNode === node;
}
/**
* @param {Program} astTree
*/
public analyze (astTree: ESTree.Node): void {
const sourceTypeLength: number = ScopeAnalyzer.sourceTypes.length;
ScopeAnalyzer.attachMissingRanges(astTree);
for (let i: number = 0; i < sourceTypeLength; i++) {
try {
this.scopeManager = eslintScope.analyze(astTree, {
...ScopeAnalyzer.eslintScopeOptions,
sourceType: ScopeAnalyzer.sourceTypes[i]
});
return;
} catch (error) {
if (i < sourceTypeLength - 1) {
continue;
}
throw new Error(error);
}
}
throw new Error('Scope analyzing error');
}
/**
* @param {Node} node
* @returns {Scope}
*/
public acquireScope (node: ESTree.Node): eslintScope.Scope {
if (!this.scopeManager) {
throw new Error('Scope manager is not defined');
}
const scope: eslintScope.Scope | null = this.scopeManager.acquire(
node,
ScopeAnalyzer.isRootNode(node)
);
if (!scope) {
throw new Error('Cannot acquire scope for node');
}
this.sanitizeScopes(scope);
return scope;
}
/**
* @param {Scope} scope
*/
private sanitizeScopes (scope: eslintScope.Scope): void {
scope.childScopes.forEach((childScope: eslintScope.Scope) => {
// fix of class scopes
// trying to move class scope references to the parent scope
if (childScope.type === 'class' && childScope.upper) {
if (!childScope.variables.length) {
return;
}
// class name variable is always first
const classNameVariable: eslintScope.Variable = childScope.variables[0];
const upperVariable: eslintScope.Variable | undefined = childScope.upper.variables
.find((variable: eslintScope.Variable) => {
const isValidClassNameVariable: boolean = classNameVariable.defs
.some((definition: eslintScope.Definition) => definition.type === 'ClassName');
return isValidClassNameVariable && variable.name === classNameVariable.name;
});
upperVariable?.references.push(...childScope.variables[0].references);
}
});
for (const childScope of scope.childScopes) {
this.sanitizeScopes(childScope);
}
}
}
@@ -0,0 +1,134 @@
import { inject, injectable, } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import * as estraverse from 'estraverse';
import * as ESTree from 'estree';
import { IOptions } from '../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
import { IStringArrayStorage } from '../../interfaces/storages/string-array-transformers/IStringArrayStorage';
import { IStringArrayStorageAnalyzer } from '../../interfaces/analyzers/string-array-storage-analyzer/IStringArrayStorageAnalyzer';
import { IStringArrayStorageItemData } from '../../interfaces/storages/string-array-transformers/IStringArrayStorageItem';
import { NodeGuards } from '../../node/NodeGuards';
import { NodeLiteralUtils } from '../../node/NodeLiteralUtils';
import { NodeMetadata } from '../../node/NodeMetadata';
/**
* Adds values of literal nodes to the string array storage
*/
@injectable()
export class StringArrayStorageAnalyzer implements IStringArrayStorageAnalyzer {
/**
* @type {number}
*/
private static readonly minimumLengthForStringArray: number = 3;
/**
* @type {IOptions}
*/
private readonly options: IOptions;
/**
* @type {randomGenerator}
*/
private readonly randomGenerator: IRandomGenerator;
/**
* @type {IStringArrayStorage}
*/
private readonly stringArrayStorage: IStringArrayStorage;
/**
* @type {Map<ESTree.Literal, IStringArrayStorageItemData>}
*/
private readonly stringArrayStorageData: Map<ESTree.Literal, IStringArrayStorageItemData> = new Map();
/**
* @param {IStringArrayStorage} stringArrayStorage
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
*/
public constructor (
@inject(ServiceIdentifiers.IStringArrayStorage) stringArrayStorage: IStringArrayStorage,
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions,
) {
this.stringArrayStorage = stringArrayStorage;
this.randomGenerator = randomGenerator;
this.options = options;
}
/**
* @param {Program} astTree
*/
public analyze (astTree: ESTree.Program): void {
if (!this.options.stringArray) {
return;
}
estraverse.traverse(astTree, {
enter: (node: ESTree.Node, parentNode: ESTree.Node | null): estraverse.VisitorOption | void => {
if (!parentNode) {
return;
}
if (NodeMetadata.isIgnoredNode(node)) {
return estraverse.VisitorOption.Skip;
}
if (!NodeGuards.isLiteralNode(node)) {
return;
}
this.analyzeLiteralNode(node, parentNode);
}
});
}
/**
* @param {Literal} literalNode
* @returns {IStringArrayStorageItemData | undefined}
*/
public getItemDataForLiteralNode (literalNode: ESTree.Literal): IStringArrayStorageItemData | undefined {
return this.stringArrayStorageData.get(literalNode);
}
/**
* @param {Literal} literalNode
* @param {Node} parentNode
*/
private analyzeLiteralNode (literalNode: ESTree.Literal, parentNode: ESTree.Node): void {
if (!NodeLiteralUtils.isStringLiteralNode(literalNode)) {
return;
}
if (NodeLiteralUtils.isProhibitedLiteralNode(literalNode, parentNode)) {
return;
}
if (!this.shouldAddValueToStringArray(literalNode)) {
return;
}
this.stringArrayStorageData.set(
literalNode,
this.stringArrayStorage.getOrThrow(literalNode.value)
);
}
/**
* @param {(SimpleLiteral & {value: string})} literalNode
* @returns {boolean}
*/
private shouldAddValueToStringArray (literalNode: ESTree.Literal & {value: string}): boolean {
const isForceTransformNode: boolean = NodeMetadata.isForceTransformNode(literalNode);
if (isForceTransformNode) {
return true;
}
return literalNode.value.length >= StringArrayStorageAnalyzer.minimumLengthForStringArray
&& this.randomGenerator.getMathRandom() <= this.options.stringArrayThreshold;
}
}
+521
View File
@@ -0,0 +1,521 @@
/* eslint-disable max-lines */
import * as commander from 'commander';
import * as path from 'path';
import { TInputCLIOptions } from '../types/options/TInputCLIOptions';
import { TInputOptions } from '../types/options/TInputOptions';
import { IFileData } from '../interfaces/cli/IFileData';
import { IInitializable } from '../interfaces/IInitializable';
import { IObfuscatedCode } from '../interfaces/source-code/IObfuscatedCode';
import { initializable } from '../decorators/Initializable';
import { IdentifierNamesGenerator } from '../enums/generators/identifier-names-generators/IdentifierNamesGenerator';
import { LoggingPrefix } from '../enums/logger/LoggingPrefix';
import { ObfuscationTarget } from '../enums/ObfuscationTarget';
import { OptionsPreset } from '../enums/options/presets/OptionsPreset';
import { SourceMapMode } from '../enums/source-map/SourceMapMode';
import { StringArrayEncoding } from '../enums/node-transformers/string-array-transformers/StringArrayEncoding';
import { StringArrayWrappersType } from '../enums/node-transformers/string-array-transformers/StringArrayWrappersType';
import { DEFAULT_PRESET } from '../options/presets/Default';
import { ArraySanitizer } from './sanitizers/ArraySanitizer';
import { BooleanSanitizer } from './sanitizers/BooleanSanitizer';
import { CLIUtils } from './utils/CLIUtils';
import { JavaScriptObfuscator } from '../JavaScriptObfuscatorFacade';
import { Logger } from '../logger/Logger';
import { ObfuscatedCodeWriter } from './utils/ObfuscatedCodeWriter';
import { SourceCodeReader } from './utils/SourceCodeReader';
import { Utils } from '../utils/Utils';
import { StringArrayIndexesType } from '../enums/node-transformers/string-array-transformers/StringArrayIndexesType';
export class JavaScriptObfuscatorCLI implements IInitializable {
/**
* @type {string[]}
*/
public static readonly availableInputExtensions: string[] = [
'.js'
];
/**
* @type {BufferEncoding}
*/
public static readonly encoding: BufferEncoding = 'utf8';
/**
* @type {string}
*/
public static readonly obfuscatedFilePrefix: string = '-obfuscated';
/**
* @type {commander.CommanderStatic}
*/
@initializable()
private commands!: commander.CommanderStatic;
/**
* @type {TInputCLIOptions}
*/
@initializable()
private inputCLIOptions!: TInputCLIOptions;
/**
* @type {string}
*/
@initializable()
private inputPath!: string;
/**
* @type {SourceCodeReader}
*/
@initializable()
private sourceCodeReader!: SourceCodeReader;
/**
* @type {ObfuscatedCodeWriter}
*/
@initializable()
private obfuscatedCodeWriter!: ObfuscatedCodeWriter;
/**
* @type {string[]}
*/
private readonly arguments: string[];
/**
* @type {string[]}
*/
private readonly rawArguments: string[];
/**
* @param {string[]} argv
*/
public constructor (argv: string[]) {
this.rawArguments = argv;
this.arguments = argv.slice(2);
}
/**
* @param {TInputCLIOptions} inputOptions
* @returns {TInputOptions}
*/
private static buildOptions (inputOptions: TInputCLIOptions): TInputOptions {
const inputCLIOptions: TInputOptions = JavaScriptObfuscatorCLI.filterOptions(inputOptions);
const configFilePath: string | undefined = inputOptions.config;
const configFileLocation: string = configFilePath ? path.resolve(configFilePath, '.') : '';
const configFileOptions: TInputOptions = configFileLocation ? CLIUtils.getUserConfig(configFileLocation) : {};
return {
...DEFAULT_PRESET,
...configFileOptions,
...inputCLIOptions
};
}
/**
* @param {TObject} options
* @returns {TInputOptions}
*/
private static filterOptions (options: TInputCLIOptions): TInputOptions {
const filteredOptions: TInputOptions = {};
Object
.keys(options)
.forEach((option: keyof TInputCLIOptions) => {
if (options[option] === undefined) {
return;
}
filteredOptions[option] = options[option];
});
return filteredOptions;
}
public initialize (): void {
this.inputPath = path.normalize(this.arguments[0] || '');
this.commands = <commander.CommanderStatic>(new commander.Command());
this.configureCommands();
this.configureHelp();
this.inputCLIOptions = JavaScriptObfuscatorCLI.buildOptions(this.commands.opts());
this.sourceCodeReader = new SourceCodeReader(
this.inputPath,
this.inputCLIOptions
);
this.obfuscatedCodeWriter = new ObfuscatedCodeWriter(
this.inputPath,
this.inputCLIOptions
);
}
public run (): void {
const canShowHelp: boolean = !this.arguments.length || this.arguments.includes('--help');
if (canShowHelp) {
this.commands.outputHelp();
return;
}
const sourceCodeData: IFileData[] = this.sourceCodeReader.readSourceCode();
this.processSourceCodeData(sourceCodeData);
}
private configureCommands (): void {
this.commands
.usage('<inputPath> [options]')
.version(
Utils.buildVersionMessage(process.env.VERSION, process.env.BUILD_TIMESTAMP),
'-v, --version'
)
.option(
'-o, --output <path>',
'Output path for obfuscated code'
)
.option(
'--compact <boolean>',
'Disable one line output code compacting',
BooleanSanitizer
)
.option(
'--config <boolean>',
'Name of js / json config file'
)
.option(
'--control-flow-flattening <boolean>',
'Enables control flow flattening',
BooleanSanitizer
)
.option(
'--control-flow-flattening-threshold <number>',
'The probability that the control flow flattening transformation will be applied to the node',
parseFloat
)
.option(
'--dead-code-injection <boolean>',
'Enables dead code injection',
BooleanSanitizer
)
.option(
'--dead-code-injection-threshold <number>',
'The probability that the dead code injection transformation will be applied to the node',
parseFloat
)
.option(
'--debug-protection <boolean>',
'Disable browser Debug panel (can cause DevTools enabled browser freeze)',
BooleanSanitizer
)
.option(
'--debug-protection-interval <boolean>',
'Disable browser Debug panel even after page was loaded (can cause DevTools enabled browser freeze)',
BooleanSanitizer
)
.option(
'--disable-console-output <boolean>',
'Allow console.log, console.info, console.error and console.warn messages output into browser console',
BooleanSanitizer
)
.option(
'--domain-lock <list> (comma separated, without whitespaces)',
'Allows to run the obfuscated source code only on specific domains and/or sub-domains (comma separated)',
ArraySanitizer
)
.option(
'--exclude <list> (comma separated, without whitespaces)',
'A filename or glob which indicates files to exclude from obfuscation',
ArraySanitizer
)
.option(
'--force-transform-strings <list> (comma separated, without whitespaces)',
'Enables force transformation of string literals, which being matched by passed RegExp patterns (comma separated)',
ArraySanitizer
)
.option(
'--identifier-names-generator <string>',
'Sets identifier names generator. ' +
`Values: ${CLIUtils.stringifyOptionAvailableValues(IdentifierNamesGenerator)}. ` +
`Default: ${IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator}`
)
.option(
'--identifiers-prefix <string>',
'Sets prefix for all global identifiers'
)
.option(
'--identifiers-dictionary <list> (comma separated, without whitespaces)',
'Identifiers dictionary (comma separated) for `--identifier-names-generator dictionary` option',
ArraySanitizer
)
.option(
'--ignore-require-imports <boolean>', 'Prevents obfuscation of `require` imports',
BooleanSanitizer
)
.option(
'--log <boolean>', 'Enables logging of the information to the console',
BooleanSanitizer
)
.option(
'--numbers-to-expressions <boolean>', 'Enables numbers conversion to expressions',
BooleanSanitizer
)
.option(
'--options-preset <string>',
'Allows to set options preset. ' +
`Values: ${CLIUtils.stringifyOptionAvailableValues(OptionsPreset)}. ` +
`Default: ${OptionsPreset.Default}`
)
.option(
'--reserved-names <list> (comma separated, without whitespaces)',
'Disables obfuscation and generation of identifiers, which being matched by passed RegExp patterns (comma separated)',
ArraySanitizer
)
.option(
'--reserved-strings <list> (comma separated, without whitespaces)',
'Disables transformation of string literals, which being matched by passed RegExp patterns (comma separated)',
ArraySanitizer
)
.option(
'--rename-globals <boolean>', 'Allows to enable obfuscation of global variable and function names with declaration',
BooleanSanitizer
)
.option(
'--rename-properties <boolean>', 'UNSAFE: Enables renaming of property names. This probably WILL break your code',
BooleanSanitizer
)
.option(
'--rotate-string-array <boolean>', 'Enable rotation of string array values during obfuscation',
BooleanSanitizer
)
.option(
'--seed <string|number>',
'Sets seed for random generator. This is useful for creating repeatable results.',
parseFloat
)
.option(
'--self-defending <boolean>',
'Disables self-defending for obfuscated code',
BooleanSanitizer
)
.option(
'--shuffle-string-array <boolean>', 'Randomly shuffles string array items',
BooleanSanitizer
)
.option(
'--simplify <boolean>', 'Enables additional code obfuscation through simplification',
BooleanSanitizer
)
.option(
'--source-map <boolean>',
'Enables source map generation',
BooleanSanitizer
)
.option(
'--source-map-base-url <string>',
'Sets base url to the source map import url when `--source-map-mode=separate`'
)
.option(
'--source-map-file-name <string>',
'Sets file name for output source map when `--source-map-mode=separate`'
)
.option(
'--source-map-mode <string>',
'Specify source map output mode. ' +
`Values: ${CLIUtils.stringifyOptionAvailableValues(SourceMapMode)}. ` +
`Default: ${SourceMapMode.Separate}`
)
.option(
'--split-strings <boolean>',
'Splits literal strings into chunks with length of `splitStringsChunkLength` option value',
BooleanSanitizer
)
.option(
'--split-strings-chunk-length <number>',
'Sets chunk length of `splitStrings` option',
parseFloat
)
.option(
'--string-array <boolean>',
'Disables gathering of all literal strings into an array and replacing every literal string with an array call',
BooleanSanitizer
)
.option(
'--string-array-encoding <list> (comma separated, without whitespaces)',
'Encodes each string in strings array using base64 or rc4 (this option can slow down your code speed). ' +
`Values: ${CLIUtils.stringifyOptionAvailableValues(StringArrayEncoding)}. ` +
`Default: ${StringArrayEncoding.None}`,
ArraySanitizer
)
.option(
'--string-array-indexes-type <list> (comma separated, without whitespaces)',
'Encodes each string in strings array using base64 or rc4 (this option can slow down your code speed). ' +
`Values: ${CLIUtils.stringifyOptionAvailableValues(StringArrayIndexesType)}. ` +
`Default: ${StringArrayIndexesType.HexadecimalNumber}`,
ArraySanitizer
)
.option(
'--string-array-index-shift <boolean>',
'Enables additional index shift for all string array calls',
BooleanSanitizer
)
.option(
'--string-array-wrappers-count <number>',
'Sets the count of wrappers for the string array inside each root or function scope',
parseInt
)
.option(
'--string-array-wrappers-chained-calls <boolean>',
'Enables the chained calls between string array wrappers',
BooleanSanitizer
)
.option(
'--string-array-wrappers-parameters-max-count <number>',
'Allows to control the maximum number of string array wrappers parameters',
parseInt
)
.option(
'--string-array-wrappers-type <string>',
'Allows to select a type of the wrappers that are appending by the `--string-array-wrappers-count` option. ' +
`Values: ${CLIUtils.stringifyOptionAvailableValues(StringArrayWrappersType)}. ` +
`Default: ${StringArrayWrappersType.Variable}`
)
.option(
'--string-array-threshold <number>',
'The probability that the literal string will be inserted into stringArray (Default: 0.8, Min: 0, Max: 1)',
parseFloat
)
.option(
'--target <string>',
'Allows to set target environment for obfuscated code. ' +
`Values: ${CLIUtils.stringifyOptionAvailableValues(ObfuscationTarget)}. ` +
`Default: ${ObfuscationTarget.Browser}`
)
.option(
'--transform-object-keys <boolean>',
'Enables transformation of object keys',
BooleanSanitizer
)
.option(
'--unicode-escape-sequence <boolean>',
'Allows to enable/disable string conversion to unicode escape sequence',
BooleanSanitizer
)
.parse(this.rawArguments);
}
private configureHelp (): void {
this.commands.on('--help', () => {
console.log(' Examples:\n');
console.log(' %> javascript-obfuscator input_file_name.js --compact true --self-defending false');
console.log(' %> javascript-obfuscator input_file_name.js --output output_file_name.js --compact true --self-defending false');
console.log(' %> javascript-obfuscator input_directory_name --compact true --self-defending false');
console.log('');
});
}
/**
* @param {IFileData[]} sourceCodeData
*/
private processSourceCodeData (sourceCodeData: IFileData[]): void {
sourceCodeData.forEach(({ filePath, content }: IFileData, index: number) => {
const outputCodePath: string = this.obfuscatedCodeWriter.getOutputCodePath(filePath);
try {
Logger.log(
Logger.colorInfo,
LoggingPrefix.CLI,
`Obfuscating file: ${filePath}...`
);
this.processSourceCode(content, filePath, outputCodePath, index);
} catch (error) {
Logger.log(
Logger.colorInfo,
LoggingPrefix.CLI,
`Error in file: ${filePath}...`
);
throw error;
}
});
}
/**
* @param {string} sourceCode
* @param {string} inputCodePath
* @param {string} outputCodePath
* @param {number | null} sourceCodeIndex
*/
private processSourceCode (
sourceCode: string,
inputCodePath: string,
outputCodePath: string,
sourceCodeIndex: number | null
): void {
const options: TInputOptions = {
...this.inputCLIOptions,
inputFileName: path.basename(inputCodePath),
...sourceCodeIndex !== null && {
identifiersPrefix: Utils.getIdentifiersPrefixForMultipleSources(
this.inputCLIOptions.identifiersPrefix,
sourceCodeIndex
)
}
};
if (options.sourceMap) {
this.processSourceCodeWithSourceMap(sourceCode, outputCodePath, options);
} else {
this.processSourceCodeWithoutSourceMap(sourceCode, outputCodePath, options);
}
}
/**
* @param {string} sourceCode
* @param {string} outputCodePath
* @param {TInputOptions} options
*/
private processSourceCodeWithoutSourceMap (
sourceCode: string,
outputCodePath: string,
options: TInputOptions
): void {
const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(sourceCode, options).getObfuscatedCode();
this.obfuscatedCodeWriter.writeFile(outputCodePath, obfuscatedCode);
}
/**
* @param {string} sourceCode
* @param {string} outputCodePath
* @param {TInputOptions} options
*/
private processSourceCodeWithSourceMap (
sourceCode: string,
outputCodePath: string,
options: TInputOptions
): void {
const outputSourceMapPath: string = this.obfuscatedCodeWriter.getOutputSourceMapPath(
outputCodePath,
options.sourceMapFileName ?? ''
);
options = {
...options,
sourceMapFileName: path.basename(outputSourceMapPath)
};
const obfuscatedCode: IObfuscatedCode = JavaScriptObfuscator.obfuscate(sourceCode, options);
this.obfuscatedCodeWriter.writeFile(outputCodePath, obfuscatedCode.getObfuscatedCode());
if (options.sourceMapMode === SourceMapMode.Separate && obfuscatedCode.getSourceMap()) {
this.obfuscatedCodeWriter.writeFile(outputSourceMapPath, obfuscatedCode.getSourceMap());
}
}
}
@@ -0,0 +1,13 @@
import { TCLISanitizer } from '../../types/cli/TCLISanitizer';
/**
* @param {string} value
* @returns {string[]}
*/
export const ArraySanitizer: TCLISanitizer <string[]> = (value: string): string[] => {
if (value.endsWith(',')) {
throw new SyntaxError('Multiple <list> values should be wrapped inside quotes: --option-name \'value1\',\'value2\'');
}
return value.split(',').map((string: string) => string.trim());
};
@@ -0,0 +1,9 @@
import { TCLISanitizer } from '../../types/cli/TCLISanitizer';
/**
* @param {string} value
* @returns {boolean}
*/
export const BooleanSanitizer: TCLISanitizer <boolean> = (value: string): boolean => {
return value === 'true' || value === '1';
};
+50
View File
@@ -0,0 +1,50 @@
import * as path from 'path';
import { TDictionary } from '../../types/TDictionary';
import { StringSeparator } from '../../enums/StringSeparator';
export class CLIUtils {
/**
* @type {string[]}
*/
public static readonly allowedConfigFileExtensions: string[] = [
'.js',
'.json'
];
/**
* @param {string} configPath
* @returns {TDictionary}
*/
public static getUserConfig (configPath: string): TDictionary {
let config: TDictionary;
const configFileExtension: string = path.extname(configPath);
const isValidExtension: boolean = CLIUtils.allowedConfigFileExtensions.includes(configFileExtension);
if (!isValidExtension) {
throw new ReferenceError('Given config path must be a valid `.js` or `.json` file path');
}
try {
config = require(configPath);
} catch {
try {
config = __non_webpack_require__(configPath);
} catch {
throw new ReferenceError(`Cannot open config file with path: ${configPath}`);
}
}
return config;
}
/**
* @param {TDictionary} optionEnum
* @returns {string}
*/
public static stringifyOptionAvailableValues (optionEnum: TDictionary): string {
return Object.values(optionEnum).join(`${StringSeparator.Comma} `);
}
}
@@ -0,0 +1,133 @@
import * as fs from 'fs';
import * as mkdirp from 'mkdirp';
import * as path from 'path';
import { TInputCLIOptions } from '../../types/options/TInputCLIOptions';
import { StringSeparator } from '../../enums/StringSeparator';
import { JavaScriptObfuscatorCLI } from '../JavaScriptObfuscatorCLI';
export class ObfuscatedCodeWriter {
/**
* @type {string}
*/
private readonly inputPath: string;
/**
* @type {TInputCLIOptions}
*/
private readonly options: TInputCLIOptions;
/**
* @param {string} inputPath
* @param {TInputCLIOptions} options
*/
public constructor (
inputPath: string,
options: TInputCLIOptions
) {
this.inputPath = path.normalize(inputPath);
this.options = options;
}
/**
* @param {string} filePath
* @returns {string}
*/
public getOutputCodePath (filePath: string): string {
const normalizedFilePath: string = path.normalize(filePath);
const normalizedRawOutputPath: string | null = this.options.output
? path.normalize(this.options.output)
: null;
if (!normalizedRawOutputPath) {
return normalizedFilePath
.split(StringSeparator.Dot)
.map((value: string, index: number) => {
return index === 0 ? `${value}${JavaScriptObfuscatorCLI.obfuscatedFilePrefix}` : value;
})
.join(StringSeparator.Dot);
}
const rawInputPathStats: fs.Stats = fs.lstatSync(this.inputPath);
const outputPathExtName: string = path.extname(normalizedRawOutputPath);
const isDirectoryRawInputPath: boolean = rawInputPathStats.isDirectory();
const isDirectoryRawOutputPath: boolean = !JavaScriptObfuscatorCLI
.availableInputExtensions
.includes(outputPathExtName);
if (isDirectoryRawInputPath) {
if (isDirectoryRawOutputPath) {
const parsedNormalizedFilePath: path.ParsedPath = path.parse(normalizedFilePath);
const baseOutputPath: string = path.join(
parsedNormalizedFilePath.dir.replace(this.inputPath, ''),
parsedNormalizedFilePath.base
);
return path.join(normalizedRawOutputPath, baseOutputPath);
} else {
throw new Error('Output path for directory obfuscation should be a directory path');
}
} else {
if (isDirectoryRawOutputPath) {
return path.join(normalizedRawOutputPath, path.basename(filePath));
} else {
return normalizedRawOutputPath;
}
}
}
/**
* @param {string} outputCodePath
* @param {string} sourceMapFileName
* @returns {string}
*/
public getOutputSourceMapPath (outputCodePath: string, sourceMapFileName: string = ''): string {
if (!outputCodePath) {
throw new Error('Output code path is empty');
}
let normalizedOutputCodePath: string = path.normalize(outputCodePath);
let parsedOutputCodePath: path.ParsedPath = path.parse(normalizedOutputCodePath);
if (!parsedOutputCodePath.ext && !sourceMapFileName) {
throw new Error('Source map file name should be set when output code path is a directory path');
}
if (sourceMapFileName) {
const indexOfLastSeparator: number = normalizedOutputCodePath.lastIndexOf(path.sep);
const sourceMapPath: string = parsedOutputCodePath.ext && indexOfLastSeparator > 0
? normalizedOutputCodePath.slice(0, indexOfLastSeparator)
: normalizedOutputCodePath;
// remove possible drive letter for win32 environment
const normalizedSourceMapFilePath: string = sourceMapFileName.replace(/^[a-zA-Z]:\\*/, '');
normalizedOutputCodePath = path.join(sourceMapPath, normalizedSourceMapFilePath);
}
if (!/\.js\.map$/.test(normalizedOutputCodePath)) {
parsedOutputCodePath = path.parse(normalizedOutputCodePath);
const outputCodePathWithoutExtension: string = path.join(parsedOutputCodePath.dir, parsedOutputCodePath.name);
normalizedOutputCodePath = `${outputCodePathWithoutExtension}.js.map`;
} else if (/\.js$/.test(normalizedOutputCodePath)) {
normalizedOutputCodePath += '.map';
}
return normalizedOutputCodePath;
}
/**
* @param {string} outputPath
* @param {string} data
*/
public writeFile (outputPath: string, data: string): void {
mkdirp.sync(path.dirname(outputPath));
fs.writeFileSync(outputPath, data, {
encoding: JavaScriptObfuscatorCLI.encoding
});
}
}
+167
View File
@@ -0,0 +1,167 @@
import * as fs from 'fs';
import * as path from 'path';
import multimatch from 'multimatch';
import { TInputCLIOptions } from '../../types/options/TInputCLIOptions';
import { IFileData } from '../../interfaces/cli/IFileData';
import { JavaScriptObfuscatorCLI } from '../JavaScriptObfuscatorCLI';
export class SourceCodeReader {
/**
* @type {string}
*/
private readonly inputPath: string;
/**
* @type {TInputCLIOptions}
*/
private readonly options: TInputCLIOptions;
/**
* @param {string} inputPath
* @param {TInputCLIOptions} options
*/
public constructor (
inputPath: string,
options: TInputCLIOptions
) {
this.inputPath = inputPath;
this.options = options;
}
/**
* @param {string} filePath
* @param {string[]} excludePatterns
* @returns {boolean}
*/
private static isExcludedPath (filePath: string, excludePatterns: string[] = []): boolean {
if (!excludePatterns.length) {
return false;
}
const fileName: string = path.basename(filePath);
const isExcludedFilePathByGlobPattern: boolean = !!multimatch([filePath], excludePatterns).length;
const isExcludedFilePathByInclusion: boolean = excludePatterns.some((excludePattern: string) =>
filePath.includes(excludePattern) || fileName.includes(excludePattern)
);
return isExcludedFilePathByInclusion || isExcludedFilePathByGlobPattern;
}
/**
* @param {string} filePath
* @returns {boolean}
*/
private static isDirectoryPath (filePath: string): boolean {
try {
return fs.statSync(filePath).isDirectory();
} catch {
return false;
}
}
/**
* @param {string} filePath
* @returns {boolean}
*/
private static isFilePath (filePath: string): boolean {
try {
return fs.statSync(filePath).isFile();
} catch {
return false;
}
}
/**
* @param {string} directoryPath
* @param {string[]} excludePatterns
* @returns {boolean}
*/
private static isValidDirectory (directoryPath: string, excludePatterns: string[] = []): boolean {
return !SourceCodeReader.isExcludedPath(directoryPath, excludePatterns);
}
/**
* @param {string} filePath
* @param {string[]} excludePatterns
* @returns {boolean}
*/
private static isValidFile (filePath: string, excludePatterns: string[] = []): boolean {
return JavaScriptObfuscatorCLI.availableInputExtensions.includes(path.extname(filePath))
&& !filePath.includes(JavaScriptObfuscatorCLI.obfuscatedFilePrefix)
&& !SourceCodeReader.isExcludedPath(filePath, excludePatterns);
}
/**
* @param {string} filePath
* @returns {string}
*/
private static readFile (filePath: string): IFileData {
return {
filePath: path.normalize(filePath),
content: fs.readFileSync(filePath, JavaScriptObfuscatorCLI.encoding)
};
}
/**
* @returns {IFileData[]}
*/
public readSourceCode (): IFileData[] {
if (
SourceCodeReader.isFilePath(this.inputPath)
&& SourceCodeReader.isValidFile(this.inputPath, this.options.exclude)
) {
return [SourceCodeReader.readFile(this.inputPath)];
}
if (
SourceCodeReader.isDirectoryPath(this.inputPath)
&& SourceCodeReader.isValidDirectory(this.inputPath, this.options.exclude)
) {
return this.readDirectoryRecursive(this.inputPath);
}
const availableFilePaths: string = JavaScriptObfuscatorCLI
.availableInputExtensions
.map((extension: string) => `\`${extension}\``)
.join(', ');
throw new ReferenceError(`Given input path must be a valid ${availableFilePaths} file or directory path`);
}
/**
* @param {string} directoryPath
* @param {IFileData[]} filesData
* @returns {IFileData[]}
*/
private readDirectoryRecursive (directoryPath: string, filesData: IFileData[] = []): IFileData[] {
fs.readdirSync(directoryPath, JavaScriptObfuscatorCLI.encoding)
.forEach((fileName: string) => {
const filePath: string = path.join(directoryPath, fileName);
if (
SourceCodeReader.isDirectoryPath(filePath)
&& SourceCodeReader.isValidDirectory(filePath, this.options.exclude)
) {
filesData.push(...this.readDirectoryRecursive(filePath));
return;
}
if (
SourceCodeReader.isFilePath(filePath)
&& SourceCodeReader.isValidFile(filePath, this.options.exclude)
) {
const fileData: IFileData = SourceCodeReader.readFile(filePath);
filesData.push(fileData);
return;
}
});
return filesData;
}
}
@@ -0,0 +1,46 @@
import { inject, injectable } from 'inversify';
import { ServiceIdentifiers } from '../container/ServiceIdentifiers';
import { ICodeTransformer } from '../interfaces/code-transformers/ICodeTransformer';
import { IOptions } from '../interfaces/options/IOptions';
import { IRandomGenerator } from '../interfaces/utils/IRandomGenerator';
import { CodeTransformer } from '../enums/code-transformers/CodeTransformer';
import { CodeTransformationStage } from '../enums/code-transformers/CodeTransformationStage';
@injectable()
export abstract class AbstractCodeTransformer implements ICodeTransformer {
/**
* @type {CodeTransformer[]}
*/
public readonly runAfter: CodeTransformer[] | undefined;
/**
* @type {IOptions}
*/
protected readonly options: IOptions;
/**
* @type {IRandomGenerator}
*/
protected readonly randomGenerator: IRandomGenerator;
/**
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
*/
protected constructor (
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
this.randomGenerator = randomGenerator;
this.options = options;
}
/**
* @param {string} code
* @param {CodeTransformationStage} codeTransformationStage
* @returns {string}
*/
public abstract transformCode (code: string, codeTransformationStage: CodeTransformationStage): string;
}
@@ -0,0 +1,13 @@
import { injectable } from 'inversify';
import { ICodeTransformer } from '../interfaces/code-transformers/ICodeTransformer';
import { CodeTransformer } from '../enums/code-transformers/CodeTransformer';
import { AbstractTransformerNamesGroupsBuilder } from '../utils/AbstractTransformerNamesGroupsBuilder';
@injectable()
export class CodeTransformerNamesGroupsBuilder extends AbstractTransformerNamesGroupsBuilder<
CodeTransformer,
ICodeTransformer
> {}
@@ -0,0 +1,100 @@
import { inject, injectable } from 'inversify';
import { ServiceIdentifiers } from '../container/ServiceIdentifiers';
import { TCodeTransformerFactory } from '../types/container/code-transformers/TCodeTransformerFactory';
import { TDictionary } from '../types/TDictionary';
import { ICodeTransformer } from '../interfaces/code-transformers/ICodeTransformer';
import { ICodeTransformersRunner } from '../interfaces/code-transformers/ICodeTransformersRunner';
import { ITransformerNamesGroupsBuilder } from '../interfaces/utils/ITransformerNamesGroupsBuilder';
import { CodeTransformer } from '../enums/code-transformers/CodeTransformer';
import { CodeTransformationStage } from '../enums/code-transformers/CodeTransformationStage';
@injectable()
export class CodeTransformersRunner implements ICodeTransformersRunner {
/**
* @type {TCodeTransformerFactory}
*/
private readonly codeTransformerFactory: TCodeTransformerFactory;
/**
* @type {ITransformerNamesGroupsBuilder}
*/
private readonly codeTransformerNamesGroupsBuilder: ITransformerNamesGroupsBuilder<
CodeTransformer,
ICodeTransformer
>;
/**
* @param {TNodeTransformerFactory} codeTransformerFactory
* @param {ITransformerNamesGroupsBuilder} codeTransformerNamesGroupsBuilder
*/
public constructor (
@inject(ServiceIdentifiers.Factory__ICodeTransformer)
codeTransformerFactory: TCodeTransformerFactory,
@inject(ServiceIdentifiers.ICodeTransformerNamesGroupsBuilder)
codeTransformerNamesGroupsBuilder: ITransformerNamesGroupsBuilder<
CodeTransformer,
ICodeTransformer
>,
) {
this.codeTransformerFactory = codeTransformerFactory;
this.codeTransformerNamesGroupsBuilder = codeTransformerNamesGroupsBuilder;
}
/**
* @param {string} code
* @param {CodeTransformer[]} codeTransformerNames
* @param {CodeTransformationStage} codeTransformationStage
* @returns {string}
*/
public transform (
code: string,
codeTransformerNames: CodeTransformer[],
codeTransformationStage: CodeTransformationStage
): string {
if (!codeTransformerNames.length) {
return code;
}
const normalizedCodeTransformers: TDictionary<ICodeTransformer> =
this.buildNormalizedCodeTransformers(codeTransformerNames, codeTransformationStage);
const codeTransformerNamesGroups: CodeTransformer[][] =
this.codeTransformerNamesGroupsBuilder.build(normalizedCodeTransformers);
for (const nodeTransformerNamesGroup of codeTransformerNamesGroups) {
for (const nodeTransformerName of nodeTransformerNamesGroup) {
const codeTransformer: ICodeTransformer = normalizedCodeTransformers[nodeTransformerName];
code = codeTransformer.transformCode(code, codeTransformationStage);
}
}
return code;
}
/**
* @param {NodeTransformer[]} codeTransformerNames
* @param {NodeTransformationStage} codeTransformationStage
* @returns {TDictionary<INodeTransformer>}
*/
private buildNormalizedCodeTransformers (
codeTransformerNames: CodeTransformer[],
codeTransformationStage: CodeTransformationStage
): TDictionary<ICodeTransformer> {
return codeTransformerNames
.reduce<TDictionary<ICodeTransformer>>(
(acc: TDictionary<ICodeTransformer>, codeTransformerName: CodeTransformer) => {
const codeTransformer: ICodeTransformer = this.codeTransformerFactory(codeTransformerName);
return {
...acc,
[codeTransformerName]: codeTransformer
};
},
{}
);
}
}
@@ -0,0 +1,72 @@
import { inject, injectable, } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import { IOptions } from '../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
import { CodeTransformationStage } from '../../enums/code-transformers/CodeTransformationStage';
import { AbstractCodeTransformer } from '../AbstractCodeTransformer';
@injectable()
export class HashbangOperatorTransformer extends AbstractCodeTransformer {
/**
* @type {string | null}
*/
private hashbangOperatorLine: string | null = null;
/**
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
*/
public constructor (
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
super(randomGenerator, options);
}
/**
* Removes hashbang operator before AST transformation and appends it back after
*
* @param {string} code
* @param {CodeTransformationStage} codeTransformationStage
* @returns {string}
*/
public transformCode (code: string, codeTransformationStage: CodeTransformationStage): string {
switch (codeTransformationStage) {
case CodeTransformationStage.PreparingTransformers:
return this.removeAndSaveHashbangOperatorLine(code);
case CodeTransformationStage.FinalizingTransformers:
return this.appendSavedHashbangOperatorLine(code);
default:
return code;
}
}
/**
* @param {string} code
* @returns {string}
*/
private removeAndSaveHashbangOperatorLine (code: string): string {
return code
.replace(/^#!.*$(\r?\n)*/m, (substring: string) => {
if (substring) {
this.hashbangOperatorLine = substring;
}
return '';
})
.trim();
}
/**
* @param {string} code
* @returns {string}
*/
private appendSavedHashbangOperatorLine (code: string): string {
return `${this.hashbangOperatorLine ?? ''}${code}`;
}
}
+1
View File
@@ -0,0 +1 @@
export const alphabetString: string = 'abcdefghijklmnopqrstuvwxyz';
@@ -0,0 +1,3 @@
import { alphabetString } from './AlphabetString';
export const alphabetStringUppercase: string = alphabetString.toUpperCase();
+5
View File
@@ -0,0 +1,5 @@
import { alphabetStringUppercase } from './AlphabetStringUppercase';
import { alphabetString } from './AlphabetString';
import { numbersString } from './NumbersString';
export const base64alphabet: string = `${alphabetStringUppercase}${alphabetString}${numbersString}+/=`;
@@ -0,0 +1,8 @@
import { alphabetStringUppercase } from './AlphabetStringUppercase';
import { alphabetString } from './AlphabetString';
import { numbersString } from './NumbersString';
/**
* Swapped lowercase and uppercase groups of alphabet to prevent easy decode
*/
export const base64alphabetSwapped: string = `${alphabetString}${alphabetStringUppercase}${numbersString}+/=`;
+3
View File
@@ -0,0 +1,3 @@
import * as acorn from 'acorn';
export const ecmaVersion: acorn.Options['ecmaVersion'] & number = 12;
+1
View File
@@ -0,0 +1 @@
export const numbersString: string = '0123456789';
@@ -0,0 +1,233 @@
import { Container, interfaces } from 'inversify';
import { ServiceIdentifiers } from './ServiceIdentifiers';
import { analyzersModule } from './modules/analyzers/AnalyzersModule';
import { codeTransformersModule } from './modules/code-transformers/CodeTransformersModule';
import { controlFlowTransformersModule } from './modules/node-transformers/ControlFlowTransformersModule';
import { convertingTransformersModule } from './modules/node-transformers/ConvertingTransformersModule';
import { customCodeHelpersModule } from './modules/custom-code-helpers/CustomCodeHelpersModule';
import { customNodesModule } from './modules/custom-nodes/CustomNodesModule';
import { deadCodeInjectionTransformersModule } from './modules/node-transformers/DeadCodeInjectionTransformersModule';
import { finalizingTransformersModule } from './modules/node-transformers/FinalizingTransformersModule';
import { generatorsModule } from './modules/generators/GeneratorsModule';
import { initializingTransformersModule } from './modules/node-transformers/InitializingTransformersModule';
import { nodeModule } from './modules/node/NodeModule';
import { nodeTransformersModule } from './modules/node-transformers/NodeTransformersModule';
import { optionsModule } from './modules/options/OptionsModule';
import { preparingTransformersModule } from './modules/node-transformers/PreparingTransformersModule';
import { renameIdentifiersTransformersModule } from './modules/node-transformers/RenameIdentifiersTransformersModule';
import { renamePropertiesTransformersModule } from './modules/node-transformers/RenamePropertiesTransformersModule';
import { simplifyingTransformersModule } from './modules/node-transformers/SimplifyingTransformersModule';
import { storagesModule } from './modules/storages/StoragesModule';
import { stringArrayTransformersModule } from './modules/node-transformers/StringArrayTransformersModule';
import { utilsModule } from './modules/utils/UtilsModule';
import { TInputOptions } from '../types/options/TInputOptions';
import { ICodeTransformersRunner } from '../interfaces/code-transformers/ICodeTransformersRunner';
import { IInversifyContainerFacade } from '../interfaces/container/IInversifyContainerFacade';
import { IJavaScriptObfuscator } from '../interfaces/IJavaScriptObfsucator';
import { ILogger } from '../interfaces/logger/ILogger';
import { IObfuscationEventEmitter } from '../interfaces/event-emitters/IObfuscationEventEmitter';
import { IObfuscatedCode } from '../interfaces/source-code/IObfuscatedCode';
import { ISourceCode } from '../interfaces/source-code/ISourceCode';
import { INodeTransformersRunner } from '../interfaces/node-transformers/INodeTransformersRunner';
import { CodeTransformersRunner } from '../code-transformers/CodeTransformersRunner';
import { JavaScriptObfuscator } from '../JavaScriptObfuscator';
import { Logger } from '../logger/Logger';
import { NodeTransformersRunner } from '../node-transformers/NodeTransformersRunner';
import { ObfuscationEventEmitter } from '../event-emitters/ObfuscationEventEmitter';
import { ObfuscatedCode } from '../source-code/ObfuscatedCode';
import { SourceCode } from '../source-code/SourceCode';
export class InversifyContainerFacade implements IInversifyContainerFacade {
/**
* @type {interfaces.Container}
*/
private readonly container: interfaces.Container;
public constructor () {
this.container = new Container();
}
/**
* @param {interfaces.ServiceIdentifier<U>} serviceIdentifier
* @returns {U}
*/
public static getFactory <T extends string, U> (
serviceIdentifier: interfaces.ServiceIdentifier<U>
): (context: interfaces.Context) => (bindingName: T) => U {
return (context: interfaces.Context): (bindingName: T) => U => {
return (bindingName: T): U => {
return context.container.getNamed<U>(serviceIdentifier, bindingName);
};
};
}
/**
* @param {interfaces.ServiceIdentifier<U>} serviceIdentifier
* @returns {U}
*/
public static getCacheFactory <T extends string, U> (
serviceIdentifier: interfaces.ServiceIdentifier<U>
): (context: interfaces.Context) => (bindingName: T) => U {
return (context: interfaces.Context): (bindingName: T) => U => {
const cache: Map <T, U> = new Map();
return (bindingName: T): U => {
if (cache.has(bindingName)) {
return <U>cache.get(bindingName);
}
const object: U = context.container.getNamed<U>(serviceIdentifier, bindingName);
cache.set(bindingName, object);
return object;
};
};
}
/**
* @param {interfaces.ServiceIdentifier<interfaces.Newable<U>>} serviceIdentifier
* @param {interfaces.ServiceIdentifier<interfaces.Newable<Object>>[]} dependencies
* @returns {U}
*/
public static getConstructorFactory <T extends string, U> (
serviceIdentifier: interfaces.ServiceIdentifier<interfaces.Newable<U>>,
...dependencies: interfaces.ServiceIdentifier<interfaces.Newable<Record<string, any>>>[]
): (context: interfaces.Context) => (bindingName: T) => U {
return (context: interfaces.Context): (bindingName: T) => U => {
const cache: Map<T, interfaces.Newable<U>> = new Map();
const cachedDependencies: Record<string, any>[] = [];
return (bindingName: T): U => {
dependencies.forEach((
dependency: interfaces.ServiceIdentifier<interfaces.Newable<Record<string, any>>>,
index: number
) => {
if (!cachedDependencies[index]) {
cachedDependencies[index] = context.container.get(dependency);
}
});
if (cache.has(bindingName)) {
return new (<interfaces.Newable<U>>cache.get(bindingName))(...cachedDependencies);
}
const constructor: interfaces.Newable<U> = context.container
.getNamed<interfaces.Newable<U>>(
serviceIdentifier,
bindingName
);
cache.set(bindingName, constructor);
return new constructor(...cachedDependencies);
};
};
}
/**
* @param {interfaces.ServiceIdentifier<T>} serviceIdentifier
* @returns {T}
*/
public get <T> (serviceIdentifier: interfaces.ServiceIdentifier<T>): T {
return this.container.get<T>(serviceIdentifier);
}
/**
* @param {interfaces.ServiceIdentifier<T>} serviceIdentifier
* @param {string | number | symbol} named
* @returns {T}
*/
public getNamed <T> (serviceIdentifier: interfaces.ServiceIdentifier<T>, named: string | number | symbol): T {
return this.container.getNamed<T>(serviceIdentifier, named);
}
/**
* @param {string} sourceCode
* @param {string} sourceMap
* @param {TInputOptions} options
*/
public load (sourceCode: string, sourceMap: string, options: TInputOptions): void {
this.container
.bind<ISourceCode>(ServiceIdentifiers.ISourceCode)
.toDynamicValue(() => new SourceCode(sourceCode, sourceMap))
.inSingletonScope();
this.container
.bind<TInputOptions>(ServiceIdentifiers.TInputOptions)
.toDynamicValue(() => options)
.inSingletonScope();
this.container
.bind<ILogger>(ServiceIdentifiers.ILogger)
.to(Logger)
.inSingletonScope();
this.container
.bind<IJavaScriptObfuscator>(ServiceIdentifiers.IJavaScriptObfuscator)
.to(JavaScriptObfuscator)
.inSingletonScope();
this.container
.bind<ICodeTransformersRunner>(ServiceIdentifiers.ICodeTransformersRunner)
.to(CodeTransformersRunner)
.inSingletonScope();
this.container
.bind<INodeTransformersRunner>(ServiceIdentifiers.INodeTransformersRunner)
.to(NodeTransformersRunner)
.inSingletonScope();
this.container
.bind<IObfuscatedCode>(ServiceIdentifiers.IObfuscatedCode)
.to(ObfuscatedCode);
this.container
.bind<IObfuscatedCode>(ServiceIdentifiers.Factory__IObfuscatedCode)
.toFactory<IObfuscatedCode>((context: interfaces.Context) => {
return (obfuscatedCodeAsString: string, sourceMapAsString: string): IObfuscatedCode => {
const obfuscatedCode: IObfuscatedCode = context.container
.get<IObfuscatedCode>(ServiceIdentifiers.IObfuscatedCode);
obfuscatedCode.initialize(obfuscatedCodeAsString, sourceMapAsString);
return obfuscatedCode;
};
});
this.container
.bind<IObfuscationEventEmitter>(ServiceIdentifiers.IObfuscationEventEmitter)
.to(ObfuscationEventEmitter)
.inSingletonScope();
// modules
this.container.load(analyzersModule);
this.container.load(codeTransformersModule);
this.container.load(controlFlowTransformersModule);
this.container.load(convertingTransformersModule);
this.container.load(customCodeHelpersModule);
this.container.load(customNodesModule);
this.container.load(deadCodeInjectionTransformersModule);
this.container.load(finalizingTransformersModule);
this.container.load(generatorsModule);
this.container.load(initializingTransformersModule);
this.container.load(nodeModule);
this.container.load(nodeTransformersModule);
this.container.load(optionsModule);
this.container.load(preparingTransformersModule);
this.container.load(renameIdentifiersTransformersModule);
this.container.load(renamePropertiesTransformersModule);
this.container.load(simplifyingTransformersModule);
this.container.load(storagesModule);
this.container.load(stringArrayTransformersModule);
this.container.load(utilsModule);
}
public unload (): void {
this.container.unbindAll();
}
}
+64
View File
@@ -0,0 +1,64 @@
export enum ServiceIdentifiers {
Factory__ICalleeDataExtractor = 'Factory<ICalleeDataExtractor>',
Factory__ICodeTransformer = 'Factory<ICodeTransformer[]>',
Factory__IControlFlowCustomNode = 'Factory<IControlFlowCustomNode>',
Factory__IControlFlowReplacer = 'Factory<IControlFlowReplacer>',
Factory__ICustomCodeHelper = 'Factory<ICustomCodeHelper>',
Factory__ICustomCodeHelperGroup = 'Factory<ICustomCodeHelperGroup>',
Factory__IDeadCodeInjectionCustomNode = 'Factory<IDeadCodeInjectionCustomNode>',
Factory__IIdentifierNamesGenerator = 'Factory<IIdentifierNamesGenerator>',
Factory__INodeGuard = 'Factory<INodeGuard>',
Factory__INodeTransformer = 'Factory<INodeTransformer[]>',
Factory__IObfuscatedCode = 'Factory<IObfuscatedCode>',
Factory__IObjectExpressionKeysTransformerCustomNode = 'Factory<IObjectExpressionKeysTransformerCustomNode>',
Factory__IObjectExpressionExtractor = 'Factory<IObjectExpressionExtractor>',
Factory__IStringArrayCustomNode = 'Factory<IStringArrayCustomNode>',
Factory__IStringArrayIndexNode = 'Factory<IStringArrayIndexNode>',
Factory__TControlFlowStorage = 'Factory<TControlFlowStorage>',
IArrayUtils = 'IArrayUtils',
ICalleeDataExtractor = 'ICalleeDataExtractor',
ICallsGraphAnalyzer = 'ICallsGraphAnalyzer',
ICodeTransformer = 'ICodeTransformer',
ICodeTransformerNamesGroupsBuilder = 'ICodeTransformerNamesGroupsBuilder',
ICodeTransformersRunner = 'ICodeTransformersRunner',
ICryptUtils = 'ICryptUtils',
ICryptUtilsSwappedAlphabet = 'ICryptUtilsSwappedAlphabet',
ICustomCodeHelper = 'ICustomCodeHelper',
ICustomCodeHelperGroup = 'ICustomCodeHelperGroup',
IControlFlowReplacer = 'IControlFlowReplacer',
ICustomCodeHelperFormatter = 'ICustomCodeHelperFormatter',
ICustomCodeHelperObfuscator = 'ICustomCodeHelperObfuscator',
IEscapeSequenceEncoder = 'IEscapeSequenceEncoder',
IIdentifierNamesGenerator = 'IIdentifierNamesGenerator',
IIdentifierReplacer = 'IIdentifierReplacer',
IJavaScriptObfuscator = 'IJavaScriptObfuscator',
ILevelledTopologicalSorter = 'ILevelledTopologicalSorter',
ILiteralNodesCacheStorage = 'ILiteralNodesCacheStorage',
ILogger = 'ILogger',
INodeGuard = 'INodeGuard',
INodeTransformer = 'INodeTransformer',
INodeTransformerNamesGroupsBuilder = 'INodeTransformerNamesGroupsBuilder',
INodeTransformersRunner = 'INodeTransformersRunner',
INumberNumericalExpressionAnalyzer = 'INumberNumericalExpressionAnalyzer',
IObfuscationEventEmitter = 'IObfuscationEventEmitter',
IObfuscatedCode = 'IObfuscatedCode',
IOptions = 'IOptions',
IOptionsNormalizer = 'IOptionsNormalizer',
IPrevailingKindOfVariablesAnalyzer = 'IPrevailingKindOfVariablesAnalyzer',
IObjectExpressionExtractor = 'IObjectExpressionExtractor',
IRandomGenerator = 'IRandomGenerator',
IRenamePropertiesReplacer = 'IRenamePropertiesReplacer',
IScopeIdentifiersTraverser = 'IScopeIdentifiersTraverser',
ISourceCode = 'ISourceCode',
IScopeAnalyzer = 'IScopeAnalyzer',
IStringArrayIndexNode = 'IStringArrayIndexNode',
IStringArrayScopeCallsWrapperLexicalScopeDataStorage = 'IStringArrayScopeCallsWrapperLexicalScopeDataStorage',
IStringArrayScopeCallsWrapperNamesDataStorage = 'IStringArrayScopeCallsWrapperNamesDataStorage',
IStringArrayStorage = 'IStringArrayStorage',
IStringArrayStorageAnalyzer = 'IStringArrayStorageAnalyzer',
IVisitedLexicalScopeNodesStackStorage = 'IVisitedLexicalScopeNodesStackStorage',
Newable__ICustomNode = 'Newable<ICustomNode>',
Newable__TControlFlowStorage = 'Newable<TControlFlowStorage>',
TCustomNodeGroupStorage = 'TCustomNodeGroupStorage',
TInputOptions = 'TInputOptions'
}
@@ -0,0 +1,67 @@
import { InversifyContainerFacade } from '../../InversifyContainerFacade';
import { ContainerModule, interfaces } from 'inversify';
import { ServiceIdentifiers } from '../../ServiceIdentifiers';
import { ICalleeDataExtractor } from '../../../interfaces/analyzers/calls-graph-analyzer/ICalleeDataExtractor';
import { ICallsGraphAnalyzer } from '../../../interfaces/analyzers/calls-graph-analyzer/ICallsGraphAnalyzer';
import { INumberNumericalExpressionAnalyzer } from '../../../interfaces/analyzers/number-numerical-expression-analyzer/INumberNumericalExpressionAnalyzer';
import { IPrevailingKindOfVariablesAnalyzer } from '../../../interfaces/analyzers/calls-graph-analyzer/IPrevailingKindOfVariablesAnalyzer';
import { IScopeAnalyzer } from '../../../interfaces/analyzers/scope-analyzer/IScopeAnalyzer';
import { IStringArrayStorageAnalyzer } from '../../../interfaces/analyzers/string-array-storage-analyzer/IStringArrayStorageAnalyzer';
import { CalleeDataExtractor } from '../../../enums/analyzers/calls-graph-analyzer/CalleeDataExtractor';
import { CallsGraphAnalyzer } from '../../../analyzers/calls-graph-analyzer/CallsGraphAnalyzer';
import { FunctionDeclarationCalleeDataExtractor } from '../../../analyzers/calls-graph-analyzer/callee-data-extractors/FunctionDeclarationCalleeDataExtractor';
import { FunctionExpressionCalleeDataExtractor } from '../../../analyzers/calls-graph-analyzer/callee-data-extractors/FunctionExpressionCalleeDataExtractor';
import { NumberNumericalExpressionAnalyzer } from '../../../analyzers/number-numerical-expression-analyzer/NumberNumericalExpressionAnalyzer';
import { ObjectExpressionCalleeDataExtractor } from '../../../analyzers/calls-graph-analyzer/callee-data-extractors/ObjectExpressionCalleeDataExtractor';
import { PrevailingKindOfVariablesAnalyzer } from '../../../analyzers/prevailing-kind-of-variables-analyzer/PrevailingKindOfVariablesAnalyzer';
import { ScopeAnalyzer } from '../../../analyzers/scope-analyzer/ScopeAnalyzer';
import { StringArrayStorageAnalyzer } from '../../../analyzers/string-array-storage-analyzer/StringArrayStorageAnalyzer';
export const analyzersModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
// calls graph analyzer
bind<ICallsGraphAnalyzer>(ServiceIdentifiers.ICallsGraphAnalyzer)
.to(CallsGraphAnalyzer)
.inSingletonScope();
// number numerical expression analyzer
bind<INumberNumericalExpressionAnalyzer>(ServiceIdentifiers.INumberNumericalExpressionAnalyzer)
.to(NumberNumericalExpressionAnalyzer)
.inSingletonScope();
// prevailing kind of variables analyzer
bind<IPrevailingKindOfVariablesAnalyzer>(ServiceIdentifiers.IPrevailingKindOfVariablesAnalyzer)
.to(PrevailingKindOfVariablesAnalyzer)
.inSingletonScope();
// scope analyzer
bind<IScopeAnalyzer>(ServiceIdentifiers.IScopeAnalyzer)
.to(ScopeAnalyzer)
.inSingletonScope();
// string array storage analyzer
bind<IStringArrayStorageAnalyzer>(ServiceIdentifiers.IStringArrayStorageAnalyzer)
.to(StringArrayStorageAnalyzer)
.inSingletonScope();
// callee data extractors
bind<ICalleeDataExtractor>(ServiceIdentifiers.ICalleeDataExtractor)
.to(FunctionDeclarationCalleeDataExtractor)
.whenTargetNamed(CalleeDataExtractor.FunctionDeclarationCalleeDataExtractor);
bind<ICalleeDataExtractor>(ServiceIdentifiers.ICalleeDataExtractor)
.to(FunctionExpressionCalleeDataExtractor)
.whenTargetNamed(CalleeDataExtractor.FunctionExpressionCalleeDataExtractor);
bind<ICalleeDataExtractor>(ServiceIdentifiers.ICalleeDataExtractor)
.to(ObjectExpressionCalleeDataExtractor)
.whenTargetNamed(CalleeDataExtractor.ObjectExpressionCalleeDataExtractor);
// callee data extractor factory
bind<ICalleeDataExtractor>(ServiceIdentifiers.Factory__ICalleeDataExtractor)
.toFactory<ICalleeDataExtractor>(InversifyContainerFacade
.getCacheFactory<CalleeDataExtractor, ICalleeDataExtractor>(
ServiceIdentifiers.ICalleeDataExtractor
));
});
@@ -0,0 +1,28 @@
import { InversifyContainerFacade } from '../../InversifyContainerFacade';
import { ContainerModule, interfaces } from 'inversify';
import { ServiceIdentifiers } from '../../ServiceIdentifiers';
import { ICodeTransformer } from '../../../interfaces/code-transformers/ICodeTransformer';
import { ITransformerNamesGroupsBuilder } from '../../../interfaces/utils/ITransformerNamesGroupsBuilder';
import { CodeTransformer } from '../../../enums/code-transformers/CodeTransformer';
import { CodeTransformerNamesGroupsBuilder } from '../../../code-transformers/CodeTransformerNamesGroupsBuilder';
import { HashbangOperatorTransformer } from '../../../code-transformers/preparing-transformers/HashbangOperatorTransformer';
export const codeTransformersModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
// code transformers factory
bind<ICodeTransformer>(ServiceIdentifiers.Factory__ICodeTransformer)
.toFactory<ICodeTransformer>(InversifyContainerFacade
.getCacheFactory<CodeTransformer, ICodeTransformer>(ServiceIdentifiers.ICodeTransformer));
// code transformer names groups builder
bind<ITransformerNamesGroupsBuilder<CodeTransformer, ICodeTransformer>>(ServiceIdentifiers.ICodeTransformerNamesGroupsBuilder)
.to(CodeTransformerNamesGroupsBuilder)
.inSingletonScope();
// preparing code transformers
bind<ICodeTransformer>(ServiceIdentifiers.ICodeTransformer)
.to(HashbangOperatorTransformer)
.whenTargetNamed(CodeTransformer.HashbangOperatorTransformer);
});
@@ -0,0 +1,124 @@
import { InversifyContainerFacade } from '../../InversifyContainerFacade';
import { ContainerModule, interfaces } from 'inversify';
import { ServiceIdentifiers } from '../../ServiceIdentifiers';
import { ICustomCodeHelper } from '../../../interfaces/custom-code-helpers/ICustomCodeHelper';
import { ICustomCodeHelperFormatter } from '../../../interfaces/custom-code-helpers/ICustomCodeHelperFormatter';
import { ICustomCodeHelperGroup } from '../../../interfaces/custom-code-helpers/ICustomCodeHelperGroup';
import { ICustomCodeHelperObfuscator } from '../../../interfaces/custom-code-helpers/ICustomCodeHelperObfuscator';
import { CustomCodeHelper } from '../../../enums/custom-code-helpers/CustomCodeHelper';
import { CustomCodeHelperGroup } from '../../../enums/custom-code-helpers/CustomCodeHelperGroup';
import { ConsoleOutputCodeHelperGroup } from '../../../custom-code-helpers/console-output/group/ConsoleOutputCodeHelperGroup';
import { DebugProtectionCodeHelperGroup } from '../../../custom-code-helpers/debug-protection/group/DebugProtectionCodeHelperGroup';
import { DomainLockCustomCodeHelperGroup } from '../../../custom-code-helpers/domain-lock/group/DomainLockCustomCodeHelperGroup';
import { SelfDefendingCodeHelperGroup } from '../../../custom-code-helpers/self-defending/group/SelfDefendingCodeHelperGroup';
import { StringArrayCodeHelperGroup } from '../../../custom-code-helpers/string-array/group/StringArrayCodeHelperGroup';
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';
import { DebugProtectionFunctionIntervalCodeHelper } from '../../../custom-code-helpers/debug-protection/DebugProtectionFunctionIntervalCodeHelper';
import { DebugProtectionFunctionCodeHelper } from '../../../custom-code-helpers/debug-protection/DebugProtectionFunctionCodeHelper';
import { DomainLockCodeHelper } from '../../../custom-code-helpers/domain-lock/DomainLockCodeHelper';
import { CallsControllerFunctionCodeHelper } from '../../../custom-code-helpers/calls-controller/CallsControllerFunctionCodeHelper';
import { SelfDefendingUnicodeCodeHelper } from '../../../custom-code-helpers/self-defending/SelfDefendingUnicodeCodeHelper';
import { StringArrayCallsWrapperCodeHelper } from '../../../custom-code-helpers/string-array/StringArrayCallsWrapperCodeHelper';
import { StringArrayCallsWrapperBase64CodeHelper } from '../../../custom-code-helpers/string-array/StringArrayCallsWrapperBase64CodeHelper';
import { StringArrayCallsWrapperRc4CodeHelper } from '../../../custom-code-helpers/string-array/StringArrayCallsWrapperRc4CodeHelper';
import { StringArrayCodeHelper } from '../../../custom-code-helpers/string-array/StringArrayCodeHelper';
import { StringArrayRotateFunctionCodeHelper } from '../../../custom-code-helpers/string-array/StringArrayRotateFunctionCodeHelper';
export const customCodeHelpersModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
// custom code helpers
bind<ICustomCodeHelper>(ServiceIdentifiers.ICustomCodeHelper)
.to(ConsoleOutputDisableCodeHelper)
.whenTargetNamed(CustomCodeHelper.ConsoleOutputDisable);
bind<ICustomCodeHelper>(ServiceIdentifiers.ICustomCodeHelper)
.to(DebugProtectionFunctionCallCodeHelper)
.whenTargetNamed(CustomCodeHelper.DebugProtectionFunctionCall);
bind<ICustomCodeHelper>(ServiceIdentifiers.ICustomCodeHelper)
.to(DebugProtectionFunctionIntervalCodeHelper)
.whenTargetNamed(CustomCodeHelper.DebugProtectionFunctionInterval);
bind<ICustomCodeHelper>(ServiceIdentifiers.ICustomCodeHelper)
.to(DebugProtectionFunctionCodeHelper)
.whenTargetNamed(CustomCodeHelper.DebugProtectionFunction);
bind<ICustomCodeHelper>(ServiceIdentifiers.ICustomCodeHelper)
.to(DomainLockCodeHelper)
.whenTargetNamed(CustomCodeHelper.DomainLock);
bind<ICustomCodeHelper>(ServiceIdentifiers.ICustomCodeHelper)
.to(CallsControllerFunctionCodeHelper)
.whenTargetNamed(CustomCodeHelper.CallsControllerFunction);
bind<ICustomCodeHelper>(ServiceIdentifiers.ICustomCodeHelper)
.to(SelfDefendingUnicodeCodeHelper)
.whenTargetNamed(CustomCodeHelper.SelfDefendingUnicode);
bind<ICustomCodeHelper>(ServiceIdentifiers.ICustomCodeHelper)
.to(StringArrayCallsWrapperCodeHelper)
.whenTargetNamed(CustomCodeHelper.StringArrayCallsWrapper);
bind<ICustomCodeHelper>(ServiceIdentifiers.ICustomCodeHelper)
.to(StringArrayCallsWrapperBase64CodeHelper)
.whenTargetNamed(CustomCodeHelper.StringArrayCallsWrapperBase64);
bind<ICustomCodeHelper>(ServiceIdentifiers.ICustomCodeHelper)
.to(StringArrayCallsWrapperRc4CodeHelper)
.whenTargetNamed(CustomCodeHelper.StringArrayCallsWrapperRc4);
bind<ICustomCodeHelper>(ServiceIdentifiers.ICustomCodeHelper)
.to(StringArrayCodeHelper)
.whenTargetNamed(CustomCodeHelper.StringArray);
bind<ICustomCodeHelper>(ServiceIdentifiers.ICustomCodeHelper)
.to(StringArrayRotateFunctionCodeHelper)
.whenTargetNamed(CustomCodeHelper.StringArrayRotateFunction);
// code helper groups
bind<ICustomCodeHelperGroup>(ServiceIdentifiers.ICustomCodeHelperGroup)
.to(ConsoleOutputCodeHelperGroup)
.whenTargetNamed(CustomCodeHelperGroup.ConsoleOutput);
bind<ICustomCodeHelperGroup>(ServiceIdentifiers.ICustomCodeHelperGroup)
.to(DebugProtectionCodeHelperGroup)
.whenTargetNamed(CustomCodeHelperGroup.DebugProtection);
bind<ICustomCodeHelperGroup>(ServiceIdentifiers.ICustomCodeHelperGroup)
.to(DomainLockCustomCodeHelperGroup)
.whenTargetNamed(CustomCodeHelperGroup.DomainLock);
bind<ICustomCodeHelperGroup>(ServiceIdentifiers.ICustomCodeHelperGroup)
.to(SelfDefendingCodeHelperGroup)
.whenTargetNamed(CustomCodeHelperGroup.SelfDefending);
bind<ICustomCodeHelperGroup>(ServiceIdentifiers.ICustomCodeHelperGroup)
.to(StringArrayCodeHelperGroup)
.whenTargetNamed(CustomCodeHelperGroup.StringArray);
// customCodeHelper factory
bind<ICustomCodeHelper>(ServiceIdentifiers.Factory__ICustomCodeHelper)
.toFactory<ICustomCodeHelper>(InversifyContainerFacade
.getFactory<CustomCodeHelper, ICustomCodeHelper>(ServiceIdentifiers.ICustomCodeHelper));
// customCodeHelperGroup factory
bind<ICustomCodeHelperGroup>(ServiceIdentifiers.Factory__ICustomCodeHelperGroup)
.toFactory<ICustomCodeHelperGroup>(InversifyContainerFacade
.getFactory<CustomCodeHelperGroup, ICustomCodeHelperGroup>(ServiceIdentifiers.ICustomCodeHelperGroup));
// custom code helper formatter
bind<ICustomCodeHelperFormatter>(ServiceIdentifiers.ICustomCodeHelperFormatter)
.to(CustomCodeHelperFormatter)
.inSingletonScope();
// custom code helper obfuscator
bind<ICustomCodeHelperObfuscator>(ServiceIdentifiers.ICustomCodeHelperObfuscator)
.to(CustomCodeHelperObfuscator)
.inSingletonScope();
});
@@ -0,0 +1,154 @@
import { InversifyContainerFacade } from '../../InversifyContainerFacade';
import { ContainerModule, interfaces } from 'inversify';
import { ServiceIdentifiers } from '../../ServiceIdentifiers';
import { ICustomNode } from '../../../interfaces/custom-nodes/ICustomNode';
import { IStringArrayIndexNode } from '../../../interfaces/custom-nodes/string-array-nodes/IStringArrayIndexNode';
import { ControlFlowCustomNode } from '../../../enums/custom-nodes/ControlFlowCustomNode';
import { DeadCodeInjectionCustomNode } from '../../../enums/custom-nodes/DeadCodeInjectionCustomNode';
import { ObjectExpressionKeysTransformerCustomNode } from '../../../enums/custom-nodes/ObjectExpressionKeysTransformerCustomNode';
import { StringArrayCustomNode } from '../../../enums/custom-nodes/StringArrayCustomNode';
import { BinaryExpressionFunctionNode } from '../../../custom-nodes/control-flow-flattening-nodes/BinaryExpressionFunctionNode';
import { BlockStatementControlFlowFlatteningNode } from '../../../custom-nodes/control-flow-flattening-nodes/BlockStatementControlFlowFlatteningNode';
import { BlockStatementDeadCodeInjectionNode } from '../../../custom-nodes/dead-code-injection-nodes/BlockStatementDeadCodeInjectionNode';
import { CallExpressionControlFlowStorageCallNode } from '../../../custom-nodes/control-flow-flattening-nodes/control-flow-storage-nodes/CallExpressionControlFlowStorageCallNode';
import { CallExpressionFunctionNode } from '../../../custom-nodes/control-flow-flattening-nodes/CallExpressionFunctionNode';
import { ControlFlowStorageNode } from '../../../custom-nodes/control-flow-flattening-nodes/control-flow-storage-nodes/ControlFlowStorageNode';
import { ExpressionWithOperatorControlFlowStorageCallNode } from '../../../custom-nodes/control-flow-flattening-nodes/control-flow-storage-nodes/ExpressionWithOperatorControlFlowStorageCallNode';
import { LogicalExpressionFunctionNode } from '../../../custom-nodes/control-flow-flattening-nodes/LogicalExpressionFunctionNode';
import { ObjectExpressionVariableDeclarationHostNode } from '../../../custom-nodes/object-expression-keys-transformer-nodes/ObjectExpressionVariableDeclarationHostNode';
import { StringArrayCallNode } from '../../../custom-nodes/string-array-nodes/StringArrayCallNode';
import { StringArrayHexadecimalNumberIndexNode } from '../../../custom-nodes/string-array-nodes/string-array-index-nodes/StringArrayHexadecimalNumberIndexNode';
import { StringArrayHexadecimalNumericStringIndexNode } from '../../../custom-nodes/string-array-nodes/string-array-index-nodes/StringArrayHexadecimalNumericStringIndexNode';
import { StringArrayIndexNode } from '../../../enums/custom-nodes/string-array-index-nodes/StringArrayIndexNode';
import { StringArrayScopeCallsWrapperFunctionNode } from '../../../custom-nodes/string-array-nodes/StringArrayScopeCallsWrapperFunctionNode';
import { StringArrayScopeCallsWrapperVariableNode } from '../../../custom-nodes/string-array-nodes/StringArrayScopeCallsWrapperVariableNode';
import { StringLiteralControlFlowStorageCallNode } from '../../../custom-nodes/control-flow-flattening-nodes/control-flow-storage-nodes/StringLiteralControlFlowStorageCallNode';
import { StringLiteralNode } from '../../../custom-nodes/control-flow-flattening-nodes/StringLiteralNode';
export const customNodesModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
// control flow custom nodes
bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
.toConstructor(BinaryExpressionFunctionNode)
.whenTargetNamed(ControlFlowCustomNode.BinaryExpressionFunctionNode);
bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
.toConstructor(BlockStatementControlFlowFlatteningNode)
.whenTargetNamed(ControlFlowCustomNode.BlockStatementControlFlowFlatteningNode);
bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
.toConstructor(CallExpressionControlFlowStorageCallNode)
.whenTargetNamed(ControlFlowCustomNode.CallExpressionControlFlowStorageCallNode);
bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
.toConstructor(CallExpressionFunctionNode)
.whenTargetNamed(ControlFlowCustomNode.CallExpressionFunctionNode);
bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
.toConstructor(ControlFlowStorageNode)
.whenTargetNamed(ControlFlowCustomNode.ControlFlowStorageNode);
bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
.toConstructor(ExpressionWithOperatorControlFlowStorageCallNode)
.whenTargetNamed(ControlFlowCustomNode.ExpressionWithOperatorControlFlowStorageCallNode);
bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
.toConstructor(LogicalExpressionFunctionNode)
.whenTargetNamed(ControlFlowCustomNode.LogicalExpressionFunctionNode);
bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
.toConstructor(StringLiteralNode)
.whenTargetNamed(ControlFlowCustomNode.StringLiteralNode);
bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
.toConstructor(StringLiteralControlFlowStorageCallNode)
.whenTargetNamed(ControlFlowCustomNode.StringLiteralControlFlowStorageCallNode);
// dead code injection custom nodes
bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
.toConstructor(BlockStatementDeadCodeInjectionNode)
.whenTargetNamed(DeadCodeInjectionCustomNode.BlockStatementDeadCodeInjectionNode);
// object expression keys transformer nodes
bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
.toConstructor(ObjectExpressionVariableDeclarationHostNode)
.whenTargetNamed(ObjectExpressionKeysTransformerCustomNode.ObjectExpressionVariableDeclarationHostNode);
// string array nodes
bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
.toConstructor(StringArrayCallNode)
.whenTargetNamed(StringArrayCustomNode.StringArrayCallNode);
bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
.toConstructor(StringArrayScopeCallsWrapperFunctionNode)
.whenTargetNamed(StringArrayCustomNode.StringArrayScopeCallsWrapperFunctionNode);
bind<interfaces.Newable<ICustomNode>>(ServiceIdentifiers.Newable__ICustomNode)
.toConstructor(StringArrayScopeCallsWrapperVariableNode)
.whenTargetNamed(StringArrayCustomNode.StringArrayScopeCallsWrapperVariableNode);
// string array index nodes
bind<IStringArrayIndexNode>(ServiceIdentifiers.IStringArrayIndexNode)
.to(StringArrayHexadecimalNumberIndexNode)
.inSingletonScope()
.whenTargetNamed(StringArrayIndexNode.StringArrayHexadecimalNumberIndexNode);
bind<IStringArrayIndexNode>(ServiceIdentifiers.IStringArrayIndexNode)
.to(StringArrayHexadecimalNumericStringIndexNode)
.inSingletonScope()
.whenTargetNamed(StringArrayIndexNode.StringArrayHexadecimalNumericStringIndexNode);
// control flow customNode constructor factory
bind<ICustomNode>(ServiceIdentifiers.Factory__IControlFlowCustomNode)
.toFactory<ICustomNode>(InversifyContainerFacade
.getConstructorFactory<ControlFlowCustomNode, ICustomNode>(
ServiceIdentifiers.Newable__ICustomNode,
ServiceIdentifiers.Factory__IIdentifierNamesGenerator,
ServiceIdentifiers.ICustomCodeHelperFormatter,
ServiceIdentifiers.IRandomGenerator,
ServiceIdentifiers.IOptions
));
// dead code injection customNode constructor factory
bind<ICustomNode>(ServiceIdentifiers.Factory__IDeadCodeInjectionCustomNode)
.toFactory<ICustomNode>(InversifyContainerFacade
.getConstructorFactory<DeadCodeInjectionCustomNode, ICustomNode>(
ServiceIdentifiers.Newable__ICustomNode,
ServiceIdentifiers.Factory__IIdentifierNamesGenerator,
ServiceIdentifiers.ICustomCodeHelperFormatter,
ServiceIdentifiers.IRandomGenerator,
ServiceIdentifiers.IOptions
));
// object expression keys transformer customNode constructor factory
bind<ICustomNode>(ServiceIdentifiers.Factory__IObjectExpressionKeysTransformerCustomNode)
.toFactory<ICustomNode>(InversifyContainerFacade
.getConstructorFactory<ObjectExpressionKeysTransformerCustomNode, ICustomNode>(
ServiceIdentifiers.Newable__ICustomNode,
ServiceIdentifiers.Factory__IIdentifierNamesGenerator,
ServiceIdentifiers.ICustomCodeHelperFormatter,
ServiceIdentifiers.IRandomGenerator,
ServiceIdentifiers.IOptions
));
// string array customNode constructor factory
bind<ICustomNode>(ServiceIdentifiers.Factory__IStringArrayCustomNode)
.toFactory<ICustomNode>(InversifyContainerFacade
.getConstructorFactory<StringArrayCustomNode, ICustomNode>(
ServiceIdentifiers.Newable__ICustomNode,
ServiceIdentifiers.Factory__IIdentifierNamesGenerator,
ServiceIdentifiers.Factory__IStringArrayIndexNode,
ServiceIdentifiers.ICustomCodeHelperFormatter,
ServiceIdentifiers.IStringArrayStorage,
ServiceIdentifiers.IArrayUtils,
ServiceIdentifiers.IRandomGenerator,
ServiceIdentifiers.IOptions
));
// string array index node factory
bind<IStringArrayIndexNode>(ServiceIdentifiers.Factory__IStringArrayIndexNode)
.toFactory<IStringArrayIndexNode>(InversifyContainerFacade
.getCacheFactory<StringArrayIndexNode, IStringArrayIndexNode>(ServiceIdentifiers.IStringArrayIndexNode));
});
@@ -0,0 +1,87 @@
import { ContainerModule, interfaces } from 'inversify';
import { ServiceIdentifiers } from '../../ServiceIdentifiers';
import { IIdentifierNamesGenerator } from '../../../interfaces/generators/identifier-names-generators/IIdentifierNamesGenerator';
import { IOptions } from '../../../interfaces/options/IOptions';
import { IdentifierNamesGenerator } from '../../../enums/generators/identifier-names-generators/IdentifierNamesGenerator';
import { DictionaryIdentifierNamesGenerator } from '../../../generators/identifier-names-generators/DictionaryIdentifierNamesGenerator';
import { HexadecimalIdentifierNamesGenerator } from '../../../generators/identifier-names-generators/HexadecimalIdentifierNamesGenerator';
import { MangledIdentifierNamesGenerator } from '../../../generators/identifier-names-generators/MangledIdentifierNamesGenerator';
import { MangledShuffledIdentifierNamesGenerator } from '../../../generators/identifier-names-generators/MangledShuffledIdentifierNamesGenerator';
export const generatorsModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
// identifier name generators
bind<IIdentifierNamesGenerator>(ServiceIdentifiers.IIdentifierNamesGenerator)
.to(DictionaryIdentifierNamesGenerator)
.inSingletonScope()
.whenTargetNamed(IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator);
bind<IIdentifierNamesGenerator>(ServiceIdentifiers.IIdentifierNamesGenerator)
.to(HexadecimalIdentifierNamesGenerator)
.inSingletonScope()
.whenTargetNamed(IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator);
bind<IIdentifierNamesGenerator>(ServiceIdentifiers.IIdentifierNamesGenerator)
.to(MangledIdentifierNamesGenerator)
.inSingletonScope()
.whenTargetNamed(IdentifierNamesGenerator.MangledIdentifierNamesGenerator);
bind<IIdentifierNamesGenerator>(ServiceIdentifiers.IIdentifierNamesGenerator)
.to(MangledShuffledIdentifierNamesGenerator)
.inSingletonScope()
.whenTargetNamed(IdentifierNamesGenerator.MangledShuffledIdentifierNamesGenerator);
// identifier name generator factory
function identifierNameGeneratorFactory (): (context: interfaces.Context) => (options: IOptions) => IIdentifierNamesGenerator {
let cachedIdentifierNamesGenerator: IIdentifierNamesGenerator | null = null;
return (context: interfaces.Context): (options: IOptions) => IIdentifierNamesGenerator => (options: IOptions): IIdentifierNamesGenerator => {
if (cachedIdentifierNamesGenerator) {
return cachedIdentifierNamesGenerator;
}
let identifierNamesGenerator: IIdentifierNamesGenerator;
switch (options.identifierNamesGenerator) {
case IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator:
identifierNamesGenerator = context.container.getNamed<IIdentifierNamesGenerator>(
ServiceIdentifiers.IIdentifierNamesGenerator,
IdentifierNamesGenerator.DictionaryIdentifierNamesGenerator
);
break;
case IdentifierNamesGenerator.MangledIdentifierNamesGenerator:
identifierNamesGenerator = context.container.getNamed<IIdentifierNamesGenerator>(
ServiceIdentifiers.IIdentifierNamesGenerator,
IdentifierNamesGenerator.MangledIdentifierNamesGenerator
);
break;
case IdentifierNamesGenerator.MangledShuffledIdentifierNamesGenerator:
identifierNamesGenerator = context.container.getNamed<IIdentifierNamesGenerator>(
ServiceIdentifiers.IIdentifierNamesGenerator,
IdentifierNamesGenerator.MangledShuffledIdentifierNamesGenerator
);
break;
case IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator:
default:
identifierNamesGenerator = context.container.getNamed<IIdentifierNamesGenerator>(
ServiceIdentifiers.IIdentifierNamesGenerator,
IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator
);
}
cachedIdentifierNamesGenerator = identifierNamesGenerator;
return identifierNamesGenerator;
};
}
bind<IIdentifierNamesGenerator>(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
.toFactory<IIdentifierNamesGenerator>(identifierNameGeneratorFactory());
});
@@ -0,0 +1,49 @@
import { InversifyContainerFacade } from '../../InversifyContainerFacade';
import { ContainerModule, interfaces } from 'inversify';
import { ServiceIdentifiers } from '../../ServiceIdentifiers';
import { IControlFlowReplacer } from '../../../interfaces/node-transformers/control-flow-transformers/IControlFlowReplacer';
import { INodeTransformer } from '../../../interfaces/node-transformers/INodeTransformer';
import { ControlFlowReplacer } from '../../../enums/node-transformers/control-flow-transformers/control-flow-replacers/ControlFlowReplacer';
import { NodeTransformer } from '../../../enums/node-transformers/NodeTransformer';
import { BinaryExpressionControlFlowReplacer } from '../../../node-transformers/control-flow-transformers/control-flow-replacers/BinaryExpressionControlFlowReplacer';
import { BlockStatementControlFlowTransformer } from '../../../node-transformers/control-flow-transformers/BlockStatementControlFlowTransformer';
import { CallExpressionControlFlowReplacer } from '../../../node-transformers/control-flow-transformers/control-flow-replacers/CallExpressionControlFlowReplacer';
import { FunctionControlFlowTransformer } from '../../../node-transformers/control-flow-transformers/FunctionControlFlowTransformer';
import { LogicalExpressionControlFlowReplacer } from '../../../node-transformers/control-flow-transformers/control-flow-replacers/LogicalExpressionControlFlowReplacer';
import { StringLiteralControlFlowReplacer } from '../../../node-transformers/control-flow-transformers/control-flow-replacers/StringLiteralControlFlowReplacer';
export const controlFlowTransformersModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
// control flow transformers
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(BlockStatementControlFlowTransformer)
.whenTargetNamed(NodeTransformer.BlockStatementControlFlowTransformer);
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(FunctionControlFlowTransformer)
.whenTargetNamed(NodeTransformer.FunctionControlFlowTransformer);
// control flow replacers
bind<IControlFlowReplacer>(ServiceIdentifiers.IControlFlowReplacer)
.to(BinaryExpressionControlFlowReplacer)
.whenTargetNamed(ControlFlowReplacer.BinaryExpressionControlFlowReplacer);
bind<IControlFlowReplacer>(ServiceIdentifiers.IControlFlowReplacer)
.to(CallExpressionControlFlowReplacer)
.whenTargetNamed(ControlFlowReplacer.CallExpressionControlFlowReplacer);
bind<IControlFlowReplacer>(ServiceIdentifiers.IControlFlowReplacer)
.to(LogicalExpressionControlFlowReplacer)
.whenTargetNamed(ControlFlowReplacer.LogicalExpressionControlFlowReplacer);
bind<IControlFlowReplacer>(ServiceIdentifiers.IControlFlowReplacer)
.to(StringLiteralControlFlowReplacer)
.whenTargetNamed(ControlFlowReplacer.StringLiteralControlFlowReplacer);
// control flow replacer factory
bind<IControlFlowReplacer>(ServiceIdentifiers.Factory__IControlFlowReplacer)
.toFactory<IControlFlowReplacer>(InversifyContainerFacade
.getCacheFactory<ControlFlowReplacer, IControlFlowReplacer>(ServiceIdentifiers.IControlFlowReplacer));
});
@@ -0,0 +1,86 @@
import { ContainerModule, interfaces } from 'inversify';
import { InversifyContainerFacade } from '../../InversifyContainerFacade';
import { ServiceIdentifiers } from '../../ServiceIdentifiers';
import { INodeTransformer } from '../../../interfaces/node-transformers/INodeTransformer';
import { IObjectExpressionExtractor } from '../../../interfaces/node-transformers/converting-transformers/object-expression-extractors/IObjectExpressionExtractor';
import { NodeTransformer } from '../../../enums/node-transformers/NodeTransformer';
import { ObjectExpressionExtractor } from '../../../enums/node-transformers/converting-transformers/properties-extractors/ObjectExpressionExtractor';
import { BasePropertiesExtractor } from '../../../node-transformers/converting-transformers/object-expression-extractors/BasePropertiesExtractor';
import { BooleanLiteralTransformer } from '../../../node-transformers/converting-transformers/BooleanLiteralTransformer';
import { ExportSpecifierTransformer } from '../../../node-transformers/converting-transformers/ExportSpecifierTransformer';
import { MemberExpressionTransformer } from '../../../node-transformers/converting-transformers/MemberExpressionTransformer';
import { MethodDefinitionTransformer } from '../../../node-transformers/converting-transformers/MethodDefinitionTransformer';
import { NumberLiteralTransformer } from '../../../node-transformers/converting-transformers/NumberLiteralTransformer';
import { NumberToNumericalExpressionTransformer } from '../../../node-transformers/converting-transformers/NumberToNumericalExpressionTransformer';
import { ObjectExpressionKeysTransformer } from '../../../node-transformers/converting-transformers/ObjectExpressionKeysTransformer';
import { ObjectExpressionToVariableDeclarationExtractor } from '../../../node-transformers/converting-transformers/object-expression-extractors/ObjectExpressionToVariableDeclarationExtractor';
import { ObjectExpressionTransformer } from '../../../node-transformers/converting-transformers/ObjectExpressionTransformer';
import { ObjectPatternPropertiesTransformer } from '../../../node-transformers/converting-transformers/ObjectPatternPropertiesTransformer';
import { SplitStringTransformer } from '../../../node-transformers/converting-transformers/SplitStringTransformer';
import { TemplateLiteralTransformer } from '../../../node-transformers/converting-transformers/TemplateLiteralTransformer';
export const convertingTransformersModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
// converting transformers
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(BooleanLiteralTransformer)
.whenTargetNamed(NodeTransformer.BooleanLiteralTransformer);
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(ExportSpecifierTransformer)
.whenTargetNamed(NodeTransformer.ExportSpecifierTransformer);
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(MemberExpressionTransformer)
.whenTargetNamed(NodeTransformer.MemberExpressionTransformer);
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(MethodDefinitionTransformer)
.whenTargetNamed(NodeTransformer.MethodDefinitionTransformer);
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(NumberLiteralTransformer)
.whenTargetNamed(NodeTransformer.NumberLiteralTransformer);
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(NumberToNumericalExpressionTransformer)
.whenTargetNamed(NodeTransformer.NumberToNumericalExpressionTransformer);
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(ObjectExpressionKeysTransformer)
.whenTargetNamed(NodeTransformer.ObjectExpressionKeysTransformer);
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(ObjectExpressionTransformer)
.whenTargetNamed(NodeTransformer.ObjectExpressionTransformer);
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(ObjectPatternPropertiesTransformer)
.whenTargetNamed(NodeTransformer.ObjectPatternPropertiesTransformer);
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(SplitStringTransformer)
.whenTargetNamed(NodeTransformer.SplitStringTransformer);
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(TemplateLiteralTransformer)
.whenTargetNamed(NodeTransformer.TemplateLiteralTransformer);
// object expression extractors
bind<IObjectExpressionExtractor>(ServiceIdentifiers.IObjectExpressionExtractor)
.to(ObjectExpressionToVariableDeclarationExtractor)
.whenTargetNamed(ObjectExpressionExtractor.ObjectExpressionToVariableDeclarationExtractor);
bind<IObjectExpressionExtractor>(ServiceIdentifiers.IObjectExpressionExtractor)
.to(BasePropertiesExtractor)
.whenTargetNamed(ObjectExpressionExtractor.BasePropertiesExtractor);
// object expression extractor factory
bind<IObjectExpressionExtractor>(ServiceIdentifiers.Factory__IObjectExpressionExtractor)
.toFactory<IObjectExpressionExtractor>(InversifyContainerFacade
.getCacheFactory<ObjectExpressionExtractor, IObjectExpressionExtractor>(
ServiceIdentifiers.IObjectExpressionExtractor
));
});
@@ -0,0 +1,15 @@
import { ContainerModule, interfaces } from 'inversify';
import { ServiceIdentifiers } from '../../ServiceIdentifiers';
import { INodeTransformer } from '../../../interfaces/node-transformers/INodeTransformer';
import { NodeTransformer } from '../../../enums/node-transformers/NodeTransformer';
import { DeadCodeInjectionTransformer } from '../../../node-transformers/dead-code-injection-transformers/DeadCodeInjectionTransformer';
export const deadCodeInjectionTransformersModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
// dead code injection
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(DeadCodeInjectionTransformer)
.whenTargetNamed(NodeTransformer.DeadCodeInjectionTransformer);
});
@@ -0,0 +1,15 @@
import { ContainerModule, interfaces } from 'inversify';
import { ServiceIdentifiers } from '../../ServiceIdentifiers';
import { INodeTransformer } from '../../../interfaces/node-transformers/INodeTransformer';
import { NodeTransformer } from '../../../enums/node-transformers/NodeTransformer';
import { EscapeSequenceTransformer } from '../../../node-transformers/finalizing-transformers/EscapeSequenceTransformer';
export const finalizingTransformersModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
// finalizing transformers
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(EscapeSequenceTransformer)
.whenTargetNamed(NodeTransformer.EscapeSequenceTransformer);
});
@@ -0,0 +1,15 @@
import { ContainerModule, interfaces } from 'inversify';
import { ServiceIdentifiers } from '../../ServiceIdentifiers';
import { INodeTransformer } from '../../../interfaces/node-transformers/INodeTransformer';
import { NodeTransformer } from '../../../enums/node-transformers/NodeTransformer';
import { CommentsTransformer } from '../../../node-transformers/initializing-transformers/CommentsTransformer';
export const initializingTransformersModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
// preparing transformers
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(CommentsTransformer)
.whenTargetNamed(NodeTransformer.CommentsTransformer);
});
@@ -0,0 +1,22 @@
import { InversifyContainerFacade } from '../../InversifyContainerFacade';
import { ContainerModule, interfaces } from 'inversify';
import { ServiceIdentifiers } from '../../ServiceIdentifiers';
import { INodeTransformer } from '../../../interfaces/node-transformers/INodeTransformer';
import { ITransformerNamesGroupsBuilder } from '../../../interfaces/utils/ITransformerNamesGroupsBuilder';
import { NodeTransformer } from '../../../enums/node-transformers/NodeTransformer';
import { NodeTransformerNamesGroupsBuilder } from '../../../node-transformers/NodeTransformerNamesGroupsBuilder';
export const nodeTransformersModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
// node transformers factory
bind<INodeTransformer>(ServiceIdentifiers.Factory__INodeTransformer)
.toFactory<INodeTransformer>(InversifyContainerFacade
.getCacheFactory<NodeTransformer, INodeTransformer>(ServiceIdentifiers.INodeTransformer));
// node transformer names groups builder
bind<ITransformerNamesGroupsBuilder<NodeTransformer, INodeTransformer>>(ServiceIdentifiers.INodeTransformerNamesGroupsBuilder)
.to(NodeTransformerNamesGroupsBuilder)
.inSingletonScope();
});
@@ -0,0 +1,81 @@
import { InversifyContainerFacade } from '../../InversifyContainerFacade';
import { ContainerModule, interfaces } from 'inversify';
import { ServiceIdentifiers } from '../../ServiceIdentifiers';
import { INodeTransformer } from '../../../interfaces/node-transformers/INodeTransformer';
import { IObfuscatingGuard } from '../../../interfaces/node-transformers/preparing-transformers/obfuscating-guards/IObfuscatingGuard';
import { NodeTransformer } from '../../../enums/node-transformers/NodeTransformer';
import { ObfuscatingGuard } from '../../../enums/node-transformers/preparing-transformers/obfuscating-guards/ObfuscatingGuard';
import { BlackListObfuscatingGuard } from '../../../node-transformers/preparing-transformers/obfuscating-guards/BlackListObfuscatingGuard';
import { ConditionalCommentObfuscatingGuard } from '../../../node-transformers/preparing-transformers/obfuscating-guards/ConditionalCommentObfuscatingGuard';
import { CustomCodeHelpersTransformer } from '../../../node-transformers/preparing-transformers/CustomCodeHelpersTransformer';
import { EvalCallExpressionTransformer } from '../../../node-transformers/preparing-transformers/EvalCallExpressionTransformer';
import { ForceTransformStringObfuscatingGuard } from '../../../node-transformers/preparing-transformers/obfuscating-guards/ForceTransformStringObfuscatingGuard';
import { IgnoredRequireImportObfuscatingGuard } from '../../../node-transformers/preparing-transformers/obfuscating-guards/IgnoredRequireImportObfuscatingGuard';
import { MetadataTransformer } from '../../../node-transformers/preparing-transformers/MetadataTransformer';
import { ObfuscatingGuardsTransformer } from '../../../node-transformers/preparing-transformers/ObfuscatingGuardsTransformer';
import { ParentificationTransformer } from '../../../node-transformers/preparing-transformers/ParentificationTransformer';
import { ReservedStringObfuscatingGuard } from '../../../node-transformers/preparing-transformers/obfuscating-guards/ReservedStringObfuscatingGuard';
import { VariablePreserveTransformer } from '../../../node-transformers/preparing-transformers/VariablePreserveTransformer';
export const preparingTransformersModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
// preparing transformers
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(CustomCodeHelpersTransformer)
.whenTargetNamed(NodeTransformer.CustomCodeHelpersTransformer);
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(EvalCallExpressionTransformer)
.whenTargetNamed(NodeTransformer.EvalCallExpressionTransformer);
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(MetadataTransformer)
.whenTargetNamed(NodeTransformer.MetadataTransformer);
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(ObfuscatingGuardsTransformer)
.whenTargetNamed(NodeTransformer.ObfuscatingGuardsTransformer);
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(ParentificationTransformer)
.whenTargetNamed(NodeTransformer.ParentificationTransformer);
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(VariablePreserveTransformer)
.whenTargetNamed(NodeTransformer.VariablePreserveTransformer);
// obfuscating guards
bind<IObfuscatingGuard>(ServiceIdentifiers.INodeGuard)
.to(BlackListObfuscatingGuard)
.inSingletonScope()
.whenTargetNamed(ObfuscatingGuard.BlackListObfuscatingGuard);
bind<IObfuscatingGuard>(ServiceIdentifiers.INodeGuard)
.to(ConditionalCommentObfuscatingGuard)
.inSingletonScope()
.whenTargetNamed(ObfuscatingGuard.ConditionalCommentObfuscatingGuard);
bind<IObfuscatingGuard>(ServiceIdentifiers.INodeGuard)
.to(ForceTransformStringObfuscatingGuard)
.inSingletonScope()
.whenTargetNamed(ObfuscatingGuard.ForceTransformStringObfuscatingGuard);
bind<IObfuscatingGuard>(ServiceIdentifiers.INodeGuard)
.to(IgnoredRequireImportObfuscatingGuard)
.inSingletonScope()
.whenTargetNamed(ObfuscatingGuard.IgnoredRequireImportObfuscatingGuard);
bind<IObfuscatingGuard>(ServiceIdentifiers.INodeGuard)
.to(ReservedStringObfuscatingGuard)
.inSingletonScope()
.whenTargetNamed(ObfuscatingGuard.ReservedStringObfuscatingGuard);
// obfuscating guards factory
bind<IObfuscatingGuard>(ServiceIdentifiers.Factory__INodeGuard)
.toFactory<IObfuscatingGuard>(InversifyContainerFacade
.getCacheFactory<ObfuscatingGuard, IObfuscatingGuard>(
ServiceIdentifiers.INodeGuard
));
});
@@ -0,0 +1,32 @@
import { ContainerModule, interfaces } from 'inversify';
import { ServiceIdentifiers } from '../../ServiceIdentifiers';
import { IIdentifierReplacer } from '../../../interfaces/node-transformers/rename-identifiers-transformers/replacer/IIdentifierReplacer';
import { INodeTransformer } from '../../../interfaces/node-transformers/INodeTransformer';
import { NodeTransformer } from '../../../enums/node-transformers/NodeTransformer';
import { IdentifierReplacer } from '../../../node-transformers/rename-identifiers-transformers/replacer/IdentifierReplacer';
import { LabeledStatementTransformer } from '../../../node-transformers/rename-identifiers-transformers/LabeledStatementTransformer';
import { ScopeIdentifiersTransformer } from '../../../node-transformers/rename-identifiers-transformers/ScopeIdentifiersTransformer';
import { ScopeThroughIdentifiersTransformer } from '../../../node-transformers/rename-identifiers-transformers/ScopeThroughIdentifiersTransformer';
export const renameIdentifiersTransformersModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
// rename identifiers transformers
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(LabeledStatementTransformer)
.whenTargetNamed(NodeTransformer.LabeledStatementTransformer);
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(ScopeIdentifiersTransformer)
.whenTargetNamed(NodeTransformer.ScopeIdentifiersTransformer);
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(ScopeThroughIdentifiersTransformer)
.whenTargetNamed(NodeTransformer.ScopeThroughIdentifiersTransformer);
// identifier replacer
bind<IIdentifierReplacer>(ServiceIdentifiers.IIdentifierReplacer)
.to(IdentifierReplacer)
.inSingletonScope();
});
@@ -0,0 +1,21 @@
import { ContainerModule, interfaces } from 'inversify';
import { ServiceIdentifiers } from '../../ServiceIdentifiers';
import { IRenamePropertiesReplacer } from '../../../interfaces/node-transformers/rename-properties-transformers/replacer/IRenamePropertiesReplacer';
import { INodeTransformer } from '../../../interfaces/node-transformers/INodeTransformer';
import { NodeTransformer } from '../../../enums/node-transformers/NodeTransformer';
import { RenamePropertiesReplacer } from '../../../node-transformers/rename-properties-transformers/replacer/RenamePropertiesReplacer';
import { RenamePropertiesTransformer } from '../../../node-transformers/rename-properties-transformers/RenamePropertiesTransformer';
export const renamePropertiesTransformersModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
// rename properties transformers
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(RenamePropertiesTransformer)
.whenTargetNamed(NodeTransformer.RenamePropertiesTransformer);
// rename properties obfuscating replacer
bind<IRenamePropertiesReplacer>(ServiceIdentifiers.IRenamePropertiesReplacer)
.to(RenamePropertiesReplacer);
});
@@ -0,0 +1,30 @@
import { ContainerModule, interfaces } from 'inversify';
import { ServiceIdentifiers } from '../../ServiceIdentifiers';
import { INodeTransformer } from '../../../interfaces/node-transformers/INodeTransformer';
import { NodeTransformer } from '../../../enums/node-transformers/NodeTransformer';
import { BlockStatementSimplifyTransformer } from '../../../node-transformers/simplifying-transformers/BlockStatementSimplifyTransformer';
import { ExpressionStatementsMergeTransformer } from '../../../node-transformers/simplifying-transformers/ExpressionStatementsMergeTransformer';
import { IfStatementSimplifyTransformer } from '../../../node-transformers/simplifying-transformers/IfStatementSimplifyTransformer';
import { VariableDeclarationsMergeTransformer } from '../../../node-transformers/simplifying-transformers/VariableDeclarationsMergeTransformer';
export const simplifyingTransformersModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
// simplifying transformers
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(BlockStatementSimplifyTransformer)
.whenTargetNamed(NodeTransformer.BlockStatementSimplifyTransformer);
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(ExpressionStatementsMergeTransformer)
.whenTargetNamed(NodeTransformer.ExpressionStatementsMergeTransformer);
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(IfStatementSimplifyTransformer)
.whenTargetNamed(NodeTransformer.IfStatementSimplifyTransformer);
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(VariableDeclarationsMergeTransformer)
.whenTargetNamed(NodeTransformer.VariableDeclarationsMergeTransformer);
});
@@ -0,0 +1,20 @@
import { ContainerModule, interfaces } from 'inversify';
import { ServiceIdentifiers } from '../../ServiceIdentifiers';
import { INodeTransformer } from '../../../interfaces/node-transformers/INodeTransformer';
import { NodeTransformer } from '../../../enums/node-transformers/NodeTransformer';
import { StringArrayScopeCallsWrapperTransformer } from '../../../node-transformers/string-array-transformers/StringArrayScopeCallsWrapperTransformer';
import { StringArrayTransformer } from '../../../node-transformers/string-array-transformers/StringArrayTransformer';
export const stringArrayTransformersModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
// strings transformers
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(StringArrayScopeCallsWrapperTransformer)
.whenTargetNamed(NodeTransformer.StringArrayScopeCallsWrapperTransformer);
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(StringArrayTransformer)
.whenTargetNamed(NodeTransformer.StringArrayTransformer);
});
@@ -0,0 +1,13 @@
import { ContainerModule, interfaces } from 'inversify';
import { ServiceIdentifiers } from '../../ServiceIdentifiers';
import { IScopeIdentifiersTraverser } from '../../../interfaces/node/IScopeIdentifiersTraverser';
import { ScopeIdentifiersTraverser } from '../../../node/ScopeIdentifiersTraverser';
export const nodeModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
// scope identifiers traverser
bind<IScopeIdentifiersTraverser>(ServiceIdentifiers.IScopeIdentifiersTraverser)
.to(ScopeIdentifiersTraverser)
.inSingletonScope();
});
@@ -0,0 +1,18 @@
import { ContainerModule, interfaces } from 'inversify';
import { ServiceIdentifiers } from '../../ServiceIdentifiers';
import { IOptions } from '../../../interfaces/options/IOptions';
import { IOptionsNormalizer } from '../../../interfaces/options/IOptionsNormalizer';
import { Options } from '../../../options/Options';
import { OptionsNormalizer } from '../../../options/OptionsNormalizer';
export const optionsModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
bind<IOptions>(ServiceIdentifiers.IOptions)
.to(Options)
.inSingletonScope();
bind<IOptionsNormalizer>(ServiceIdentifiers.IOptionsNormalizer)
.to(OptionsNormalizer)
.inSingletonScope();
});
@@ -0,0 +1,70 @@
import { ContainerModule, interfaces } from 'inversify';
import { ServiceIdentifiers } from '../../ServiceIdentifiers';
import { TControlFlowStorage } from '../../../types/storages/TControlFlowStorage';
import { TCustomCodeHelperGroupStorage } from '../../../types/storages/TCustomCodeHelperGroupStorage';
import { ILiteralNodesCacheStorage } from '../../../interfaces/storages/string-array-transformers/ILiteralNodesCacheStorage';
import { IOptions } from '../../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../../interfaces/utils/IRandomGenerator';
import { IStringArrayScopeCallsWrapperLexicalScopeDataStorage } from '../../../interfaces/storages/string-array-transformers/IStringArrayScopeCallsWrapperLexicalScopeDataStorage';
import { IStringArrayScopeCallsWrapperNamesDataStorage } from '../../../interfaces/storages/string-array-transformers/IStringArrayScopeCallsWrapperNamesDataStorage';
import { IStringArrayStorage } from '../../../interfaces/storages/string-array-transformers/IStringArrayStorage';
import { IVisitedLexicalScopeNodesStackStorage } from '../../../interfaces/storages/string-array-transformers/IVisitedLexicalScopeNodesStackStorage';
import { ControlFlowStorage } from '../../../storages/custom-nodes/ControlFlowStorage';
import { CustomCodeHelperGroupStorage } from '../../../storages/custom-code-helpers/CustomCodeHelperGroupStorage';
import { LiteralNodesCacheStorage } from '../../../storages/string-array-transformers/LiteralNodesCacheStorage';
import { StringArrayScopeCallsWrapperLexicalScopeDataStorage } from '../../../storages/string-array-transformers/StringArrayScopeCallsWrapperLexicalScopeDataStorage';
import { StringArrayScopeCallsWrapperNamesDataStorage } from '../../../storages/string-array-transformers/StringArrayScopeCallsWrapperNamesDataStorage';
import { StringArrayStorage } from '../../../storages/string-array-transformers/StringArrayStorage';
import { VisitedLexicalScopeNodesStackStorage } from '../../../storages/string-array-transformers/VisitedLexicalScopeNodesStackStorage';
export const storagesModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
// storages
bind<TCustomCodeHelperGroupStorage>(ServiceIdentifiers.TCustomNodeGroupStorage)
.to(CustomCodeHelperGroupStorage)
.inSingletonScope();
bind<ILiteralNodesCacheStorage>(ServiceIdentifiers.ILiteralNodesCacheStorage)
.to(LiteralNodesCacheStorage)
.inSingletonScope();
bind<IStringArrayStorage>(ServiceIdentifiers.IStringArrayStorage)
.to(StringArrayStorage)
.inSingletonScope();
bind<IStringArrayScopeCallsWrapperLexicalScopeDataStorage>(ServiceIdentifiers.IStringArrayScopeCallsWrapperLexicalScopeDataStorage)
.to(StringArrayScopeCallsWrapperLexicalScopeDataStorage)
.inSingletonScope();
bind<IStringArrayScopeCallsWrapperNamesDataStorage>(ServiceIdentifiers.IStringArrayScopeCallsWrapperNamesDataStorage)
.to(StringArrayScopeCallsWrapperNamesDataStorage)
.inSingletonScope();
bind<IVisitedLexicalScopeNodesStackStorage>(ServiceIdentifiers.IVisitedLexicalScopeNodesStackStorage)
.to(VisitedLexicalScopeNodesStackStorage)
.inSingletonScope();
bind<interfaces.Newable<TControlFlowStorage>>(ServiceIdentifiers.Newable__TControlFlowStorage)
.toConstructor(ControlFlowStorage);
// controlFlowStorage factory
bind<TControlFlowStorage>(ServiceIdentifiers.Factory__TControlFlowStorage)
.toFactory<TControlFlowStorage>((context: interfaces.Context) => {
return (): TControlFlowStorage => {
const constructor: interfaces.Newable<TControlFlowStorage> = context.container
.get<interfaces.Newable<TControlFlowStorage>>(ServiceIdentifiers.Newable__TControlFlowStorage);
const randomGenerator: IRandomGenerator = context.container
.get<IRandomGenerator>(ServiceIdentifiers.IRandomGenerator);
const options: IOptions = context.container
.get<IOptions>(ServiceIdentifiers.IOptions);
const storage: TControlFlowStorage = new constructor(randomGenerator, options);
storage.initialize();
return storage;
};
});
});
@@ -0,0 +1,47 @@
import { ContainerModule, interfaces } from 'inversify';
import { ServiceIdentifiers } from '../../ServiceIdentifiers';
import { IArrayUtils } from '../../../interfaces/utils/IArrayUtils';
import { ICryptUtils } from '../../../interfaces/utils/ICryptUtils';
import { ICryptUtilsSwappedAlphabet } from '../../../interfaces/utils/ICryptUtilsSwappedAlphabet';
import { IEscapeSequenceEncoder } from '../../../interfaces/utils/IEscapeSequenceEncoder';
import { ILevelledTopologicalSorter } from '../../../interfaces/utils/ILevelledTopologicalSorter';
import { IRandomGenerator } from '../../../interfaces/utils/IRandomGenerator';
import { ArrayUtils } from '../../../utils/ArrayUtils';
import { CryptUtils } from '../../../utils/CryptUtils';
import { CryptUtilsSwappedAlphabet } from '../../../utils/CryptUtilsSwappedAlphabet';
import { EscapeSequenceEncoder } from '../../../utils/EscapeSequenceEncoder';
import { LevelledTopologicalSorter } from '../../../utils/LevelledTopologicalSorter';
import { RandomGenerator } from '../../../utils/RandomGenerator';
export const utilsModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
// array utils
bind<IArrayUtils>(ServiceIdentifiers.IArrayUtils)
.to(ArrayUtils)
.inSingletonScope();
// random generator
bind<IRandomGenerator>(ServiceIdentifiers.IRandomGenerator)
.to(RandomGenerator)
.inSingletonScope();
// crypt utils
bind<ICryptUtils>(ServiceIdentifiers.ICryptUtils)
.to(CryptUtils)
.inSingletonScope();
// crypt utils with swapped alphabet
bind<ICryptUtilsSwappedAlphabet>(ServiceIdentifiers.ICryptUtilsSwappedAlphabet)
.to(CryptUtilsSwappedAlphabet)
.inSingletonScope();
// escape sequence encoder
bind<IEscapeSequenceEncoder>(ServiceIdentifiers.IEscapeSequenceEncoder)
.to(EscapeSequenceEncoder)
.inSingletonScope();
// levelled topological sorter
bind<ILevelledTopologicalSorter>(ServiceIdentifiers.ILevelledTopologicalSorter)
.to(LevelledTopologicalSorter);
});
@@ -0,0 +1,121 @@
import { inject, injectable } from 'inversify';
import { ServiceIdentifiers } from '../container/ServiceIdentifiers';
import { TIdentifierNamesGeneratorFactory } from '../types/container/generators/TIdentifierNamesGeneratorFactory';
import { TStatement } from '../types/node/TStatement';
import { ICustomCodeHelper } from '../interfaces/custom-code-helpers/ICustomCodeHelper';
import { ICustomCodeHelperFormatter } from '../interfaces/custom-code-helpers/ICustomCodeHelperFormatter';
import { ICustomCodeHelperObfuscator } from '../interfaces/custom-code-helpers/ICustomCodeHelperObfuscator';
import { IIdentifierNamesGenerator } from '../interfaces/generators/identifier-names-generators/IIdentifierNamesGenerator';
import { IOptions } from '../interfaces/options/IOptions';
import { IRandomGenerator } from '../interfaces/utils/IRandomGenerator';
import { GlobalVariableTemplate1 } from './common/templates/GlobalVariableTemplate1';
import { GlobalVariableTemplate2 } from './common/templates/GlobalVariableTemplate2';
@injectable()
export abstract class AbstractCustomCodeHelper <
TInitialData extends unknown[] = unknown[]
> implements ICustomCodeHelper <TInitialData> {
/**
* @type {string[]}
*/
private static readonly globalVariableTemplateFunctions: string[] = [
GlobalVariableTemplate1(),
GlobalVariableTemplate2()
];
/**
* @type {TStatement[] | null}
*/
protected cachedNode: TStatement[] | null = null;
/**
* @type {ICustomCodeHelperFormatter}
*/
protected readonly customCodeHelperFormatter: ICustomCodeHelperFormatter;
/**
* @type {ICustomCodeHelperObfuscator}
*/
protected readonly customCodeHelperObfuscator: ICustomCodeHelperObfuscator;
/**
* @type {IIdentifierNamesGenerator}
*/
protected readonly identifierNamesGenerator: IIdentifierNamesGenerator;
/**
* @type {IOptions}
*/
protected readonly options: IOptions;
/**
* @type {IRandomGenerator}
*/
protected readonly randomGenerator: IRandomGenerator;
/**
* @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
* @param {ICustomCodeHelperFormatter} customCodeHelperFormatter
* @param {ICustomCodeHelperObfuscator} customCodeHelperObfuscator
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
*/
protected constructor (
@inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
@inject(ServiceIdentifiers.ICustomCodeHelperFormatter) customCodeHelperFormatter: ICustomCodeHelperFormatter,
@inject(ServiceIdentifiers.ICustomCodeHelperObfuscator) customCodeHelperObfuscator: ICustomCodeHelperObfuscator,
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
this.identifierNamesGenerator = identifierNamesGeneratorFactory(options);
this.customCodeHelperFormatter = customCodeHelperFormatter;
this.customCodeHelperObfuscator = customCodeHelperObfuscator;
this.randomGenerator = randomGenerator;
this.options = options;
}
/**
* @returns {TStatement[]}
*/
public getNode (): TStatement[] {
if (!this.cachedNode) {
const codeHelperTemplate: string = this.getCodeHelperTemplate();
this.cachedNode = this.customCodeHelperFormatter.formatStructure(
this.getNodeStructure(codeHelperTemplate)
);
}
return this.cachedNode;
}
/**
* @returns {string}
*/
protected getGlobalVariableTemplate (): string {
return this.randomGenerator
.getRandomGenerator()
.pickone(AbstractCustomCodeHelper.globalVariableTemplateFunctions);
}
/**
* @returns {string}
*/
protected getCodeHelperTemplate (): string {
return '';
}
/**
* @param {TInitialData} args
*/
public abstract initialize (...args: TInitialData): void;
/**
* @returns {TStatement[]}
*/
protected abstract getNodeStructure (codeHelperTemplate: string): TStatement[];
}
@@ -0,0 +1,104 @@
import { inject, injectable } from 'inversify';
import { ServiceIdentifiers } from '../container/ServiceIdentifiers';
import { TIdentifierNamesGeneratorFactory } from '../types/container/generators/TIdentifierNamesGeneratorFactory';
import { TNodeWithStatements } from '../types/node/TNodeWithStatements';
import { ICallsGraphData } from '../interfaces/analyzers/calls-graph-analyzer/ICallsGraphData';
import { ICustomCodeHelper } from '../interfaces/custom-code-helpers/ICustomCodeHelper';
import { ICustomCodeHelperGroup } from '../interfaces/custom-code-helpers/ICustomCodeHelperGroup';
import { IIdentifierNamesGenerator } from '../interfaces/generators/identifier-names-generators/IIdentifierNamesGenerator';
import { IOptions } from '../interfaces/options/IOptions';
import { IRandomGenerator } from '../interfaces/utils/IRandomGenerator';
import { CustomCodeHelper } from '../enums/custom-code-helpers/CustomCodeHelper';
import { ObfuscationEvent } from '../enums/event-emitters/ObfuscationEvent';
@injectable()
export abstract class AbstractCustomCodeHelperGroup implements ICustomCodeHelperGroup {
/**
* @type {IIdentifierNamesGenerator}
*/
protected readonly identifierNamesGenerator: IIdentifierNamesGenerator;
/**
* @type {IOptions}
*/
protected readonly options: IOptions;
/**
* @type {IRandomGenerator}
*/
protected readonly randomGenerator: IRandomGenerator;
/**
* @type {ObfuscationEvent}
*/
protected abstract readonly appendEvent: ObfuscationEvent;
/**
* @type {Map<CustomCodeHelper, ICustomCodeHelper>}
*/
protected abstract customCodeHelpers: Map <CustomCodeHelper, ICustomCodeHelper>;
/**
* @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
*/
public constructor (
@inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
this.identifierNamesGenerator = identifierNamesGeneratorFactory(options);
this.randomGenerator = randomGenerator;
this.options = options;
}
/**
* @returns {ObfuscationEvent}
*/
public getAppendEvent (): ObfuscationEvent {
return this.appendEvent;
}
/**
* @returns {Map<CustomCodeHelper, ICustomCodeHelper>}
*/
public getCustomCodeHelpers (): Map <CustomCodeHelper, ICustomCodeHelper> {
return this.customCodeHelpers;
}
/**
* @param {CustomCodeHelper} customCodeHelperName
* @param {callback} callback
*/
protected appendCustomNodeIfExist (customCodeHelperName: CustomCodeHelper, callback: (customCodeHelper: ICustomCodeHelper) => void): void {
const customCodeHelper: ICustomCodeHelper | undefined = this.customCodeHelpers.get(customCodeHelperName);
if (!customCodeHelper) {
return;
}
callback(customCodeHelper);
}
/**
* @param {number} callsGraphLength
* @returns {number}
*/
protected getRandomCallsGraphIndex (callsGraphLength: number): number {
return this.randomGenerator.getRandomInteger(0, Math.max(0, Math.round(callsGraphLength - 1)));
}
/**
* @param {TNodeWithStatements} nodeWithStatements
* @param {ICallsGraphData[]} callsGraphData
*/
public abstract appendNodes (nodeWithStatements: TNodeWithStatements, callsGraphData: ICallsGraphData[]): void;
public abstract initialize (): void;
}
@@ -0,0 +1,65 @@
import { inject, injectable } from 'inversify';
import { ServiceIdentifiers } from '../container/ServiceIdentifiers';
import * as estraverse from 'estraverse';
import * as ESTree from 'estree';
import format from 'string-template';
import { TDictionary } from '../types/TDictionary';
import { TStatement } from '../types/node/TStatement';
import { ICustomCodeHelperFormatter } from '../interfaces/custom-code-helpers/ICustomCodeHelperFormatter';
import { IPrevailingKindOfVariablesAnalyzer } from '../interfaces/analyzers/calls-graph-analyzer/IPrevailingKindOfVariablesAnalyzer';
import { NodeGuards } from '../node/NodeGuards';
@injectable()
export class CustomCodeHelperFormatter implements ICustomCodeHelperFormatter {
/**
* @type {ESTree.VariableDeclaration['kind']}
*/
private readonly prevailingKindOfVariables: ESTree.VariableDeclaration['kind'];
public constructor (
@inject(ServiceIdentifiers.IPrevailingKindOfVariablesAnalyzer)
prevailingKindOfVariablesAnalyzer: IPrevailingKindOfVariablesAnalyzer
) {
this.prevailingKindOfVariables = prevailingKindOfVariablesAnalyzer.getPrevailingKind();
}
/**
* @param {string} template
* @param {TMapping} mapping
* @returns {string}
*/
public formatTemplate <TMapping extends TDictionary> (
template: string,
mapping: TMapping
): string {
return format(template, mapping);
}
/**
* @param {TStatement[]} statements
* @returns {TStatement[]}
*/
public formatStructure (statements: TStatement[]): TStatement[] {
for (const statement of statements) {
estraverse.replace(statement, {
enter: (node: ESTree.Node): ESTree.Node | void => {
if (!NodeGuards.isVariableDeclarationNode(node)) {
return;
}
if (this.prevailingKindOfVariables === 'var') {
node.kind = 'var';
}
return node;
}
});
}
return statements;
}
}
@@ -0,0 +1,57 @@
import { inject, injectable } from 'inversify';
import { ServiceIdentifiers } from '../container/ServiceIdentifiers';
import { TInputOptions } from '../types/options/TInputOptions';
import { ICustomCodeHelperObfuscator } from '../interfaces/custom-code-helpers/ICustomCodeHelperObfuscator';
import { IOptions } from '../interfaces/options/IOptions';
import { IRandomGenerator } from '../interfaces/utils/IRandomGenerator';
import { NO_ADDITIONAL_NODES_PRESET } from '../options/presets/NoCustomNodes';
import { JavaScriptObfuscator } from '../JavaScriptObfuscatorFacade';
@injectable()
export class CustomCodeHelperObfuscator implements ICustomCodeHelperObfuscator {
/**
* @type {IOptions}
*/
private readonly options: IOptions;
/**
* @type {IRandomGenerator}
*/
private readonly randomGenerator: IRandomGenerator;
/**
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
*/
public constructor (
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
this.randomGenerator = randomGenerator;
this.options = options;
}
/**
* @param {string} template
* @param {TInputOptions} additionalOptions
* @returns {string}
*/
public obfuscateTemplate (template: string, additionalOptions: TInputOptions = {}): string {
return JavaScriptObfuscator.obfuscate(
template,
{
...NO_ADDITIONAL_NODES_PRESET,
identifierNamesGenerator: this.options.identifierNamesGenerator,
identifiersDictionary: this.options.identifiersDictionary,
numbersToExpressions: this.options.numbersToExpressions,
simplify: this.options.simplify,
seed: this.randomGenerator.getRawSeed(),
...additionalOptions
}
).getObfuscatedCode();
}
}
@@ -0,0 +1,92 @@
import { inject, injectable, } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import { TIdentifierNamesGeneratorFactory } from '../../types/container/generators/TIdentifierNamesGeneratorFactory';
import { TStatement } from '../../types/node/TStatement';
import { ICustomCodeHelperObfuscator } from '../../interfaces/custom-code-helpers/ICustomCodeHelperObfuscator';
import { ICustomCodeHelperFormatter } from '../../interfaces/custom-code-helpers/ICustomCodeHelperFormatter';
import { IOptions } from '../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
import { ObfuscationEvent } from '../../enums/event-emitters/ObfuscationEvent';
import { initializable } from '../../decorators/Initializable';
import { SingleCallControllerTemplate } from '../common/templates/SingleCallControllerTemplate';
import { AbstractCustomCodeHelper } from '../AbstractCustomCodeHelper';
import { NodeUtils } from '../../node/NodeUtils';
@injectable()
export class CallsControllerFunctionCodeHelper extends AbstractCustomCodeHelper {
/**
* @type {string}
*/
@initializable()
protected callsControllerFunctionName!: string;
/**
* @type {ObfuscationEvent}
*/
@initializable()
private appendEvent!: ObfuscationEvent;
/**
* @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
* @param {ICustomCodeHelperFormatter} customCodeHelperFormatter
* @param {ICustomCodeHelperObfuscator} customCodeHelperObfuscator
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
*/
public constructor (
@inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
@inject(ServiceIdentifiers.ICustomCodeHelperFormatter) customCodeHelperFormatter: ICustomCodeHelperFormatter,
@inject(ServiceIdentifiers.ICustomCodeHelperObfuscator) customCodeHelperObfuscator: ICustomCodeHelperObfuscator,
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
super(
identifierNamesGeneratorFactory,
customCodeHelperFormatter,
customCodeHelperObfuscator,
randomGenerator,
options
);
}
/**
* @param {ObfuscationEvent} appendEvent
* @param {string} callsControllerFunctionName
*/
public initialize (appendEvent: ObfuscationEvent, callsControllerFunctionName: string): void {
this.appendEvent = appendEvent;
this.callsControllerFunctionName = callsControllerFunctionName;
}
/**
* @param {string} codeHelperTemplate
* @returns {TStatement[]}
*/
protected getNodeStructure (codeHelperTemplate: string): TStatement[] {
return NodeUtils.convertCodeToStructure(codeHelperTemplate);
}
/**
* @returns {string}
*/
protected getCodeHelperTemplate (): string {
if (this.appendEvent === ObfuscationEvent.AfterObfuscation) {
return this.customCodeHelperObfuscator.obfuscateTemplate(
this.customCodeHelperFormatter.formatTemplate(SingleCallControllerTemplate(), {
callControllerFunctionName: this.callsControllerFunctionName
})
);
}
return this.customCodeHelperFormatter.formatTemplate(SingleCallControllerTemplate(), {
callControllerFunctionName: this.callsControllerFunctionName
});
}
}
@@ -0,0 +1,14 @@
/**
* @returns {string}
*/
export function GlobalVariableNoEvalTemplate (): string {
return `
const that = (typeof window !== 'undefined'
? window
: (typeof process === 'object' &&
typeof require === 'function' &&
typeof global === 'object')
? global
: this);
`;
}
@@ -0,0 +1,16 @@
/**
* @returns {string}
*/
export function GlobalVariableTemplate1 (): string {
return `
let that;
try {
const getGlobal = Function('return (function() ' + '{}.constructor("return this")( )' + ');');
that = getGlobal();
} catch (e) {
that = window;
}
`;
}
@@ -0,0 +1,19 @@
/**
* @returns {string}
*/
export function GlobalVariableTemplate2 (): string {
return `
const getGlobal = function () {
let globalObject;
try {
globalObject = Function('return (function() ' + '{}.constructor("return this")( )' + ');')();
} catch (e) {
globalObject = window;
}
return globalObject;
};
const that = getGlobal();
`;
}
@@ -0,0 +1,24 @@
/**
* @returns {string}
*/
export function SingleCallControllerTemplate (): string {
return `
const {callControllerFunctionName} = (function(){
let firstCall = true;
return function (context, fn){
const rfn = firstCall ? function(){
if(fn){
const res = fn.apply(context, arguments);
fn = null;
return res;
}
} : function(){}
firstCall = false;
return rfn;
}
})();
`;
}
@@ -0,0 +1,91 @@
import { inject, injectable, } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import { TIdentifierNamesGeneratorFactory } from '../../types/container/generators/TIdentifierNamesGeneratorFactory';
import { TStatement } from '../../types/node/TStatement';
import { ICustomCodeHelperFormatter } from '../../interfaces/custom-code-helpers/ICustomCodeHelperFormatter';
import { ICustomCodeHelperObfuscator } from '../../interfaces/custom-code-helpers/ICustomCodeHelperObfuscator';
import { IOptions } from '../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
import { ObfuscationTarget } from '../../enums/ObfuscationTarget';
import { ConsoleOutputDisableTemplate } from './templates/ConsoleOutputDisableTemplate';
import { GlobalVariableNoEvalTemplate } from '../common/templates/GlobalVariableNoEvalTemplate';
import { initializable } from '../../decorators/Initializable';
import { AbstractCustomCodeHelper } from '../AbstractCustomCodeHelper';
import { NodeUtils } from '../../node/NodeUtils';
@injectable()
export class ConsoleOutputDisableCodeHelper extends AbstractCustomCodeHelper {
/**
* @type {string}
*/
@initializable()
private callsControllerFunctionName!: string;
/**
* @type {string}
*/
@initializable()
private consoleOutputDisableFunctionName!: string;
/**
* @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
* @param {ICustomCodeHelperFormatter} customCodeHelperFormatter
* @param {ICustomCodeHelperObfuscator} customCodeHelperObfuscator
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
*/
public constructor (
@inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
@inject(ServiceIdentifiers.ICustomCodeHelperFormatter) customCodeHelperFormatter: ICustomCodeHelperFormatter,
@inject(ServiceIdentifiers.ICustomCodeHelperObfuscator) customCodeHelperObfuscator: ICustomCodeHelperObfuscator,
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
super(
identifierNamesGeneratorFactory,
customCodeHelperFormatter,
customCodeHelperObfuscator,
randomGenerator,
options
);
}
/**
* @param {string} callsControllerFunctionName
* @param {StaticRange} consoleOutputDisableFunctionName
*/
public initialize (callsControllerFunctionName: string, consoleOutputDisableFunctionName: string): void {
this.callsControllerFunctionName = callsControllerFunctionName;
this.consoleOutputDisableFunctionName = consoleOutputDisableFunctionName;
}
/**
* @param {string} codeHelperTemplate
* @returns {TStatement[]}
*/
protected getNodeStructure (codeHelperTemplate: string): TStatement[] {
return NodeUtils.convertCodeToStructure(codeHelperTemplate);
}
/**
* @returns {string}
*/
protected getCodeHelperTemplate (): string {
const globalVariableTemplate: string = this.options.target !== ObfuscationTarget.BrowserNoEval
? this.getGlobalVariableTemplate()
: GlobalVariableNoEvalTemplate();
return this.customCodeHelperFormatter.formatTemplate(ConsoleOutputDisableTemplate(), {
callControllerFunctionName: this.callsControllerFunctionName,
consoleLogDisableFunctionName: this.consoleOutputDisableFunctionName,
globalVariableTemplate
});
}
}
@@ -0,0 +1,126 @@
import { inject, injectable, } from 'inversify';
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';
import { IOptions } from '../../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../../interfaces/utils/IRandomGenerator';
import { ICallsGraphData } from '../../../interfaces/analyzers/calls-graph-analyzer/ICallsGraphData';
import { initializable } from '../../../decorators/Initializable';
import { CustomCodeHelper } from '../../../enums/custom-code-helpers/CustomCodeHelper';
import { ObfuscationEvent } from '../../../enums/event-emitters/ObfuscationEvent';
import { AbstractCustomCodeHelperGroup } from '../../AbstractCustomCodeHelperGroup';
import { CallsControllerFunctionCodeHelper } from '../../calls-controller/CallsControllerFunctionCodeHelper';
import { ConsoleOutputDisableCodeHelper } from '../ConsoleOutputDisableCodeHelper';
import { NodeAppender } from '../../../node/NodeAppender';
import { NodeLexicalScopeUtils } from '../../../node/NodeLexicalScopeUtils';
@injectable()
export class ConsoleOutputCodeHelperGroup extends AbstractCustomCodeHelperGroup {
/**
* @type {Map<CustomCodeHelper, ICustomCodeHelper>}
*/
@initializable()
protected customCodeHelpers!: Map <CustomCodeHelper, ICustomCodeHelper>;
/**
* @type {ObfuscationEvent}
*/
protected readonly appendEvent: ObfuscationEvent = ObfuscationEvent.BeforeObfuscation;
/**
* @type {TCustomCodeHelperFactory}
*/
private readonly customCodeHelperFactory: TCustomCodeHelperFactory;
/**
* @param {TCustomCodeHelperFactory} customCodeHelperFactory
* @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
*/
public constructor (
@inject(ServiceIdentifiers.Factory__ICustomCodeHelper) customCodeHelperFactory: TCustomCodeHelperFactory,
@inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
super(identifierNamesGeneratorFactory, randomGenerator, options);
this.customCodeHelperFactory = customCodeHelperFactory;
}
/**
* @param {TNodeWithStatements} nodeWithStatements
* @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
? this.identifierNamesGenerator.generate(consoleOutputDisableLexicalScopeNode)
: this.identifierNamesGenerator.generateNext();
const callsControllerFunctionName: string = consoleOutputDisableLexicalScopeNode
? this.identifierNamesGenerator.generate(consoleOutputDisableLexicalScopeNode)
: this.identifierNamesGenerator.generateNext();
// consoleOutputDisableExpression helper nodes append
this.appendCustomNodeIfExist(
CustomCodeHelper.ConsoleOutputDisable,
(customCodeHelper: ICustomCodeHelper<TInitialData<ConsoleOutputDisableCodeHelper>>) => {
customCodeHelper.initialize(callsControllerFunctionName, consoleOutputDisableFunctionName);
NodeAppender.prepend(consoleOutputDisableHostNode, 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 {
this.customCodeHelpers = new Map <CustomCodeHelper, ICustomCodeHelper>();
if (!this.options.disableConsoleOutput) {
return;
}
const consoleOutputDisableExpressionCodeHelper: ICustomCodeHelper<TInitialData<ConsoleOutputDisableCodeHelper>> =
this.customCodeHelperFactory(CustomCodeHelper.ConsoleOutputDisable);
const callsControllerFunctionCodeHelper: ICustomCodeHelper<TInitialData<CallsControllerFunctionCodeHelper>> =
this.customCodeHelperFactory(CustomCodeHelper.CallsControllerFunction);
this.customCodeHelpers.set(CustomCodeHelper.ConsoleOutputDisable, consoleOutputDisableExpressionCodeHelper);
this.customCodeHelpers.set(CustomCodeHelper.CallsControllerFunction, callsControllerFunctionCodeHelper);
}
}
@@ -0,0 +1,26 @@
/**
* @returns {string}
*/
export function ConsoleOutputDisableTemplate (): string {
return `
const {consoleLogDisableFunctionName} = {callControllerFunctionName}(this, function () {
{globalVariableTemplate}
const consoleObject = (that.console = that.console || {});
const methods = ['log', 'warn', 'info', 'error', 'exception', 'table', 'trace'];
for (let index = 0; index < methods.length; index++){
const func = {callControllerFunctionName}.constructor.prototype.bind({callControllerFunctionName});
const methodName = methods[index];
const originalFunction = consoleObject[methodName] || func;
func.__proto__ = {callControllerFunctionName}.bind({callControllerFunctionName});
func.toString = originalFunction.toString.bind(originalFunction);
consoleObject[methodName] = func;
}
});
{consoleLogDisableFunctionName}();
`;
}
@@ -0,0 +1,83 @@
import { inject, injectable, } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import { TIdentifierNamesGeneratorFactory } from '../../types/container/generators/TIdentifierNamesGeneratorFactory';
import { TStatement } from '../../types/node/TStatement';
import { ICustomCodeHelperFormatter } from '../../interfaces/custom-code-helpers/ICustomCodeHelperFormatter';
import { ICustomCodeHelperObfuscator } from '../../interfaces/custom-code-helpers/ICustomCodeHelperObfuscator';
import { IOptions } from '../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
import { initializable } from '../../decorators/Initializable';
import { DebugProtectionFunctionCallTemplate } from './templates/debug-protection-function-call/DebugProtectionFunctionCallTemplate';
import { AbstractCustomCodeHelper } from '../AbstractCustomCodeHelper';
import { NodeUtils } from '../../node/NodeUtils';
@injectable()
export class DebugProtectionFunctionCallCodeHelper extends AbstractCustomCodeHelper {
/**
* @type {string}
*/
@initializable()
private callsControllerFunctionName!: string;
/**
* @type {string}
*/
@initializable()
private debugProtectionFunctionName!: string;
/**
* @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
* @param {ICustomCodeHelperFormatter} customCodeHelperFormatter
* @param {ICustomCodeHelperObfuscator} customCodeHelperObfuscator
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
*/
public constructor (
@inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
@inject(ServiceIdentifiers.ICustomCodeHelperFormatter) customCodeHelperFormatter: ICustomCodeHelperFormatter,
@inject(ServiceIdentifiers.ICustomCodeHelperObfuscator) customCodeHelperObfuscator: ICustomCodeHelperObfuscator,
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
super(
identifierNamesGeneratorFactory,
customCodeHelperFormatter,
customCodeHelperObfuscator,
randomGenerator,
options
);
}
/**
* @param {string} debugProtectionFunctionName
* @param {string} callsControllerFunctionName
*/
public initialize (debugProtectionFunctionName: string, callsControllerFunctionName: string): void {
this.debugProtectionFunctionName = debugProtectionFunctionName;
this.callsControllerFunctionName = callsControllerFunctionName;
}
/**
* @param {string} codeHelperTemplate
* @returns {TStatement[]}
*/
protected getNodeStructure (codeHelperTemplate: string): TStatement[] {
return NodeUtils.convertCodeToStructure(codeHelperTemplate);
}
/**
* @returns {string}
*/
protected getCodeHelperTemplate (): string {
return this.customCodeHelperFormatter.formatTemplate(DebugProtectionFunctionCallTemplate(), {
debugProtectionFunctionName: this.debugProtectionFunctionName,
callControllerFunctionName: this.callsControllerFunctionName
});
}
}
@@ -0,0 +1,83 @@
import { inject, injectable, } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import { TIdentifierNamesGeneratorFactory } from '../../types/container/generators/TIdentifierNamesGeneratorFactory';
import { TStatement } from '../../types/node/TStatement';
import { ICustomCodeHelperFormatter } from '../../interfaces/custom-code-helpers/ICustomCodeHelperFormatter';
import { ICustomCodeHelperObfuscator } from '../../interfaces/custom-code-helpers/ICustomCodeHelperObfuscator';
import { IOptions } from '../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
import { ObfuscationTarget } from '../../enums/ObfuscationTarget';
import { initializable } from '../../decorators/Initializable';
import { DebuggerTemplate } from './templates/debug-protection-function/DebuggerTemplate';
import { DebuggerTemplateNoEval } from './templates/debug-protection-function/DebuggerTemplateNoEval';
import { DebugProtectionFunctionTemplate } from './templates/debug-protection-function/DebugProtectionFunctionTemplate';
import { AbstractCustomCodeHelper } from '../AbstractCustomCodeHelper';
import { NodeUtils } from '../../node/NodeUtils';
@injectable()
export class DebugProtectionFunctionCodeHelper extends AbstractCustomCodeHelper {
/**
* @type {string}
*/
@initializable()
private debugProtectionFunctionName!: string;
/**
* @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
* @param {ICustomCodeHelperFormatter} customCodeHelperFormatter
* @param {ICustomCodeHelperObfuscator} customCodeHelperObfuscator
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
*/
public constructor (
@inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
@inject(ServiceIdentifiers.ICustomCodeHelperFormatter) customCodeHelperFormatter: ICustomCodeHelperFormatter,
@inject(ServiceIdentifiers.ICustomCodeHelperObfuscator) customCodeHelperObfuscator: ICustomCodeHelperObfuscator,
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
super(
identifierNamesGeneratorFactory,
customCodeHelperFormatter,
customCodeHelperObfuscator,
randomGenerator,
options
);
}
/**
* @param {string} debugProtectionFunctionName
*/
public initialize (debugProtectionFunctionName: string): void {
this.debugProtectionFunctionName = debugProtectionFunctionName;
}
/**
* @param {string} codeHelperTemplate
* @returns {TStatement[]}
*/
protected getNodeStructure (codeHelperTemplate: string): TStatement[] {
return NodeUtils.convertCodeToStructure(codeHelperTemplate);
}
/**
* @returns {string}
*/
protected getCodeHelperTemplate (): string {
const debuggerTemplate: string = this.options.target !== ObfuscationTarget.BrowserNoEval
? DebuggerTemplate()
: DebuggerTemplateNoEval();
return this.customCodeHelperFormatter.formatTemplate(DebugProtectionFunctionTemplate(), {
debuggerTemplate,
debugProtectionFunctionName: this.debugProtectionFunctionName
});
}
}
@@ -0,0 +1,74 @@
import { inject, injectable, } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import { TIdentifierNamesGeneratorFactory } from '../../types/container/generators/TIdentifierNamesGeneratorFactory';
import { TStatement } from '../../types/node/TStatement';
import { ICustomCodeHelperFormatter } from '../../interfaces/custom-code-helpers/ICustomCodeHelperFormatter';
import { ICustomCodeHelperObfuscator } from '../../interfaces/custom-code-helpers/ICustomCodeHelperObfuscator';
import { IOptions } from '../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
import { initializable } from '../../decorators/Initializable';
import { DebugProtectionFunctionIntervalTemplate } from './templates/debug-protection-function-interval/DebugProtectionFunctionIntervalTemplate';
import { AbstractCustomCodeHelper } from '../AbstractCustomCodeHelper';
import { NodeUtils } from '../../node/NodeUtils';
@injectable()
export class DebugProtectionFunctionIntervalCodeHelper extends AbstractCustomCodeHelper {
/**
* @type {string}
*/
@initializable()
private debugProtectionFunctionName!: string;
/**
* @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
* @param {ICustomCodeHelperFormatter} customCodeHelperFormatter
* @param {ICustomCodeHelperObfuscator} customCodeHelperObfuscator
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
*/
public constructor (
@inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
@inject(ServiceIdentifiers.ICustomCodeHelperFormatter) customCodeHelperFormatter: ICustomCodeHelperFormatter,
@inject(ServiceIdentifiers.ICustomCodeHelperObfuscator) customCodeHelperObfuscator: ICustomCodeHelperObfuscator,
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
super(
identifierNamesGeneratorFactory,
customCodeHelperFormatter,
customCodeHelperObfuscator,
randomGenerator,
options
);
}
/**
* @param {string} debugProtectionFunctionName
*/
public initialize (debugProtectionFunctionName: string): void {
this.debugProtectionFunctionName = debugProtectionFunctionName;
}
/**
* @param {string} codeHelperTemplate
* @returns {TStatement[]}
*/
protected getNodeStructure (codeHelperTemplate: string): TStatement[] {
return NodeUtils.convertCodeToStructure(codeHelperTemplate);
}
/**
* @returns {string}
*/
protected getCodeHelperTemplate (): string {
return this.customCodeHelperFormatter.formatTemplate(DebugProtectionFunctionIntervalTemplate(), {
debugProtectionFunctionName: this.debugProtectionFunctionName
});
}
}
@@ -0,0 +1,164 @@
import { inject, injectable, } from 'inversify';
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';
import { IOptions } from '../../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../../interfaces/utils/IRandomGenerator';
import { ICallsGraphData } from '../../../interfaces/analyzers/calls-graph-analyzer/ICallsGraphData';
import { initializable } from '../../../decorators/Initializable';
import { CustomCodeHelper } from '../../../enums/custom-code-helpers/CustomCodeHelper';
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 { NodeGuards } from '../../../node/NodeGuards';
import { NodeLexicalScopeUtils } from '../../../node/NodeLexicalScopeUtils';
@injectable()
export class DebugProtectionCodeHelperGroup extends AbstractCustomCodeHelperGroup {
/**
* @type {Map<CustomCodeHelper, ICustomCodeHelper>}
*/
@initializable()
protected customCodeHelpers!: Map <CustomCodeHelper, ICustomCodeHelper>;
/**
* @type {ObfuscationEvent}
*/
protected readonly appendEvent: ObfuscationEvent = ObfuscationEvent.BeforeObfuscation;
/**
* @type {TCustomCodeHelperFactory}
*/
private readonly customCodeHelperFactory: TCustomCodeHelperFactory;
/**
* @param {TCustomCodeHelperFactory} customCodeHelperFactory
* @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
*/
public constructor (
@inject(ServiceIdentifiers.Factory__ICustomCodeHelper) customCodeHelperFactory: TCustomCodeHelperFactory,
@inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
super(identifierNamesGeneratorFactory, randomGenerator, options);
this.customCodeHelperFactory = customCodeHelperFactory;
}
/**
* @param {TNodeWithStatements} nodeWithStatements
* @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
? this.identifierNamesGenerator.generate(debugProtectionFunctionCallScopeNode)
: this.identifierNamesGenerator.generateNext();
const callsControllerFunctionName: string = debugProtectionFunctionCallScopeNode
? this.identifierNamesGenerator.generate(debugProtectionFunctionCallScopeNode)
: this.identifierNamesGenerator.generateNext();
// debugProtectionFunctionCall helper nodes append
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<TInitialData<DebugProtectionFunctionCodeHelper>>) => {
customCodeHelper.initialize(debugProtectionFunctionName);
NodeAppender.append(nodeWithStatements, customCodeHelper.getNode());
}
);
// debugProtectionFunctionInterval helper nodes append
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 {
this.customCodeHelpers = new Map <CustomCodeHelper, ICustomCodeHelper>();
if (!this.options.debugProtection) {
return;
}
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 callsControllerFunctionCodeHelper: ICustomCodeHelper<TInitialData<CallsControllerFunctionCodeHelper>> =
this.customCodeHelperFactory(CustomCodeHelper.CallsControllerFunction);
this.customCodeHelpers.set(CustomCodeHelper.DebugProtectionFunction, debugProtectionFunctionCodeHelper);
this.customCodeHelpers.set(CustomCodeHelper.DebugProtectionFunctionCall, debugProtectionFunctionCallCodeHelper);
if (this.options.debugProtectionInterval) {
this.customCodeHelpers.set(CustomCodeHelper.DebugProtectionFunctionInterval, debugProtectionFunctionIntervalCodeHelper);
}
this.customCodeHelpers.set(CustomCodeHelper.CallsControllerFunction, callsControllerFunctionCodeHelper);
}
}
@@ -0,0 +1,24 @@
/**
* @returns {string}
*/
export function DebugProtectionFunctionCallTemplate (): string {
return `
(function () {
{callControllerFunctionName}(
this,
function () {
const regExp1 = new RegExp('function *\\\\( *\\\\)');
const regExp2 = new RegExp('\\\\+\\\\+ *\\(?:[a-zA-Z_$][0-9a-zA-Z_$]*\\)', 'i');
const result = {debugProtectionFunctionName}('init');
if (!regExp1.test(result + 'chain') || !regExp2.test(result + 'input')) {
result('0');
} else {
{debugProtectionFunctionName}();
}
}
)();
})();
`;
}
@@ -0,0 +1,10 @@
/**
* @returns {string}
*/
export function DebugProtectionFunctionIntervalTemplate (): string {
return `
setInterval(function () {
{debugProtectionFunctionName}();
}, 4000);
`;
}
@@ -0,0 +1,23 @@
/**
* @returns {string}
*/
export function DebugProtectionFunctionTemplate (): string {
return `
function {debugProtectionFunctionName} (ret) {
function debuggerProtection (counter) {
{debuggerTemplate}
debuggerProtection(++counter);
}
try {
if (ret) {
return debuggerProtection;
} else {
debuggerProtection(0);
}
} catch (y) {}
}
`;
}
@@ -0,0 +1,17 @@
/**
* @returns {string}
*/
export function DebuggerTemplate (): string {
return `
if (typeof counter === 'string') {
return (function (arg) {}.constructor('while (true) {}').apply('counter'));
} else {
if (('' + counter / counter)['length'] !== 1 || counter % 20 === 0) {
(function () {return true;}.constructor('debu' + 'gger').call('action'));
} else {
(function () {return false;}.constructor('debu' + 'gger').apply('stateObject'));
}
}
`;
}
@@ -0,0 +1,21 @@
/**
* @returns {string}
*/
export function DebuggerTemplateNoEval (): string {
return `
if (typeof counter === 'string') {
const func = function () {
while (true) {}
};
return func();
} else {
if (('' + counter / counter)['length'] !== 1 || counter % 20 === 0) {
debugger;
} else {
debugger;
}
}
`;
}
@@ -0,0 +1,108 @@
import { inject, injectable, } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import { TIdentifierNamesGeneratorFactory } from '../../types/container/generators/TIdentifierNamesGeneratorFactory';
import { TStatement } from '../../types/node/TStatement';
import { ICustomCodeHelperFormatter } from '../../interfaces/custom-code-helpers/ICustomCodeHelperFormatter';
import { ICustomCodeHelperObfuscator } from '../../interfaces/custom-code-helpers/ICustomCodeHelperObfuscator';
import { ICryptUtils } from '../../interfaces/utils/ICryptUtils';
import { IOptions } from '../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
import { ObfuscationTarget } from '../../enums/ObfuscationTarget';
import { initializable } from '../../decorators/Initializable';
import { DomainLockTemplate } from './templates/DomainLockTemplate';
import { GlobalVariableNoEvalTemplate } from '../common/templates/GlobalVariableNoEvalTemplate';
import { AbstractCustomCodeHelper } from '../AbstractCustomCodeHelper';
import { NodeUtils } from '../../node/NodeUtils';
@injectable()
export class DomainLockCodeHelper extends AbstractCustomCodeHelper {
/**
* @type {string}
*/
@initializable()
private callsControllerFunctionName!: string;
/**
* @type {string}
*/
@initializable()
private domainLockFunctionName!: string;
/**
* @type {ICryptUtils}
*/
private readonly cryptUtils: ICryptUtils;
/**
* @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
* @param {ICustomCodeHelperFormatter} customCodeHelperFormatter
* @param {ICustomCodeHelperObfuscator} customCodeHelperObfuscator
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
* @param {ICryptUtils} cryptUtils
*/
public constructor (
@inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
@inject(ServiceIdentifiers.ICustomCodeHelperFormatter) customCodeHelperFormatter: ICustomCodeHelperFormatter,
@inject(ServiceIdentifiers.ICustomCodeHelperObfuscator) customCodeHelperObfuscator: ICustomCodeHelperObfuscator,
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions,
@inject(ServiceIdentifiers.ICryptUtils) cryptUtils: ICryptUtils
) {
super(
identifierNamesGeneratorFactory,
customCodeHelperFormatter,
customCodeHelperObfuscator,
randomGenerator,
options
);
this.cryptUtils = cryptUtils;
}
/**
* @param {string} callsControllerFunctionName
* @param {string} domainLockFunctionName
*/
public initialize (callsControllerFunctionName: string, domainLockFunctionName: string): void {
this.callsControllerFunctionName = callsControllerFunctionName;
this.domainLockFunctionName = domainLockFunctionName;
}
/**
* @param {string} codeHelperTemplate
* @returns {TStatement[]}
*/
protected getNodeStructure (codeHelperTemplate: string): TStatement[] {
return NodeUtils.convertCodeToStructure(codeHelperTemplate);
}
/**
* @returns {string}
*/
protected getCodeHelperTemplate (): string {
const domainsString: string = this.options.domainLock.join(';');
const [hiddenDomainsString, diff]: string[] = this.cryptUtils.hideString(
domainsString,
domainsString.length * 3
);
const globalVariableTemplate: string = this.options.target !== ObfuscationTarget.BrowserNoEval
? this.getGlobalVariableTemplate()
: GlobalVariableNoEvalTemplate();
return this.customCodeHelperFormatter.formatTemplate(DomainLockTemplate(), {
callControllerFunctionName: this.callsControllerFunctionName,
domainLockFunctionName: this.domainLockFunctionName,
diff,
domains: hiddenDomainsString,
globalVariableTemplate
});
}
}
@@ -0,0 +1,126 @@
import { inject, injectable, } from 'inversify';
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';
import { IOptions } from '../../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../../interfaces/utils/IRandomGenerator';
import { ICallsGraphData } from '../../../interfaces/analyzers/calls-graph-analyzer/ICallsGraphData';
import { initializable } from '../../../decorators/Initializable';
import { CustomCodeHelper } from '../../../enums/custom-code-helpers/CustomCodeHelper';
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 { NodeLexicalScopeUtils } from '../../../node/NodeLexicalScopeUtils';
@injectable()
export class DomainLockCustomCodeHelperGroup extends AbstractCustomCodeHelperGroup {
/**
* @type {Map<CustomCodeHelper, ICustomCodeHelper>}
*/
@initializable()
protected customCodeHelpers!: Map <CustomCodeHelper, ICustomCodeHelper>;
/**
* @type {ObfuscationEvent}
*/
protected readonly appendEvent: ObfuscationEvent = ObfuscationEvent.BeforeObfuscation;
/**
* @type {TCustomCodeHelperFactory}
*/
private readonly customCodeHelperFactory: TCustomCodeHelperFactory;
/**
* @param {TCustomCodeHelperFactory} customCodeHelperFactory
* @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
*/
public constructor (
@inject(ServiceIdentifiers.Factory__ICustomCodeHelper) customCodeHelperFactory: TCustomCodeHelperFactory,
@inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
super(identifierNamesGeneratorFactory, randomGenerator, options);
this.customCodeHelperFactory = customCodeHelperFactory;
}
/**
* @param {TNodeWithStatements} nodeWithStatements
* @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
? this.identifierNamesGenerator.generate(domainLockFunctionLexicalScopeNode)
: this.identifierNamesGenerator.generateNext();
const callsControllerFunctionName: string = domainLockFunctionLexicalScopeNode
? this.identifierNamesGenerator.generate(domainLockFunctionLexicalScopeNode)
: this.identifierNamesGenerator.generateNext();
// domainLock helper nodes append
this.appendCustomNodeIfExist(
CustomCodeHelper.DomainLock,
(customCodeHelper: ICustomCodeHelper<TInitialData<DomainLockCodeHelper>>) => {
customCodeHelper.initialize(callsControllerFunctionName, domainLockFunctionName);
NodeAppender.prepend(domainLockFunctionHostNode, 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 {
this.customCodeHelpers = new Map <CustomCodeHelper, ICustomCodeHelper>();
if (!this.options.domainLock.length) {
return;
}
const domainLockCodeHelper: ICustomCodeHelper<TInitialData<DomainLockCodeHelper>> =
this.customCodeHelperFactory(CustomCodeHelper.DomainLock);
const callsControllerFunctionCodeHelper: ICustomCodeHelper<TInitialData<CallsControllerFunctionCodeHelper>> =
this.customCodeHelperFactory(CustomCodeHelper.CallsControllerFunction);
this.customCodeHelpers.set(CustomCodeHelper.DomainLock, domainLockCodeHelper);
this.customCodeHelpers.set(CustomCodeHelper.CallsControllerFunction, callsControllerFunctionCodeHelper);
}
}
@@ -0,0 +1,111 @@
/**
* @returns {string}
*/
export function DomainLockTemplate (): string {
return `
const {domainLockFunctionName} = {callControllerFunctionName}(this, function () {
{globalVariableTemplate}
const func = function () {
return {
key: 'item',
value: 'attribute',
getAttribute: function () {
for (let i = 0; i < 1000; i--) {
const isPositive = i > 0;
switch (isPositive) {
case true:
return this.item + '_' + this.value + '_' + i;
default:
this.item + '_' + this.value;
}
}
}()
};
};
const regExp = new RegExp("[{diff}]", "g");
const domains = "{domains}".replace(regExp, "").split(";");
let document;
let domain;
let location;
let hostname;
for (let d in that) {
if (d.length == 8 && d.charCodeAt(7) == 116 && d.charCodeAt(5) == 101 && d.charCodeAt(3) == 117 && d.charCodeAt(0) == 100) {
document = d;
break;
}
}
for (let d1 in that[document]) {
if (d1.length == 6 && d1.charCodeAt(5) == 110 && d1.charCodeAt(0) == 100) {
domain = d1;
break;
}
}
if (!("~" > domain)) {
for (let d2 in that[document]) {
if (d2.length == 8 && d2.charCodeAt(7) == 110 && d2.charCodeAt(0) == 108) {
location = d2;
break;
}
}
for (let d3 in that[document][location]) {
if (d3.length == 8 && d3.charCodeAt(7) == 101 && d3.charCodeAt(0) == 104) {
hostname = d3;
break;
}
}
}
if (!document || !that[document]) {
return;
}
const documentDomain = that[document][domain];
const documentLocationHostName = !!that[document][location] && that[document][location][hostname];
const currentDomain = documentDomain || documentLocationHostName;
if (!currentDomain) {
return;
}
let ok = false;
for (let i = 0; i < domains.length; i++) {
const domain = domains[i];
const domainNormalized = domain[0] === String.fromCharCode(46)
? domain.slice(1)
: domain;
const position = currentDomain.length - domainNormalized.length;
const lastIndex = currentDomain.indexOf(domainNormalized, position);
const endsWith = lastIndex !== -1 && lastIndex === position;
if (endsWith) {
if (currentDomain.length == domain.length || domain.indexOf(".") === 0) {
ok = true;
}
}
}
if (!ok) {
data;
} else {
return;
}
func();
});
{domainLockFunctionName}();
`;
}
@@ -0,0 +1,95 @@
import { inject, injectable, } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import { TIdentifierNamesGeneratorFactory } from '../../types/container/generators/TIdentifierNamesGeneratorFactory';
import { TStatement } from '../../types/node/TStatement';
import { ICustomCodeHelperFormatter } from '../../interfaces/custom-code-helpers/ICustomCodeHelperFormatter';
import { ICustomCodeHelperObfuscator } from '../../interfaces/custom-code-helpers/ICustomCodeHelperObfuscator';
import { IOptions } from '../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
import { ObfuscationTarget } from '../../enums/ObfuscationTarget';
import { initializable } from '../../decorators/Initializable';
import { SelfDefendingTemplate } from './templates/SelfDefendingTemplate';
import { SelfDefendingNoEvalTemplate } from './templates/SelfDefendingNoEvalTemplate';
import { AbstractCustomCodeHelper } from '../AbstractCustomCodeHelper';
import { NodeUtils } from '../../node/NodeUtils';
import { GlobalVariableNoEvalTemplate } from '../common/templates/GlobalVariableNoEvalTemplate';
@injectable()
export class SelfDefendingUnicodeCodeHelper extends AbstractCustomCodeHelper {
/**
* @type {string}
*/
@initializable()
private callsControllerFunctionName!: string;
/**
* @type {string}
*/
@initializable()
private selfDefendingFunctionName!: string;
/**
* @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
* @param {ICustomCodeHelperFormatter} customCodeHelperFormatter
* @param {ICustomCodeHelperObfuscator} customCodeHelperObfuscator
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
*/
public constructor (
@inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
@inject(ServiceIdentifiers.ICustomCodeHelperFormatter) customCodeHelperFormatter: ICustomCodeHelperFormatter,
@inject(ServiceIdentifiers.ICustomCodeHelperObfuscator) customCodeHelperObfuscator: ICustomCodeHelperObfuscator,
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
super(
identifierNamesGeneratorFactory,
customCodeHelperFormatter,
customCodeHelperObfuscator,
randomGenerator,
options
);
}
/**
* @param {string} callsControllerFunctionName
* @param {string} selfDefendingFunctionName
*/
public initialize (callsControllerFunctionName: string, selfDefendingFunctionName: string): void {
this.callsControllerFunctionName = callsControllerFunctionName;
this.selfDefendingFunctionName = selfDefendingFunctionName;
}
/**
* @param {string} codeHelperTemplate
* @returns {TStatement[]}
*/
protected getNodeStructure (codeHelperTemplate: string): TStatement[] {
return NodeUtils.convertCodeToStructure(codeHelperTemplate);
}
/**
* @returns {string}
*/
protected getCodeHelperTemplate (): string {
const globalVariableTemplate: string = this.options.target !== ObfuscationTarget.BrowserNoEval
? this.getGlobalVariableTemplate()
: GlobalVariableNoEvalTemplate();
const selfDefendingTemplate: string = this.options.target !== ObfuscationTarget.BrowserNoEval
? SelfDefendingTemplate()
: SelfDefendingNoEvalTemplate();
return this.customCodeHelperFormatter.formatTemplate(selfDefendingTemplate, {
callControllerFunctionName: this.callsControllerFunctionName,
selfDefendingFunctionName: this.selfDefendingFunctionName,
globalVariableTemplate
});
}
}
@@ -0,0 +1,126 @@
import { inject, injectable, } from 'inversify';
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';
import { IOptions } from '../../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../../interfaces/utils/IRandomGenerator';
import { ICallsGraphData } from '../../../interfaces/analyzers/calls-graph-analyzer/ICallsGraphData';
import { initializable } from '../../../decorators/Initializable';
import { CustomCodeHelper } from '../../../enums/custom-code-helpers/CustomCodeHelper';
import { ObfuscationEvent } from '../../../enums/event-emitters/ObfuscationEvent';
import { AbstractCustomCodeHelperGroup } from '../../AbstractCustomCodeHelperGroup';
import { CallsControllerFunctionCodeHelper } from '../../calls-controller/CallsControllerFunctionCodeHelper';
import { NodeAppender } from '../../../node/NodeAppender';
import { NodeLexicalScopeUtils } from '../../../node/NodeLexicalScopeUtils';
import { SelfDefendingUnicodeCodeHelper } from '../SelfDefendingUnicodeCodeHelper';
@injectable()
export class SelfDefendingCodeHelperGroup extends AbstractCustomCodeHelperGroup {
/**
* @type {Map<CustomCodeHelper, ICustomCodeHelper>}
*/
@initializable()
protected customCodeHelpers!: Map <CustomCodeHelper, ICustomCodeHelper>;
/**
* @type {ObfuscationEvent}
*/
protected appendEvent: ObfuscationEvent = ObfuscationEvent.BeforeObfuscation;
/**
* @type {TCustomCodeHelperFactory}
*/
private readonly customCodeHelperFactory: TCustomCodeHelperFactory;
/**
* @param {TCustomCodeHelperFactory} customCodeHelperFactory
* @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
*/
public constructor (
@inject(ServiceIdentifiers.Factory__ICustomCodeHelper) customCodeHelperFactory: TCustomCodeHelperFactory,
@inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
super(identifierNamesGeneratorFactory, randomGenerator, options);
this.customCodeHelperFactory = customCodeHelperFactory;
}
/**
* @param {TNodeWithStatements} nodeWithStatements
* @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.generateNext();
const callsControllerFunctionName: string = selfDefendingFunctionLexicalScopeNode
? this.identifierNamesGenerator.generate(selfDefendingFunctionLexicalScopeNode)
: this.identifierNamesGenerator.generateNext();
// selfDefendingUnicode helper nodes append
this.appendCustomNodeIfExist(
CustomCodeHelper.SelfDefendingUnicode,
(customCodeHelper: ICustomCodeHelper<TInitialData<SelfDefendingUnicodeCodeHelper>>) => {
customCodeHelper.initialize(callsControllerFunctionName, selfDefendingFunctionName);
NodeAppender.prepend(selfDefendingFunctionHostNode, 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 {
this.customCodeHelpers = new Map <CustomCodeHelper, ICustomCodeHelper>();
if (!this.options.selfDefending) {
return;
}
const selfDefendingUnicodeCodeHelper: ICustomCodeHelper<TInitialData<SelfDefendingUnicodeCodeHelper>> =
this.customCodeHelperFactory(CustomCodeHelper.SelfDefendingUnicode);
const callsControllerFunctionCodeHelper: ICustomCodeHelper<TInitialData<CallsControllerFunctionCodeHelper>> =
this.customCodeHelperFactory(CustomCodeHelper.CallsControllerFunction);
this.customCodeHelpers.set(CustomCodeHelper.SelfDefendingUnicode, selfDefendingUnicodeCodeHelper);
this.customCodeHelpers.set(CustomCodeHelper.CallsControllerFunction, callsControllerFunctionCodeHelper);
}
}
@@ -0,0 +1,22 @@
/**
* SelfDefendingTemplate. Enters code in infinity loop.
*
* @returns {string}
*/
export function SelfDefendingNoEvalTemplate (): string {
return `
const {selfDefendingFunctionName} = {callControllerFunctionName}(this, function () {
{globalVariableTemplate}
const test = function () {
const regExp = new that.RegExp('^([^ ]+( +[^ ]+)+)+[^ ]}');
return !regExp.test({selfDefendingFunctionName});
};
return test();
});
{selfDefendingFunctionName}();
`;
}
@@ -0,0 +1,22 @@
/**
* SelfDefendingTemplate. Enters code in infinity loop.
*
* @returns {string}
*/
export function SelfDefendingTemplate (): string {
return `
const {selfDefendingFunctionName} = {callControllerFunctionName}(this, function () {
const test = function () {
const regExp = test
.constructor('return /" + this + "/')()
.constructor('^([^ ]+( +[^ ]+)+)+[^ ]}');
return !regExp.test({selfDefendingFunctionName});
};
return test();
});
{selfDefendingFunctionName}();
`;
}
@@ -0,0 +1,32 @@
import { injectable, } from 'inversify';
import { AtobTemplate } from './templates/string-array-calls-wrapper/AtobTemplate';
import { StringArrayBase64DecodeTemplate } from './templates/string-array-calls-wrapper/StringArrayBase64DecodeTemplate';
import { StringArrayCallsWrapperCodeHelper } from './StringArrayCallsWrapperCodeHelper';
@injectable()
export class StringArrayCallsWrapperBase64CodeHelper extends StringArrayCallsWrapperCodeHelper {
/**
* @returns {string}
*/
protected getDecodeStringArrayTemplate (): string {
const atobFunctionName: string = this.randomGenerator.getRandomString(6);
const atobPolyfill: string = this.customCodeHelperFormatter.formatTemplate(AtobTemplate(), {
atobFunctionName: atobFunctionName
});
const selfDefendingCode: string = this.getSelfDefendingTemplate();
return this.customCodeHelperFormatter.formatTemplate(
StringArrayBase64DecodeTemplate(this.randomGenerator),
{
atobPolyfill,
atobFunctionName,
selfDefendingCode,
stringArrayCallsWrapperName: this.stringArrayCallsWrapperName
}
);
}
}
@@ -0,0 +1,144 @@
import { inject, injectable, } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import { TIdentifierNamesGeneratorFactory } from '../../types/container/generators/TIdentifierNamesGeneratorFactory';
import { TStatement } from '../../types/node/TStatement';
import { ICustomCodeHelperFormatter } from '../../interfaces/custom-code-helpers/ICustomCodeHelperFormatter';
import { ICustomCodeHelperObfuscator } from '../../interfaces/custom-code-helpers/ICustomCodeHelperObfuscator';
import { IEscapeSequenceEncoder } from '../../interfaces/utils/IEscapeSequenceEncoder';
import { IOptions } from '../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
import { initializable } from '../../decorators/Initializable';
import { SelfDefendingTemplate } from './templates/string-array-calls-wrapper/SelfDefendingTemplate';
import { StringArrayCallsWrapperTemplate } from './templates/string-array-calls-wrapper/StringArrayCallsWrapperTemplate';
import { AbstractCustomCodeHelper } from '../AbstractCustomCodeHelper';
import { NodeUtils } from '../../node/NodeUtils';
@injectable()
export class StringArrayCallsWrapperCodeHelper extends AbstractCustomCodeHelper {
/**
* @type {number}
*/
@initializable()
protected indexShiftAmount!: number;
/**
* @type {string}
*/
@initializable()
protected stringArrayName!: string;
/**
* @type {string}
*/
@initializable()
protected stringArrayCallsWrapperName!: string;
/**
* @type {IEscapeSequenceEncoder}
*/
private readonly escapeSequenceEncoder: IEscapeSequenceEncoder;
/**
* @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
* @param {ICustomCodeHelperFormatter} customCodeHelperFormatter
* @param {ICustomCodeHelperObfuscator} customCodeHelperObfuscator
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
* @param {IEscapeSequenceEncoder} escapeSequenceEncoder
*/
public constructor (
@inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
@inject(ServiceIdentifiers.ICustomCodeHelperFormatter) customCodeHelperFormatter: ICustomCodeHelperFormatter,
@inject(ServiceIdentifiers.ICustomCodeHelperObfuscator) customCodeHelperObfuscator: ICustomCodeHelperObfuscator,
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions,
@inject(ServiceIdentifiers.IEscapeSequenceEncoder) escapeSequenceEncoder: IEscapeSequenceEncoder
) {
super(
identifierNamesGeneratorFactory,
customCodeHelperFormatter,
customCodeHelperObfuscator,
randomGenerator,
options
);
this.escapeSequenceEncoder = escapeSequenceEncoder;
}
/**
* @param {string} stringArrayName
* @param {string} stringArrayCallsWrapperName
* @param {number} indexShiftAmount
*/
public initialize (
stringArrayName: string,
stringArrayCallsWrapperName: string,
indexShiftAmount: number
): void {
this.stringArrayName = stringArrayName;
this.stringArrayCallsWrapperName = stringArrayCallsWrapperName;
this.indexShiftAmount = indexShiftAmount;
}
/**
* @param {string} codeHelperTemplate
* @returns {TStatement[]}
*/
protected getNodeStructure (codeHelperTemplate: string): TStatement[] {
return NodeUtils.convertCodeToStructure(codeHelperTemplate);
}
/**
* @returns {string}
*/
protected getCodeHelperTemplate (): string {
const decodeCodeHelperTemplate: string = this.getDecodeStringArrayTemplate();
const preservedNames: string[] = [`^${this.stringArrayName}$`];
return this.customCodeHelperObfuscator.obfuscateTemplate(
this.customCodeHelperFormatter.formatTemplate(StringArrayCallsWrapperTemplate(), {
decodeCodeHelperTemplate,
stringArrayCallsWrapperName: this.stringArrayCallsWrapperName,
stringArrayName: this.stringArrayName,
indexShiftAmount: this.indexShiftAmount
}),
{
reservedNames: preservedNames
}
);
}
/**
* @returns {string}
*/
protected getDecodeStringArrayTemplate (): string {
return '';
}
/**
* @returns {string}
*/
protected getSelfDefendingTemplate (): string {
if (!this.options.selfDefending) {
return '';
}
return this.customCodeHelperFormatter.formatTemplate(
SelfDefendingTemplate(
this.randomGenerator,
this.escapeSequenceEncoder
),
{
stringArrayCallsWrapperName: this.stringArrayCallsWrapperName,
stringArrayName: this.stringArrayName
}
);
}
}
@@ -0,0 +1,36 @@
import { injectable, } from 'inversify';
import { AtobTemplate } from './templates/string-array-calls-wrapper/AtobTemplate';
import { Rc4Template } from './templates/string-array-calls-wrapper/Rc4Template';
import { StringArrayRC4DecodeTemplate } from './templates/string-array-calls-wrapper/StringArrayRC4DecodeTemplate';
import { StringArrayCallsWrapperCodeHelper } from './StringArrayCallsWrapperCodeHelper';
@injectable()
export class StringArrayCallsWrapperRc4CodeHelper extends StringArrayCallsWrapperCodeHelper {
/**
* @returns {string}
*/
protected getDecodeStringArrayTemplate (): string {
const atobFunctionName: string = this.randomGenerator.getRandomString(6);
const atobPolyfill: string = this.customCodeHelperFormatter.formatTemplate(AtobTemplate(), {
atobFunctionName
});
const rc4Polyfill: string = this.customCodeHelperFormatter.formatTemplate(Rc4Template(), {
atobFunctionName
});
const selfDefendingCode: string = this.getSelfDefendingTemplate();
return this.customCodeHelperFormatter.formatTemplate(
StringArrayRC4DecodeTemplate(this.randomGenerator),
{
atobPolyfill,
rc4Polyfill,
selfDefendingCode,
stringArrayCallsWrapperName: this.stringArrayCallsWrapperName
}
);
}
}
@@ -0,0 +1,103 @@
import { inject, injectable, } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import { TIdentifierNamesGeneratorFactory } from '../../types/container/generators/TIdentifierNamesGeneratorFactory';
import { TStatement } from '../../types/node/TStatement';
import { ICustomCodeHelperFormatter } from '../../interfaces/custom-code-helpers/ICustomCodeHelperFormatter';
import { ICustomCodeHelperObfuscator } from '../../interfaces/custom-code-helpers/ICustomCodeHelperObfuscator';
import { IOptions } from '../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
import { IStringArrayStorage } from '../../interfaces/storages/string-array-transformers/IStringArrayStorage';
import { IStringArrayStorageItemData } from '../../interfaces/storages/string-array-transformers/IStringArrayStorageItem';
import { initializable } from '../../decorators/Initializable';
import { StringArrayTemplate } from './templates/string-array/StringArrayTemplate';
import { AbstractCustomCodeHelper } from '../AbstractCustomCodeHelper';
import { NodeUtils } from '../../node/NodeUtils';
import { StringUtils } from '../../utils/StringUtils';
@injectable()
export class StringArrayCodeHelper extends AbstractCustomCodeHelper {
/**
* @type {IStringArrayStorage}
*/
@initializable()
private stringArrayStorage!: IStringArrayStorage;
/**
* @type {string}
*/
@initializable()
private stringArrayName!: string;
/**
* @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
* @param {ICustomCodeHelperFormatter} customCodeHelperFormatter
* @param {ICustomCodeHelperObfuscator} customCodeHelperObfuscator
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
*/
public constructor (
@inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
@inject(ServiceIdentifiers.ICustomCodeHelperFormatter) customCodeHelperFormatter: ICustomCodeHelperFormatter,
@inject(ServiceIdentifiers.ICustomCodeHelperObfuscator) customCodeHelperObfuscator: ICustomCodeHelperObfuscator,
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
super(
identifierNamesGeneratorFactory,
customCodeHelperFormatter,
customCodeHelperObfuscator,
randomGenerator,
options
);
}
/**
* @param {IStringArrayStorage} stringArrayStorage
* @param {string} stringArrayName
*/
public initialize (
stringArrayStorage: IStringArrayStorage,
stringArrayName: string
): void {
this.stringArrayStorage = stringArrayStorage;
this.stringArrayName = stringArrayName;
}
/**
* @param {string} codeHelperTemplate
* @returns {TStatement[]}
*/
protected getNodeStructure (codeHelperTemplate: string): TStatement[] {
return NodeUtils.convertCodeToStructure(codeHelperTemplate);
}
/**
* @returns {string}
*/
protected getCodeHelperTemplate (): string {
return this.customCodeHelperFormatter.formatTemplate(StringArrayTemplate(), {
stringArrayName: this.stringArrayName,
stringArrayStorageItems: this.getEncodedStringArrayStorageItems()
});
}
/**
* @returns {string}
*/
private getEncodedStringArrayStorageItems (): string {
return Array
.from(this.stringArrayStorage.getStorage().values())
.map((stringArrayStorageItemData: IStringArrayStorageItemData): string => {
const escapedEncodedValue: string = StringUtils.escapeJsString(stringArrayStorageItemData.encodedValue);
return `'${escapedEncodedValue}'`;
})
.toString();
}
}
@@ -0,0 +1,121 @@
import { inject, injectable, } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import { TIdentifierNamesGeneratorFactory } from '../../types/container/generators/TIdentifierNamesGeneratorFactory';
import { TStatement } from '../../types/node/TStatement';
import { ICustomCodeHelperFormatter } from '../../interfaces/custom-code-helpers/ICustomCodeHelperFormatter';
import { ICustomCodeHelperObfuscator } from '../../interfaces/custom-code-helpers/ICustomCodeHelperObfuscator';
import { IEscapeSequenceEncoder } from '../../interfaces/utils/IEscapeSequenceEncoder';
import { IOptions } from '../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
import { initializable } from '../../decorators/Initializable';
import { SelfDefendingTemplate } from './templates/string-array-rotate-function/SelfDefendingTemplate';
import { StringArrayRotateFunctionTemplate } from './templates/string-array-rotate-function/StringArrayRotateFunctionTemplate';
import { AbstractCustomCodeHelper } from '../AbstractCustomCodeHelper';
import { NodeUtils } from '../../node/NodeUtils';
import { NumberUtils } from '../../utils/NumberUtils';
@injectable()
export class StringArrayRotateFunctionCodeHelper extends AbstractCustomCodeHelper {
/**
* @type {string}
*/
@initializable()
private stringArrayName!: string;
/**
* @param {number}
*/
@initializable()
private stringArrayRotationAmount!: number;
/**
* @type {IEscapeSequenceEncoder}
*/
private readonly escapeSequenceEncoder: IEscapeSequenceEncoder;
/**
* @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
* @param {ICustomCodeHelperFormatter} customCodeHelperFormatter
* @param {ICustomCodeHelperObfuscator} customCodeHelperObfuscator
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
* @param {IEscapeSequenceEncoder} escapeSequenceEncoder
*/
public constructor (
@inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
@inject(ServiceIdentifiers.ICustomCodeHelperFormatter) customCodeHelperFormatter: ICustomCodeHelperFormatter,
@inject(ServiceIdentifiers.ICustomCodeHelperObfuscator) customCodeHelperObfuscator: ICustomCodeHelperObfuscator,
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions,
@inject(ServiceIdentifiers.IEscapeSequenceEncoder) escapeSequenceEncoder: IEscapeSequenceEncoder
) {
super(
identifierNamesGeneratorFactory,
customCodeHelperFormatter,
customCodeHelperObfuscator,
randomGenerator,
options
);
this.escapeSequenceEncoder = escapeSequenceEncoder;
}
/**
* @param {string} stringArrayName
* @param {number} stringArrayRotationAmount
*/
public initialize (
stringArrayName: string,
stringArrayRotationAmount: number
): void {
this.stringArrayName = stringArrayName;
this.stringArrayRotationAmount = stringArrayRotationAmount;
}
/**
* @param {string} codeHelperTemplate
* @returns {TStatement[]}
*/
protected getNodeStructure (codeHelperTemplate: string): TStatement[] {
return NodeUtils.convertCodeToStructure(codeHelperTemplate);
}
/**
* @returns {string}
*/
protected getCodeHelperTemplate (): string {
const timesName: string = this.identifierNamesGenerator.generateNext();
const whileFunctionName: string = this.identifierNamesGenerator.generateNext();
const preservedNames: string[] = [`^${this.stringArrayName}$`];
let code: string = '';
if (this.options.selfDefending) {
code = this.customCodeHelperFormatter.formatTemplate(SelfDefendingTemplate(this.escapeSequenceEncoder), {
timesName,
whileFunctionName
});
} else {
code = `${whileFunctionName}(++${timesName})`;
}
return this.customCodeHelperObfuscator.obfuscateTemplate(
this.customCodeHelperFormatter.formatTemplate(StringArrayRotateFunctionTemplate(), {
code,
timesName,
whileFunctionName,
stringArrayName: this.stringArrayName,
stringArrayRotationAmount: NumberUtils.toHex(this.stringArrayRotationAmount)
}),
{
reservedNames: preservedNames
}
);
}
}
@@ -0,0 +1,175 @@
import { inject, injectable, } from 'inversify';
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 { TNodeWithStatements } from '../../../types/node/TNodeWithStatements';
import { TStringArrayEncoding } from '../../../types/options/TStringArrayEncoding';
import { ICallsGraphData } from '../../../interfaces/analyzers/calls-graph-analyzer/ICallsGraphData';
import { ICustomCodeHelper } from '../../../interfaces/custom-code-helpers/ICustomCodeHelper';
import { IOptions } from '../../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../../interfaces/utils/IRandomGenerator';
import { IStringArrayStorage } from '../../../interfaces/storages/string-array-transformers/IStringArrayStorage';
import { initializable } from '../../../decorators/Initializable';
import { CustomCodeHelper } from '../../../enums/custom-code-helpers/CustomCodeHelper';
import { ObfuscationEvent } from '../../../enums/event-emitters/ObfuscationEvent';
import { StringArrayEncoding } from '../../../enums/node-transformers/string-array-transformers/StringArrayEncoding';
import { AbstractCustomCodeHelperGroup } from '../../AbstractCustomCodeHelperGroup';
import { NodeAppender } from '../../../node/NodeAppender';
import { StringArrayCallsWrapperCodeHelper } from '../StringArrayCallsWrapperCodeHelper';
import { StringArrayCodeHelper } from '../StringArrayCodeHelper';
import { StringArrayRotateFunctionCodeHelper } from '../StringArrayRotateFunctionCodeHelper';
@injectable()
export class StringArrayCodeHelperGroup extends AbstractCustomCodeHelperGroup {
/**
* @type {Map<TStringArrayEncoding, CustomCodeHelper>}
*/
private static readonly stringArrayCallsWrapperCodeHelperMap: Map<TStringArrayEncoding, CustomCodeHelper> = new Map([
[StringArrayEncoding.None, CustomCodeHelper.StringArrayCallsWrapper],
[StringArrayEncoding.Base64, CustomCodeHelper.StringArrayCallsWrapperBase64],
[StringArrayEncoding.Rc4, CustomCodeHelper.StringArrayCallsWrapperRc4]
]);
/**
* @type {Map<CustomCodeHelper, ICustomCodeHelper>}
*/
@initializable()
protected customCodeHelpers!: Map <CustomCodeHelper, ICustomCodeHelper>;
/**
* @type {ObfuscationEvent}
*/
protected appendEvent: ObfuscationEvent = ObfuscationEvent.AfterObfuscation;
/**
* @type {TCustomCodeHelperFactory}
*/
private readonly customCodeHelperFactory: TCustomCodeHelperFactory;
/**
* @type {IStringArrayStorage}
*/
private readonly stringArrayStorage: IStringArrayStorage;
/**
* @param {TCustomCodeHelperFactory} customCodeHelperFactory
* @param {IStringArrayStorage} stringArrayStorage
* @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
*/
public constructor (
@inject(ServiceIdentifiers.Factory__ICustomCodeHelper) customCodeHelperFactory: TCustomCodeHelperFactory,
@inject(ServiceIdentifiers.IStringArrayStorage) stringArrayStorage: IStringArrayStorage,
@inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
super(identifierNamesGeneratorFactory, randomGenerator, options);
this.customCodeHelperFactory = customCodeHelperFactory;
this.stringArrayStorage = stringArrayStorage;
}
/**
* @param {TNodeWithStatements} nodeWithStatements
* @param {ICallsGraphData[]} callsGraphData
*/
public appendNodes (nodeWithStatements: TNodeWithStatements, callsGraphData: ICallsGraphData[]): void {
if (!this.stringArrayStorage.getLength()) {
return;
}
// stringArray helper nodes append
this.appendCustomNodeIfExist(
CustomCodeHelper.StringArray,
(customCodeHelper: ICustomCodeHelper<TInitialData<StringArrayCodeHelper>>) => {
NodeAppender.prepend(nodeWithStatements, customCodeHelper.getNode());
}
);
// stringArrayCallsWrapper helper nodes append
const stringArrayEncodingsLength: number = this.options.stringArrayEncoding.length;
for (let i = 0; i < stringArrayEncodingsLength; i++) {
const stringArrayEncoding: TStringArrayEncoding = this.options.stringArrayEncoding[i];
const stringArrayCallsWrapperCodeHelperName: CustomCodeHelper = this.getStringArrayCallsWrapperCodeHelperName(stringArrayEncoding);
this.appendCustomNodeIfExist(
stringArrayCallsWrapperCodeHelperName,
(customCodeHelper: ICustomCodeHelper<TInitialData<StringArrayCallsWrapperCodeHelper>>) => {
NodeAppender.insertAtIndex(nodeWithStatements, customCodeHelper.getNode(), i + 1);
}
);
}
// stringArrayRotateFunction helper nodes append
this.appendCustomNodeIfExist(
CustomCodeHelper.StringArrayRotateFunction,
(customCodeHelper: ICustomCodeHelper<TInitialData<StringArrayRotateFunctionCodeHelper>>) => {
NodeAppender.insertAtIndex(nodeWithStatements, customCodeHelper.getNode(), 1);
}
);
}
public initialize (): void {
this.customCodeHelpers = new Map <CustomCodeHelper, ICustomCodeHelper>();
if (!this.options.stringArray) {
return;
}
// stringArray helper initialize
const stringArrayCodeHelper: ICustomCodeHelper<TInitialData<StringArrayCodeHelper>> =
this.customCodeHelperFactory(CustomCodeHelper.StringArray);
const stringArrayName: string = this.stringArrayStorage.getStorageName();
stringArrayCodeHelper.initialize(this.stringArrayStorage, stringArrayName);
this.customCodeHelpers.set(CustomCodeHelper.StringArray, stringArrayCodeHelper);
// stringArrayCallsWrapper helper initialize
for (const stringArrayEncoding of this.options.stringArrayEncoding) {
const stringArrayCallsWrapperCodeHelperName: CustomCodeHelper = this.getStringArrayCallsWrapperCodeHelperName(stringArrayEncoding);
const stringArrayCallsWrapperCodeHelper: ICustomCodeHelper<TInitialData<StringArrayCallsWrapperCodeHelper>> =
this.customCodeHelperFactory(stringArrayCallsWrapperCodeHelperName);
const stringArrayCallsWrapperName: string = this.stringArrayStorage.getStorageCallsWrapperName(stringArrayEncoding);
stringArrayCallsWrapperCodeHelper.initialize(
stringArrayName,
stringArrayCallsWrapperName,
this.stringArrayStorage.getIndexShiftAmount()
);
this.customCodeHelpers.set(stringArrayCallsWrapperCodeHelperName, stringArrayCallsWrapperCodeHelper);
}
// stringArrayRotateFunction helper initialize
const stringArrayRotateFunctionCodeHelper: ICustomCodeHelper<TInitialData<StringArrayRotateFunctionCodeHelper>> =
this.customCodeHelperFactory(CustomCodeHelper.StringArrayRotateFunction);
stringArrayRotateFunctionCodeHelper.initialize(
stringArrayName,
this.stringArrayStorage.getRotationAmount()
);
if (this.options.rotateStringArray) {
this.customCodeHelpers.set(CustomCodeHelper.StringArrayRotateFunction, stringArrayRotateFunctionCodeHelper);
}
}
/**
* @param {TStringArrayEncoding} stringArrayEncoding
* @returns {CustomCodeHelper}
*/
private getStringArrayCallsWrapperCodeHelperName (stringArrayEncoding: TStringArrayEncoding): CustomCodeHelper {
return StringArrayCodeHelperGroup
.stringArrayCallsWrapperCodeHelperMap.get(stringArrayEncoding)
?? CustomCodeHelper.StringArrayCallsWrapper;
}
}
@@ -0,0 +1,24 @@
import { base64alphabetSwapped } from '../../../../constants/Base64AlphabetSwapped';
/**
* @returns {string}
*/
export function AtobTemplate (): string {
return `
var {atobFunctionName} = function (input) {
const chars = '${base64alphabetSwapped}';
const str = String(input).replace(/=+$/, '');
let output = '';
for (
let bc = 0, bs, buffer, idx = 0;
buffer = str.charAt(idx++);
~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer,
bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0
) {
buffer = chars.indexOf(buffer);
}
return output;
};
`;
}
@@ -0,0 +1,45 @@
/**
* @returns {string}
*/
export function Rc4Template (): string {
return `
const rc4 = function (str, key) {
let s = [], j = 0, x, res = '', newStr = '';
str = {atobFunctionName}(str);
for (let k = 0, length = str.length; k < length; k++) {
newStr += '%' + ('00' + str.charCodeAt(k).toString(16)).slice(-2);
}
str = decodeURIComponent(newStr);
let i;
for (i = 0; i < 256; i++) {
s[i] = i;
}
for (i = 0; i < 256; i++) {
j = (j + s[i] + key.charCodeAt(i % key.length)) % 256;
x = s[i];
s[i] = s[j];
s[j] = x;
}
i = 0;
j = 0;
for (let y = 0; y < str.length; y++) {
i = (i + 1) % 256;
j = (j + s[i]) % 256;
x = s[i];
s[i] = s[j];
s[j] = x;
res += String.fromCharCode(str.charCodeAt(y) ^ s[(s[i] + s[j]) % 256]);
}
return res;
}
`;
}
@@ -0,0 +1,66 @@
import { IEscapeSequenceEncoder } from '../../../../interfaces/utils/IEscapeSequenceEncoder';
import { IRandomGenerator } from '../../../../interfaces/utils/IRandomGenerator';
/**
* @param {IRandomGenerator} randomGenerator
* @param {IEscapeSequenceEncoder} escapeSequenceEncoder
* @returns {string}
* @constructor
*/
export function SelfDefendingTemplate (
randomGenerator: IRandomGenerator,
escapeSequenceEncoder: IEscapeSequenceEncoder
): string {
const identifierLength: number = 6;
const rc4BytesIdentifier: string = randomGenerator.getRandomString(identifierLength);
const statesIdentifier: string = randomGenerator.getRandomString(identifierLength);
const newStateIdentifier: string = randomGenerator.getRandomString(identifierLength);
const firstStateIdentifier: string = randomGenerator.getRandomString(identifierLength);
const secondStateIdentifier: string = randomGenerator.getRandomString(identifierLength);
const checkStateIdentifier: string = randomGenerator.getRandomString(identifierLength);
const runStateIdentifier: string = randomGenerator.getRandomString(identifierLength);
const getStateIdentifier: string = randomGenerator.getRandomString(identifierLength);
const stateResultIdentifier: string = randomGenerator.getRandomString(identifierLength);
return `
const StatesClass = function (${rc4BytesIdentifier}) {
this.${rc4BytesIdentifier} = ${rc4BytesIdentifier};
this.${statesIdentifier} = [1, 0, 0];
this.${newStateIdentifier} = function(){return 'newState';};
this.${firstStateIdentifier} = '${
escapeSequenceEncoder.encode('\\w+ *\\(\\) *{\\w+ *', true)
}';
this.${secondStateIdentifier} = '${
escapeSequenceEncoder.encode('[\'|"].+[\'|"];? *}', true)
}';
};
StatesClass.prototype.${checkStateIdentifier} = function () {
const regExp = new RegExp(this.${firstStateIdentifier} + this.${secondStateIdentifier});
const expression = regExp.test(this.${newStateIdentifier}.toString())
? --this.${statesIdentifier}[1]
: --this.${statesIdentifier}[0];
return this.${runStateIdentifier}(expression);
};
StatesClass.prototype.${runStateIdentifier} = function (${stateResultIdentifier}) {
if (!Boolean(~${stateResultIdentifier})) {
return ${stateResultIdentifier};
}
return this.${getStateIdentifier}(this.${rc4BytesIdentifier});
};
StatesClass.prototype.${getStateIdentifier} = function (${rc4BytesIdentifier}) {
for (let i = 0, len = this.${statesIdentifier}.length; i < len; i++) {
this.${statesIdentifier}.push(Math.round(Math.random()));
len = this.${statesIdentifier}.length;
}
return ${rc4BytesIdentifier}(this.${statesIdentifier}[0]);
};
new StatesClass({stringArrayCallsWrapperName}).${checkStateIdentifier}();
`;
}
@@ -0,0 +1,47 @@
import { IRandomGenerator } from '../../../../interfaces/utils/IRandomGenerator';
/**
* @param {IRandomGenerator} randomGenerator
* @returns {string}
* @constructor
*/
export function StringArrayBase64DecodeTemplate (
randomGenerator: IRandomGenerator
): string {
const identifierLength: number = 6;
const initializedIdentifier: string = randomGenerator.getRandomString(identifierLength);
const base64DecodeFunctionIdentifier: string = randomGenerator.getRandomString(identifierLength);
const dataIdentifier: string = randomGenerator.getRandomString(identifierLength);
return `
if ({stringArrayCallsWrapperName}.${initializedIdentifier} === undefined) {
{atobPolyfill}
{stringArrayCallsWrapperName}.${base64DecodeFunctionIdentifier} = function (str) {
const string = {atobFunctionName}(str);
let newStringChars = [];
for (let i = 0, length = string.length; i < length; i++) {
newStringChars += '%' + ('00' + string.charCodeAt(i).toString(16)).slice(-2);
}
return decodeURIComponent(newStringChars);
};
{stringArrayCallsWrapperName}.${dataIdentifier} = {};
{stringArrayCallsWrapperName}.${initializedIdentifier} = true;
}
const cachedValue = {stringArrayCallsWrapperName}.${dataIdentifier}[index];
if (cachedValue === undefined) {
{selfDefendingCode}
value = {stringArrayCallsWrapperName}.${base64DecodeFunctionIdentifier}(value);
{stringArrayCallsWrapperName}.${dataIdentifier}[index] = value;
} else {
value = cachedValue;
}
`;
}
@@ -0,0 +1,16 @@
/**
* @returns {string}
*/
export function StringArrayCallsWrapperTemplate (): string {
return `
const {stringArrayCallsWrapperName} = function (index, key) {
index = index - {indexShiftAmount};
let value = {stringArrayName}[index];
{decodeCodeHelperTemplate}
return value;
};
`;
}
@@ -0,0 +1,44 @@
import { IRandomGenerator } from '../../../../interfaces/utils/IRandomGenerator';
/**
* @param {IRandomGenerator} randomGenerator
* @returns {string}
* @constructor
*/
export function StringArrayRC4DecodeTemplate (
randomGenerator: IRandomGenerator
): string {
const identifierLength: number = 6;
const initializedIdentifier: string = randomGenerator.getRandomString(identifierLength);
const rc4Identifier: string = randomGenerator.getRandomString(identifierLength);
const dataIdentifier: string = randomGenerator.getRandomString(identifierLength);
const onceIdentifier: string = randomGenerator.getRandomString(identifierLength);
return `
if ({stringArrayCallsWrapperName}.${initializedIdentifier} === undefined) {
{atobPolyfill}
{rc4Polyfill}
{stringArrayCallsWrapperName}.${rc4Identifier} = rc4;
{stringArrayCallsWrapperName}.${dataIdentifier} = {};
{stringArrayCallsWrapperName}.${initializedIdentifier} = true;
}
const cachedValue = {stringArrayCallsWrapperName}.${dataIdentifier}[index];
if (cachedValue === undefined) {
if ({stringArrayCallsWrapperName}.${onceIdentifier} === undefined) {
{selfDefendingCode}
{stringArrayCallsWrapperName}.${onceIdentifier} = true;
}
value = {stringArrayCallsWrapperName}.${rc4Identifier}(value, key);
{stringArrayCallsWrapperName}.${dataIdentifier}[index] = value;
} else {
value = cachedValue;
}
`;
}
@@ -0,0 +1,81 @@
import { IEscapeSequenceEncoder } from '../../../../interfaces/utils/IEscapeSequenceEncoder';
/**
* SelfDefendingTemplate. Enter code in infinity loop.
*
* @param {IEscapeSequenceEncoder} escapeSequenceEncoder
* @returns {string}
*/
export function SelfDefendingTemplate (escapeSequenceEncoder: IEscapeSequenceEncoder): string {
return `
const selfDefendingFunc = function () {
const object = {
data: {
key: 'cookie',
value: 'timeout'
},
setCookie: function (options, name, value, document) {
document = document || {};
let updatedCookie = name + "=" + value;
let i = 0;
for (let i = 0, len = options.length; i < len; i++) {
const propName = options[i];
updatedCookie += "; " + propName;
const propValue = options[propName];
options.push(propValue);
len = options.length;
if (propValue !== true) {
updatedCookie += "=" + propValue;
}
}
document['cookie'] = updatedCookie;
},
removeCookie: function(){return 'dev';},
getCookie: function (document, name) {
document = document || function (value) { return value };
const matches = document(new RegExp(
"(?:^|; )" + name.replace(/([\.$?*|{}\(\)\[\]\\\/\+^])/g, '\\$1') + "=([^;]*)"
));
const func = function (param1, param2) {
param1(++param2);
};
func({whileFunctionName}, {timesName});
return matches ? decodeURIComponent(matches[1]) : undefined;
}
};
const test1 = function () {
const regExp = new RegExp('${
escapeSequenceEncoder.encode('\\w+ *\\(\\) *{\\w+ *[\'|"].+[\'|"];? *}', true)
}');
return regExp.test(object.removeCookie.toString());
};
object['updateCookie'] = test1;
let cookie = '';
const result = object['updateCookie']();
if (!result) {
object['setCookie'](['*'], 'counter', 1);
} else if (result) {
cookie = object['getCookie'](null, 'counter');
} else {
object['removeCookie']();
}
};
selfDefendingFunc();
`;
}
@@ -0,0 +1,16 @@
/**
* @returns {string}
*/
export function StringArrayRotateFunctionTemplate (): string {
return `
(function (array, {timesName}) {
const {whileFunctionName} = function (times) {
while (--times) {
array['push'](array['shift']());
}
};
{code}
})({stringArrayName}, {stringArrayRotationAmount});
`;
}
@@ -0,0 +1,8 @@
/**
* @returns {string}
*/
export function StringArrayTemplate (): string {
return `
const {stringArrayName} = [{stringArrayStorageItems}];
`;
}
@@ -0,0 +1,83 @@
import { inject, injectable } from 'inversify';
import { ServiceIdentifiers } from '../container/ServiceIdentifiers';
import { TIdentifierNamesGeneratorFactory } from '../types/container/generators/TIdentifierNamesGeneratorFactory';
import { TStatement } from '../types/node/TStatement';
import { ICustomNode } from '../interfaces/custom-nodes/ICustomNode';
import { ICustomCodeHelperFormatter } from '../interfaces/custom-code-helpers/ICustomCodeHelperFormatter';
import { IIdentifierNamesGenerator } from '../interfaces/generators/identifier-names-generators/IIdentifierNamesGenerator';
import { IOptions } from '../interfaces/options/IOptions';
import { IRandomGenerator } from '../interfaces/utils/IRandomGenerator';
@injectable()
export abstract class AbstractCustomNode <
TInitialData extends unknown[] = unknown[]
> implements ICustomNode <TInitialData> {
/**
* @type {TStatement[] | null}
*/
protected cachedNode: TStatement[] | null = null;
/**
* @type {ICustomCodeHelperFormatter}
*/
protected readonly customCodeHelperFormatter: ICustomCodeHelperFormatter;
/**
* @type {IIdentifierNamesGenerator}
*/
protected readonly identifierNamesGenerator: IIdentifierNamesGenerator;
/**
* @type {IOptions}
*/
protected readonly options: IOptions;
/**
* @type {IRandomGenerator}
*/
protected readonly randomGenerator: IRandomGenerator;
/**
* @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
* @param {ICustomCodeHelperFormatter} customCodeHelperFormatter
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
*/
protected constructor (
@inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
@inject(ServiceIdentifiers.ICustomCodeHelperFormatter) customCodeHelperFormatter: ICustomCodeHelperFormatter,
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
this.identifierNamesGenerator = identifierNamesGeneratorFactory(options);
this.customCodeHelperFormatter = customCodeHelperFormatter;
this.randomGenerator = randomGenerator;
this.options = options;
}
/**
* @returns {TStatement[]}
*/
public getNode (): TStatement[] {
if (!this.cachedNode) {
this.cachedNode = this.customCodeHelperFormatter.formatStructure(
this.getNodeStructure()
);
}
return this.cachedNode;
}
/**
* @param {TInitialData} args
*/
public abstract initialize (...args: TInitialData): void;
/**
* @returns {TStatement[]}
*/
protected abstract getNodeStructure (): TStatement[];
}
@@ -0,0 +1,78 @@
import { inject, injectable, } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import type { BinaryOperator } from 'estree';
import { TIdentifierNamesGeneratorFactory } from '../../types/container/generators/TIdentifierNamesGeneratorFactory';
import { TStatement } from '../../types/node/TStatement';
import { ICustomCodeHelperFormatter } from '../../interfaces/custom-code-helpers/ICustomCodeHelperFormatter';
import { IOptions } from '../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
import { AbstractCustomNode } from '../AbstractCustomNode';
import { NodeFactory } from '../../node/NodeFactory';
import { NodeUtils } from '../../node/NodeUtils';
@injectable()
export class BinaryExpressionFunctionNode extends AbstractCustomNode {
/**
* @type {BinaryOperator}
*/
private operator!: BinaryOperator;
/**
* @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
* @param {ICustomCodeHelperFormatter} customCodeHelperFormatter
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
*/
public constructor (
@inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
@inject(ServiceIdentifiers.ICustomCodeHelperFormatter) customCodeHelperFormatter: ICustomCodeHelperFormatter,
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
super(
identifierNamesGeneratorFactory,
customCodeHelperFormatter,
randomGenerator,
options
);
}
/**
* @param {BinaryOperator} operator
*/
public initialize (operator: BinaryOperator): void {
this.operator = operator;
}
/**
* @returns {TStatement[]}
*/
protected getNodeStructure (): TStatement[] {
const structure: TStatement = NodeFactory.expressionStatementNode(
NodeFactory.functionExpressionNode(
[
NodeFactory.identifierNode('x'),
NodeFactory.identifierNode('y')
],
NodeFactory.blockStatementNode([
NodeFactory.returnStatementNode(
NodeFactory.binaryExpressionNode(
this.operator,
NodeFactory.identifierNode('x'),
NodeFactory.identifierNode('y')
)
)
])
)
);
NodeUtils.parentizeAst(structure);
return [structure];
}
}
@@ -0,0 +1,153 @@
import { inject, injectable, } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import * as ESTree from 'estree';
import { TIdentifierNamesGeneratorFactory } from '../../types/container/generators/TIdentifierNamesGeneratorFactory';
import { TStatement } from '../../types/node/TStatement';
import { StringSeparator } from '../../enums/StringSeparator';
import { ICustomCodeHelperFormatter } from '../../interfaces/custom-code-helpers/ICustomCodeHelperFormatter';
import { IOptions } from '../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
import { initializable } from '../../decorators/Initializable';
import { AbstractCustomNode } from '../AbstractCustomNode';
import { NodeFactory } from '../../node/NodeFactory';
import { NodeGuards } from '../../node/NodeGuards';
import { NodeUtils } from '../../node/NodeUtils';
@injectable()
export class BlockStatementControlFlowFlatteningNode extends AbstractCustomNode {
/**
* @type {ESTree.Statement[]}
*/
@initializable()
private blockStatementBody!: ESTree.Statement[];
/**
* @type {number[]}
*/
@initializable()
private originalKeysIndexesInShuffledArray!: number[];
/**
* @type {number[]}
*/
@initializable()
private shuffledKeys!: number[];
/**
* @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
* @param {ICustomCodeHelperFormatter} customCodeHelperFormatter
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
*/
public constructor (
@inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
@inject(ServiceIdentifiers.ICustomCodeHelperFormatter) customCodeHelperFormatter: ICustomCodeHelperFormatter,
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
super(
identifierNamesGeneratorFactory,
customCodeHelperFormatter,
randomGenerator,
options
);
}
/**
* @param {Statement[]} blockStatementBody
* @param {number[]} shuffledKeys
* @param {number[]} originalKeysIndexesInShuffledArray
*/
public initialize (
blockStatementBody: ESTree.Statement[],
shuffledKeys: number[],
originalKeysIndexesInShuffledArray: number[]
): void {
this.blockStatementBody = blockStatementBody;
this.shuffledKeys = shuffledKeys;
this.originalKeysIndexesInShuffledArray = originalKeysIndexesInShuffledArray;
}
/**
* @returns {TStatement[]}
*/
protected getNodeStructure (): TStatement[] {
const controllerIdentifierName: string = this.randomGenerator.getRandomString(6);
const indexIdentifierName: string = this.randomGenerator.getRandomString(6);
const structure: ESTree.BlockStatement = NodeFactory.blockStatementNode([
NodeFactory.variableDeclarationNode(
[
NodeFactory.variableDeclaratorNode(
NodeFactory.identifierNode(controllerIdentifierName),
NodeFactory.callExpressionNode(
NodeFactory.memberExpressionNode(
NodeFactory.literalNode(
this.originalKeysIndexesInShuffledArray.join(StringSeparator.VerticalLine)
),
NodeFactory.identifierNode('split')
),
[
NodeFactory.literalNode(StringSeparator.VerticalLine)
]
)
)
],
'const'
),
NodeFactory.variableDeclarationNode(
[
NodeFactory.variableDeclaratorNode(
NodeFactory.identifierNode(indexIdentifierName),
NodeFactory.literalNode(0)
)
],
'let'
),
NodeFactory.whileStatementNode(
NodeFactory.literalNode(true),
NodeFactory.blockStatementNode([
NodeFactory.switchStatementNode(
NodeFactory.memberExpressionNode(
NodeFactory.identifierNode(controllerIdentifierName),
NodeFactory.updateExpressionNode(
'++',
NodeFactory.identifierNode(indexIdentifierName)
),
true
),
this.shuffledKeys.map((key: number, index: number) => {
const statement: ESTree.Statement = this.blockStatementBody[key];
const consequent: ESTree.Statement[] = [statement];
/**
* We shouldn't add continue statement after return statement
* to prevent `unreachable code after return statement` warnings
*/
if (!NodeGuards.isReturnStatementNode(statement)) {
consequent.push(NodeFactory.continueStatement());
}
return NodeFactory.switchCaseNode(
NodeFactory.literalNode(String(index)),
consequent
);
})
),
NodeFactory.breakStatement()
])
)
]);
NodeUtils.parentizeAst(structure);
return [structure];
}
}
@@ -0,0 +1,88 @@
import { inject, injectable, } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import * as ESTree from 'estree';
import { TIdentifierNamesGeneratorFactory } from '../../types/container/generators/TIdentifierNamesGeneratorFactory';
import { TStatement } from '../../types/node/TStatement';
import { ICustomCodeHelperFormatter } from '../../interfaces/custom-code-helpers/ICustomCodeHelperFormatter';
import { IOptions } from '../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
import { initializable } from '../../decorators/Initializable';
import { AbstractCustomNode } from '../AbstractCustomNode';
import { NodeFactory } from '../../node/NodeFactory';
import { NodeUtils } from '../../node/NodeUtils';
@injectable()
export class CallExpressionFunctionNode extends AbstractCustomNode {
/**
* @type {(ESTree.Expression | ESTree.SpreadElement)[]}
*/
@initializable()
private expressionArguments!: (ESTree.Expression | ESTree.SpreadElement)[];
/**
* @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
* @param {ICustomCodeHelperFormatter} customCodeHelperFormatter
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
*/
public constructor (
@inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
@inject(ServiceIdentifiers.ICustomCodeHelperFormatter) customCodeHelperFormatter: ICustomCodeHelperFormatter,
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
super(
identifierNamesGeneratorFactory,
customCodeHelperFormatter,
randomGenerator,
options
);
}
/**
* @param {(Expression | SpreadElement)[]} expressionArguments
*/
public initialize (expressionArguments: (ESTree.Expression | ESTree.SpreadElement)[]): void {
this.expressionArguments = expressionArguments;
}
/**
* @returns {TStatement[]}
*/
protected getNodeStructure (): TStatement[] {
const calleeIdentifier: ESTree.Identifier = NodeFactory.identifierNode('callee');
const params: ESTree.Identifier[] = [];
const argumentsLength: number = this.expressionArguments.length;
for (let i: number = 0; i < argumentsLength; i++) {
params.push(NodeFactory.identifierNode(`param${i + 1}`));
}
const structure: TStatement = NodeFactory.expressionStatementNode(
NodeFactory.functionExpressionNode(
[
calleeIdentifier,
...params
],
NodeFactory.blockStatementNode([
NodeFactory.returnStatementNode(
NodeFactory.callExpressionNode(
calleeIdentifier,
params
)
)
])
)
);
NodeUtils.parentizeAst(structure);
return [structure];
}
}
@@ -0,0 +1,78 @@
import { inject, injectable, } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import type { LogicalOperator } from 'estree';
import { TIdentifierNamesGeneratorFactory } from '../../types/container/generators/TIdentifierNamesGeneratorFactory';
import { TStatement } from '../../types/node/TStatement';
import { ICustomCodeHelperFormatter } from '../../interfaces/custom-code-helpers/ICustomCodeHelperFormatter';
import { IOptions } from '../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
import { AbstractCustomNode } from '../AbstractCustomNode';
import { NodeFactory } from '../../node/NodeFactory';
import { NodeUtils } from '../../node/NodeUtils';
@injectable()
export class LogicalExpressionFunctionNode extends AbstractCustomNode {
/**
* @type {LogicalOperator}
*/
private operator!: LogicalOperator;
/**
* @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
* @param {ICustomCodeHelperFormatter} customCodeHelperFormatter
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
*/
public constructor (
@inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
@inject(ServiceIdentifiers.ICustomCodeHelperFormatter) customCodeHelperFormatter: ICustomCodeHelperFormatter,
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
super(
identifierNamesGeneratorFactory,
customCodeHelperFormatter,
randomGenerator,
options
);
}
/**
* @param {LogicalOperator} operator
*/
public initialize (operator: LogicalOperator): void {
this.operator = operator;
}
/**
* @returns {TStatement[]}
*/
protected getNodeStructure (): TStatement[] {
const structure: TStatement = NodeFactory.expressionStatementNode(
NodeFactory.functionExpressionNode(
[
NodeFactory.identifierNode('x'),
NodeFactory.identifierNode('y')
],
NodeFactory.blockStatementNode([
NodeFactory.returnStatementNode(
NodeFactory.logicalExpressionNode(
this.operator,
NodeFactory.identifierNode('x'),
NodeFactory.identifierNode('y')
)
)
])
)
);
NodeUtils.parentizeAst(structure);
return [structure];
}
}
@@ -0,0 +1,62 @@
import { inject, injectable, } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import { TIdentifierNamesGeneratorFactory } from '../../types/container/generators/TIdentifierNamesGeneratorFactory';
import { TStatement } from '../../types/node/TStatement';
import { ICustomCodeHelperFormatter } from '../../interfaces/custom-code-helpers/ICustomCodeHelperFormatter';
import { IOptions } from '../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
import { initializable } from '../../decorators/Initializable';
import { AbstractCustomNode } from '../AbstractCustomNode';
import { NodeFactory } from '../../node/NodeFactory';
@injectable()
export class StringLiteralNode extends AbstractCustomNode {
/**
* @type {string}
*/
@initializable()
private literalValue!: string;
/**
* @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
* @param {ICustomCodeHelperFormatter} customCodeHelperFormatter
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
*/
public constructor (
@inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
@inject(ServiceIdentifiers.ICustomCodeHelperFormatter) customCodeHelperFormatter: ICustomCodeHelperFormatter,
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
super(
identifierNamesGeneratorFactory,
customCodeHelperFormatter,
randomGenerator,
options
);
}
/**
* @param {string} literalValue
*/
public initialize (literalValue: string): void {
this.literalValue = literalValue;
}
/**
* @returns {TStatement[]}
*/
protected getNodeStructure (): TStatement[] {
const structure: TStatement = NodeFactory.expressionStatementNode(
NodeFactory.literalNode(this.literalValue)
);
return [structure];
}
}
Loaded 100 of 3760 files, more files were not shown because too many files have changed in this diff. Show more