mirror of
https://github.com/javascript-obfuscator/javascript-obfuscator
synced 2026-08-09 12:42:29 +00:00
Reorganized transformers structure and order
This commit is contained in:
@@ -0,0 +1,231 @@
|
||||
import { inject, injectable, } from 'inversify';
|
||||
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
|
||||
|
||||
import * as ESTree from 'estree';
|
||||
|
||||
import { IEscapeSequenceEncoder } from '../../interfaces/utils/IEscapeSequenceEncoder';
|
||||
import { IOptions } from '../../interfaces/options/IOptions';
|
||||
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
|
||||
import { IStringArrayStorage } from '../../interfaces/storages/string-array-storage/IStringArrayStorage';
|
||||
import { IStringArrayStorageAnalyzer } from '../../interfaces/analyzers/string-array-storage-analyzer/IStringArrayStorageAnalyzer';
|
||||
import { IStringArrayStorageItemData } from '../../interfaces/storages/string-array-storage/IStringArrayStorageItem';
|
||||
import { IVisitor } from '../../interfaces/node-transformers/IVisitor';
|
||||
|
||||
import { NodeTransformationStage } from '../../enums/node-transformers/NodeTransformationStage';
|
||||
import { NodeTransformer } from '../../enums/node-transformers/NodeTransformer';
|
||||
import { StringArrayEncoding } from '../../enums/StringArrayEncoding';
|
||||
|
||||
import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
|
||||
import { NodeFactory } from '../../node/NodeFactory';
|
||||
import { NodeGuards } from '../../node/NodeGuards';
|
||||
import { NodeLiteralUtils } from '../../node/NodeLiteralUtils';
|
||||
import { NodeMetadata } from '../../node/NodeMetadata';
|
||||
import { NodeUtils } from '../../node/NodeUtils';
|
||||
import { NumberUtils } from '../../utils/NumberUtils';
|
||||
|
||||
@injectable()
|
||||
export class StringArrayTransformer extends AbstractNodeTransformer {
|
||||
/**
|
||||
* @type {NodeTransformer[]}
|
||||
*/
|
||||
public readonly runAfter: NodeTransformer[] = [
|
||||
NodeTransformer.MemberExpressionTransformer
|
||||
];
|
||||
|
||||
/**
|
||||
* @type {IEscapeSequenceEncoder}
|
||||
*/
|
||||
private readonly escapeSequenceEncoder: IEscapeSequenceEncoder;
|
||||
|
||||
/**
|
||||
* @type {Map<string, ESTree.Node>}
|
||||
*/
|
||||
private readonly nodesCache: Map <string, ESTree.Node> = new Map();
|
||||
|
||||
/**
|
||||
* @type {IStringArrayStorage}
|
||||
*/
|
||||
private readonly stringArrayStorage: IStringArrayStorage;
|
||||
|
||||
/**
|
||||
* @type {IStringArrayStorageAnalyzer}
|
||||
*/
|
||||
private readonly stringArrayStorageAnalyzer: IStringArrayStorageAnalyzer;
|
||||
|
||||
/**
|
||||
* @param {IRandomGenerator} randomGenerator
|
||||
* @param {IOptions} options
|
||||
* @param {IStringArrayStorage} stringArrayStorage
|
||||
* @param {IStringArrayStorageAnalyzer} stringArrayStorageAnalyzer
|
||||
* @param {IEscapeSequenceEncoder} escapeSequenceEncoder
|
||||
*/
|
||||
public constructor (
|
||||
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
|
||||
@inject(ServiceIdentifiers.IOptions) options: IOptions,
|
||||
@inject(ServiceIdentifiers.IStringArrayStorage) stringArrayStorage: IStringArrayStorage,
|
||||
@inject(ServiceIdentifiers.IStringArrayStorageAnalyzer) stringArrayStorageAnalyzer: IStringArrayStorageAnalyzer,
|
||||
@inject(ServiceIdentifiers.IEscapeSequenceEncoder) escapeSequenceEncoder: IEscapeSequenceEncoder
|
||||
) {
|
||||
super(randomGenerator, options);
|
||||
|
||||
this.stringArrayStorage = stringArrayStorage;
|
||||
this.stringArrayStorageAnalyzer = stringArrayStorageAnalyzer;
|
||||
this.escapeSequenceEncoder = escapeSequenceEncoder;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} hexadecimalIndex
|
||||
* @returns {Literal}
|
||||
*/
|
||||
private static getHexadecimalLiteralNode (hexadecimalIndex: string): ESTree.Literal {
|
||||
const hexadecimalLiteralNode: ESTree.Literal = NodeFactory.literalNode(hexadecimalIndex);
|
||||
|
||||
NodeMetadata.set(hexadecimalLiteralNode, { replacedLiteral: true });
|
||||
|
||||
return hexadecimalLiteralNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} literalValue
|
||||
* @returns {Literal}
|
||||
*/
|
||||
private static getRc4KeyLiteralNode (literalValue: string): ESTree.Literal {
|
||||
const rc4KeyLiteralNode: ESTree.Literal = NodeFactory.literalNode(literalValue);
|
||||
|
||||
NodeMetadata.set(rc4KeyLiteralNode, { replacedLiteral: true });
|
||||
|
||||
return rc4KeyLiteralNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {NodeTransformationStage} nodeTransformationStage
|
||||
* @returns {IVisitor | null}
|
||||
*/
|
||||
public getVisitor (nodeTransformationStage: NodeTransformationStage): IVisitor | null {
|
||||
switch (nodeTransformationStage) {
|
||||
case NodeTransformationStage.StringArray:
|
||||
return {
|
||||
enter: (node: ESTree.Node, parentNode: ESTree.Node | null): ESTree.Node | undefined => {
|
||||
if (NodeGuards.isProgramNode(node)) {
|
||||
this.prepareNode(node);
|
||||
}
|
||||
|
||||
if (parentNode && NodeGuards.isLiteralNode(node) && !NodeMetadata.isReplacedLiteral(node)) {
|
||||
return this.transformNode(node, parentNode);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
case NodeTransformationStage.Finalizing:
|
||||
return {
|
||||
enter: (node: ESTree.Node, parentNode: ESTree.Node | null): ESTree.Node | undefined => {
|
||||
if (parentNode && NodeGuards.isLiteralNode(node)) {
|
||||
return this.encodeLiteralNodeToEscapeSequence(node, parentNode);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Program} programNode
|
||||
*/
|
||||
public prepareNode (programNode: ESTree.Program): void {
|
||||
this.stringArrayStorageAnalyzer.analyze(programNode);
|
||||
|
||||
if (this.options.shuffleStringArray) {
|
||||
this.stringArrayStorage.shuffleStorage();
|
||||
}
|
||||
|
||||
if (this.options.rotateStringArray) {
|
||||
this.stringArrayStorage.rotateStorage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Literal} literalNode
|
||||
* @param {NodeGuards} parentNode
|
||||
* @returns {NodeGuards}
|
||||
*/
|
||||
public transformNode (literalNode: ESTree.Literal, parentNode: ESTree.Node): ESTree.Node {
|
||||
if (typeof literalNode.value !== 'string' || NodeLiteralUtils.isProhibitedLiteralNode(literalNode, parentNode)) {
|
||||
return literalNode;
|
||||
}
|
||||
|
||||
const literalValue: ESTree.SimpleLiteral['value'] = literalNode.value;
|
||||
|
||||
const stringArrayStorageItemData: IStringArrayStorageItemData | undefined = this.stringArrayStorageAnalyzer
|
||||
.getItemDataForLiteralNode(literalNode);
|
||||
const cacheKey: string = `${literalValue}-${Boolean(stringArrayStorageItemData)}`;
|
||||
const useCachedValue: boolean = this.nodesCache.has(cacheKey) && this.options.stringArrayEncoding !== StringArrayEncoding.Rc4;
|
||||
|
||||
if (useCachedValue) {
|
||||
return <ESTree.Node>this.nodesCache.get(cacheKey);
|
||||
}
|
||||
|
||||
const resultNode: ESTree.Node = stringArrayStorageItemData
|
||||
? this.getStringArrayCallNode(stringArrayStorageItemData)
|
||||
: this.getLiteralNode(literalValue);
|
||||
|
||||
this.nodesCache.set(cacheKey, resultNode);
|
||||
|
||||
NodeUtils.parentizeNode(resultNode, parentNode);
|
||||
|
||||
return resultNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @returns {Node}
|
||||
*/
|
||||
private getLiteralNode (value: string): ESTree.Node {
|
||||
return NodeFactory.literalNode(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {IStringArrayStorageItemData} stringArrayStorageItemData
|
||||
* @returns {Node}
|
||||
*/
|
||||
private getStringArrayCallNode (stringArrayStorageItemData: IStringArrayStorageItemData): ESTree.Node {
|
||||
const { index, decodeKey } = stringArrayStorageItemData;
|
||||
|
||||
const hexadecimalIndex: string = NumberUtils.toHex(index);
|
||||
const callExpressionArgs: (ESTree.Expression | ESTree.SpreadElement)[] = [
|
||||
StringArrayTransformer.getHexadecimalLiteralNode(hexadecimalIndex)
|
||||
];
|
||||
|
||||
if (decodeKey) {
|
||||
callExpressionArgs.push(StringArrayTransformer.getRc4KeyLiteralNode(decodeKey));
|
||||
}
|
||||
|
||||
const stringArrayIdentifierNode: ESTree.Identifier = NodeFactory.identifierNode(
|
||||
this.stringArrayStorage.getStorageCallsWrapperName()
|
||||
);
|
||||
|
||||
return NodeFactory.callExpressionNode(
|
||||
stringArrayIdentifierNode,
|
||||
callExpressionArgs
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Literal} literalNode
|
||||
* @param {Node} parentNode
|
||||
* @returns {Literal}
|
||||
*/
|
||||
private encodeLiteralNodeToEscapeSequence (
|
||||
literalNode: ESTree.Literal,
|
||||
parentNode: ESTree.Node
|
||||
): ESTree.Literal {
|
||||
if (typeof literalNode.value !== 'string') {
|
||||
return literalNode;
|
||||
}
|
||||
|
||||
return NodeFactory.literalNode(
|
||||
this.escapeSequenceEncoder.encode(literalNode.value, this.options.unicodeEscapeSequence)
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user