javascript-obfuscator
Version:
JavaScript obfuscator
148 lines (119 loc) • 5.33 kB
text/typescript
import { inject, injectable, } from 'inversify';
import { ServiceIdentifiers } from '../../../container/ServiceIdentifiers';
import * as ESTree from 'estree';
import { TIdentifierNamesGeneratorFactory } from '../../../types/container/generators/TIdentifierNamesGeneratorFactory';
import { TNodeWithLexicalScope } from '../../../types/node/TNodeWithLexicalScope';
import { IIdentifierNamesGenerator } from '../../../interfaces/generators/identifier-names-generators/IIdentifierNamesGenerator';
import { IIdentifierReplacer } from '../../../interfaces/node-transformers/rename-identifiers-transformers/replacer/IIdentifierReplacer';
import { IOptions } from '../../../interfaces/options/IOptions';
import { NodeFactory } from '../../../node/NodeFactory';
export class IdentifierReplacer implements IIdentifierReplacer {
/**
* @type {IIdentifierNamesGenerator}
*/
private readonly identifierNamesGenerator: IIdentifierNamesGenerator;
/**
* @type {Map<TNodeWithLexicalScope, Map<string, string>>}
*/
private readonly blockScopesMap: Map<TNodeWithLexicalScope, Map<string, string>> = new Map();
/**
* @type {IOptions}
*/
private readonly options: IOptions;
/**
* @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
* @param {IOptions} options
*/
public constructor (
identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
options: IOptions
) {
this.options = options;
this.identifierNamesGenerator = identifierNamesGeneratorFactory(options);
}
/**
* Store `nodeName` of global identifiers as key in map with random name as value.
* Reserved name will be ignored.
*
* @param {Node} identifierNode
* @param {TNodeWithLexicalScope} lexicalScopeNode
*/
public storeGlobalName (identifierNode: ESTree.Identifier, lexicalScopeNode: TNodeWithLexicalScope): void {
const identifierName: string = identifierNode.name;
if (this.isReservedName(identifierName)) {
return;
}
const newIdentifierName: string = this.identifierNamesGenerator.generateForGlobalScope();
if (!this.blockScopesMap.has(lexicalScopeNode)) {
this.blockScopesMap.set(lexicalScopeNode, new Map());
}
const namesMap: Map<string, string> = <Map<string, string>>this.blockScopesMap.get(lexicalScopeNode);
namesMap.set(identifierName, newIdentifierName);
}
/**
* Store `nodeName` of local identifier as key in map with random name as value.
* Reserved name will be ignored.
*
* @param {Identifier} identifierNode
* @param {TNodeWithLexicalScope} lexicalScopeNode
*/
public storeLocalName (identifierNode: ESTree.Identifier, lexicalScopeNode: TNodeWithLexicalScope): void {
const identifierName: string = identifierNode.name;
if (this.isReservedName(identifierName)) {
return;
}
const newIdentifierName: string = this.identifierNamesGenerator.generateForLexicalScope(lexicalScopeNode);
if (!this.blockScopesMap.has(lexicalScopeNode)) {
this.blockScopesMap.set(lexicalScopeNode, new Map());
}
const namesMap: Map<string, string> = <Map<string, string>>this.blockScopesMap.get(lexicalScopeNode);
namesMap.set(identifierName, newIdentifierName);
}
/**
* @param {Identifier} identifierNode
* @param {TNodeWithLexicalScope} lexicalScopeNode
* @returns {Identifier}
*/
public replace (identifierNode: ESTree.Identifier, lexicalScopeNode: TNodeWithLexicalScope): ESTree.Identifier {
let identifierName: string = identifierNode.name;
if (this.blockScopesMap.has(lexicalScopeNode)) {
const namesMap: Map<string, string> = <Map<string, string>>this.blockScopesMap.get(lexicalScopeNode);
if (namesMap.has(identifierName)) {
identifierName = <string>namesMap.get(identifierName);
}
}
return NodeFactory.identifierNode(identifierName);
}
/**
* Preserve `name` to protect it from further using
*
* @param {Identifier} identifierNode
*/
public preserveName (identifierNode: ESTree.Identifier): void {
this.identifierNamesGenerator.preserveName(identifierNode.name);
}
/**
* Preserve `name` to protect it from further using
*
* @param {Identifier} identifierNode
* @param {TNodeWithLexicalScope} lexicalScopeNode
*/
public preserveNameForLexicalScope (identifierNode: ESTree.Identifier, lexicalScopeNode: TNodeWithLexicalScope): void {
this.identifierNamesGenerator.preserveNameForLexicalScope(identifierNode.name, lexicalScopeNode);
}
/**
* @param {string} name
* @returns {boolean}
*/
private isReservedName (name: string): boolean {
if (!this.options.reservedNames.length) {
return false;
}
return this.options.reservedNames
.some((reservedName: string) => {
return new RegExp(reservedName, 'g').exec(name) !== null;
});
}
}