mirror of
https://github.com/javascript-obfuscator/javascript-obfuscator
synced 2026-08-09 12:42:29 +00:00
Optimisations for identifers renaming
Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/146
This commit is contained in:
@@ -17,6 +17,7 @@ import { DEFAULT_PRESET } from '../options/presets/Default';
|
||||
|
||||
import { ArraySanitizer } from './sanitizers/ArraySanitizer';
|
||||
import { BooleanSanitizer } from './sanitizers/BooleanSanitizer';
|
||||
import { IdentifierNamesGeneratorSanitizer } from './sanitizers/IdentifierNamesGeneratorSanitizer';
|
||||
import { ObfuscationTargetSanitizer } from './sanitizers/ObfuscatingTargetSanitizer';
|
||||
import { SourceMapModeSanitizer } from './sanitizers/SourceMapModeSanitizer';
|
||||
import { StringArrayEncodingSanitizer } from './sanitizers/StringArrayEncodingSanitizer';
|
||||
@@ -241,7 +242,7 @@ export class JavaScriptObfuscatorCLI implements IInitializable {
|
||||
)
|
||||
.option(
|
||||
'--identifier-names-generator <string> [hexadecimal, mangled]', 'Sets identifier names generator (Default: hexadecimal)',
|
||||
BooleanSanitizer
|
||||
IdentifierNamesGeneratorSanitizer
|
||||
)
|
||||
.option(
|
||||
'--log <boolean>', 'Enables logging of the information to the console',
|
||||
|
||||
@@ -6,7 +6,7 @@ import { TCLISanitizer } from '../../types/cli/TCLISanitizer';
|
||||
*/
|
||||
export const ArraySanitizer: TCLISanitizer = (value: string): string[] => {
|
||||
if (/,$/.test(value)) {
|
||||
throw new SyntaxError(`Multiple <list> values should be wrapped inside quotes: --optionName 'value1, value2'`);
|
||||
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,21 @@
|
||||
import { TCLISanitizer } from '../../types/cli/TCLISanitizer';
|
||||
|
||||
import { IdentifierNamesGenerator } from '../../enums/generators/identifier-names-generators/IdentifierNamesGenerator';
|
||||
|
||||
/**
|
||||
* @param {string} value
|
||||
* @returns {string}
|
||||
*/
|
||||
export const IdentifierNamesGeneratorSanitizer: TCLISanitizer = (value: string): string => {
|
||||
const isCorrectIdentifierNamesGenerator: boolean = Object
|
||||
.keys(IdentifierNamesGenerator)
|
||||
.some((key: any): boolean => {
|
||||
return IdentifierNamesGenerator[key] === value;
|
||||
});
|
||||
|
||||
if (!isCorrectIdentifierNamesGenerator) {
|
||||
throw new ReferenceError('Invalid value of `--identifier-names-generator` option');
|
||||
}
|
||||
|
||||
return value;
|
||||
};
|
||||
@@ -14,7 +14,7 @@ export const SourceMapModeSanitizer: TCLISanitizer = (value: string): string =>
|
||||
});
|
||||
|
||||
if (!isCorrectSourceMapMode) {
|
||||
throw new ReferenceError('Invalid value of `--sourceMapMode` option');
|
||||
throw new ReferenceError('Invalid value of `--source-map-mode` option');
|
||||
}
|
||||
|
||||
return value;
|
||||
|
||||
@@ -6,6 +6,8 @@ import * as ESTree from 'estree';
|
||||
|
||||
import { TIdentifierObfuscatingReplacerFactory } from "../../types/container/node-transformers/TIdentifierObfuscatingReplacerFactory";
|
||||
import { TNodeWithBlockStatement } from '../../types/node/TNodeWithBlockStatement';
|
||||
import { TReplaceableIdentifiers } from '../../types/node-transformers/TReplaceableIdentifiers';
|
||||
import { TReplaceableIdentifiersNames } from '../../types/node-transformers/TReplaceableIdentifiersNamesMap';
|
||||
|
||||
import { IIdentifierObfuscatingReplacer } from '../../interfaces/node-transformers/obfuscating-transformers/obfuscating-replacers/IIdentifierObfuscatingReplacer';
|
||||
import { IOptions } from '../../interfaces/options/IOptions';
|
||||
@@ -38,7 +40,7 @@ export class FunctionDeclarationTransformer extends AbstractNodeTransformer {
|
||||
/**
|
||||
* @type {Map<ESTree.Node, ESTree.Identifier[]>}
|
||||
*/
|
||||
private readonly replaceableIdentifiers: Map <ESTree.Node, ESTree.Identifier[]> = new Map();
|
||||
private readonly replaceableIdentifiers: TReplaceableIdentifiers = new Map();
|
||||
|
||||
/**
|
||||
* @param {TIdentifierObfuscatingReplacerFactory} identifierObfuscatingReplacerFactory
|
||||
@@ -89,7 +91,7 @@ export class FunctionDeclarationTransformer extends AbstractNodeTransformer {
|
||||
|
||||
// check for cached identifiers for current scope node. If exist - loop through them.
|
||||
if (this.replaceableIdentifiers.has(blockScopeNode)) {
|
||||
this.replaceScopeCachedIdentifiers(blockScopeNode, nodeIdentifier);
|
||||
this.replaceScopeCachedIdentifiers(functionDeclarationNode, blockScopeNode, nodeIdentifier);
|
||||
} else {
|
||||
this.replaceScopeIdentifiers(blockScopeNode, nodeIdentifier);
|
||||
}
|
||||
@@ -106,18 +108,37 @@ export class FunctionDeclarationTransformer extends AbstractNodeTransformer {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {FunctionDeclaration} functionDeclarationNode
|
||||
* @param {TNodeWithBlockStatement} blockScopeNode
|
||||
* @param {number} nodeIdentifier
|
||||
*/
|
||||
private replaceScopeCachedIdentifiers (blockScopeNode: TNodeWithBlockStatement, nodeIdentifier: number): void {
|
||||
const cachedReplaceableIdentifiers: ESTree.Identifier[] = <ESTree.Identifier[]>this.replaceableIdentifiers.get(blockScopeNode);
|
||||
private replaceScopeCachedIdentifiers (
|
||||
functionDeclarationNode: ESTree.FunctionDeclaration,
|
||||
blockScopeNode: TNodeWithBlockStatement,
|
||||
nodeIdentifier: number
|
||||
): void {
|
||||
const cachedReplaceableIdentifiersNamesMap: TReplaceableIdentifiersNames | undefined = this.replaceableIdentifiers.get(blockScopeNode);
|
||||
|
||||
cachedReplaceableIdentifiers.forEach((replaceableIdentifier: ESTree.Identifier) => {
|
||||
const newReplaceableIdentifier: ESTree.Identifier = this.identifierObfuscatingReplacer.
|
||||
replace(replaceableIdentifier.name, nodeIdentifier);
|
||||
if (!cachedReplaceableIdentifiersNamesMap) {
|
||||
return;
|
||||
}
|
||||
|
||||
const cachedReplaceableIdentifiers: ESTree.Identifier[] | undefined = cachedReplaceableIdentifiersNamesMap
|
||||
.get(functionDeclarationNode.id.name);
|
||||
|
||||
if (!cachedReplaceableIdentifiers) {
|
||||
return;
|
||||
}
|
||||
|
||||
const cachedReplaceableIdentifierLength: number = cachedReplaceableIdentifiers.length;
|
||||
|
||||
for (let i: number = 0; i < cachedReplaceableIdentifierLength; i++) {
|
||||
const replaceableIdentifier: ESTree.Identifier = cachedReplaceableIdentifiers[i];
|
||||
const newReplaceableIdentifier: ESTree.Identifier = this.identifierObfuscatingReplacer
|
||||
.replace(replaceableIdentifier.name, nodeIdentifier);
|
||||
|
||||
replaceableIdentifier.name = newReplaceableIdentifier.name;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -125,7 +146,7 @@ export class FunctionDeclarationTransformer extends AbstractNodeTransformer {
|
||||
* @param {number} nodeIdentifier
|
||||
*/
|
||||
private replaceScopeIdentifiers (blockScopeNode: TNodeWithBlockStatement, nodeIdentifier: number): void {
|
||||
const storedReplaceableIdentifiers: ESTree.Identifier[] = [];
|
||||
const storedReplaceableIdentifiersNamesMap: TReplaceableIdentifiersNames = new Map();
|
||||
|
||||
estraverse.replace(blockScopeNode, {
|
||||
enter: (node: ESTree.Node, parentNode: ESTree.Node | null): any => {
|
||||
@@ -137,12 +158,15 @@ export class FunctionDeclarationTransformer extends AbstractNodeTransformer {
|
||||
if (node.name !== newIdentifierName) {
|
||||
node.name = newIdentifierName;
|
||||
} else {
|
||||
const storedReplaceableIdentifiers: ESTree.Identifier[] = storedReplaceableIdentifiersNamesMap.get(node.name) || [];
|
||||
|
||||
storedReplaceableIdentifiers.push(node);
|
||||
storedReplaceableIdentifiersNamesMap.set(node.name, storedReplaceableIdentifiers);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.replaceableIdentifiers.set(blockScopeNode, storedReplaceableIdentifiers);
|
||||
this.replaceableIdentifiers.set(blockScopeNode, storedReplaceableIdentifiersNamesMap);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@ import * as ESTree from 'estree';
|
||||
|
||||
import { TIdentifierObfuscatingReplacerFactory } from '../../types/container/node-transformers/TIdentifierObfuscatingReplacerFactory';
|
||||
import { TNodeWithBlockStatement } from '../../types/node/TNodeWithBlockStatement';
|
||||
import { TReplaceableIdentifiers } from '../../types/node-transformers/TReplaceableIdentifiers';
|
||||
import { TReplaceableIdentifiersNames } from '../../types/node-transformers/TReplaceableIdentifiersNamesMap';
|
||||
|
||||
import { IIdentifierObfuscatingReplacer } from '../../interfaces/node-transformers/obfuscating-transformers/obfuscating-replacers/IIdentifierObfuscatingReplacer';
|
||||
import { IOptions } from '../../interfaces/options/IOptions';
|
||||
@@ -37,9 +39,9 @@ export class VariableDeclarationTransformer extends AbstractNodeTransformer {
|
||||
private readonly identifierObfuscatingReplacer: IIdentifierObfuscatingReplacer;
|
||||
|
||||
/**
|
||||
* @type {Map<ESTree.Node, ESTree.Identifier[]>}
|
||||
* @type {TReplaceableIdentifiers}
|
||||
*/
|
||||
private readonly replaceableIdentifiers: Map <ESTree.Node, ESTree.Identifier[]> = new Map();
|
||||
private readonly replaceableIdentifiers: TReplaceableIdentifiers = new Map();
|
||||
|
||||
/**
|
||||
* @param {TIdentifierObfuscatingReplacerFactory} identifierObfuscatingReplacerFactory
|
||||
@@ -94,7 +96,7 @@ export class VariableDeclarationTransformer extends AbstractNodeTransformer {
|
||||
|
||||
// check for cached identifiers for current scope node. If exist - loop through them.
|
||||
if (this.replaceableIdentifiers.has(scopeNode)) {
|
||||
this.replaceScopeCachedIdentifiers(scopeNode, nodeIdentifier);
|
||||
this.replaceScopeCachedIdentifiers(variableDeclarationNode, scopeNode, nodeIdentifier);
|
||||
} else {
|
||||
this.replaceScopeIdentifiers(scopeNode, nodeIdentifier);
|
||||
}
|
||||
@@ -107,34 +109,54 @@ export class VariableDeclarationTransformer extends AbstractNodeTransformer {
|
||||
* @param {number} nodeIdentifier
|
||||
*/
|
||||
private storeVariableNames (variableDeclarationNode: ESTree.VariableDeclaration, nodeIdentifier: number): void {
|
||||
variableDeclarationNode.declarations
|
||||
.forEach((declarationNode: ESTree.VariableDeclarator) => {
|
||||
if (NodeGuards.isObjectPatternNode(declarationNode.id)) {
|
||||
return estraverse.VisitorOption.Skip;
|
||||
}
|
||||
|
||||
estraverse.traverse(declarationNode.id, {
|
||||
enter: (node: ESTree.Node) => {
|
||||
if (NodeGuards.isIdentifierNode(node)) {
|
||||
this.identifierObfuscatingReplacer.storeNames(node.name, nodeIdentifier);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
this.traverseDeclarationIdentifiers(variableDeclarationNode, (identifierNode: ESTree.Identifier) => {
|
||||
this.identifierObfuscatingReplacer.storeNames(identifierNode.name, nodeIdentifier);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {VariableDeclaration} variableDeclarationNode
|
||||
* @param {Node} scopeNode
|
||||
* @param {number} nodeIdentifier
|
||||
*/
|
||||
private replaceScopeCachedIdentifiers (scopeNode: ESTree.Node, nodeIdentifier: number): void {
|
||||
const cachedReplaceableIdentifiers: ESTree.Identifier[] = <ESTree.Identifier[]>this.replaceableIdentifiers.get(scopeNode);
|
||||
private replaceScopeCachedIdentifiers (
|
||||
variableDeclarationNode: ESTree.VariableDeclaration,
|
||||
scopeNode: ESTree.Node,
|
||||
nodeIdentifier: number
|
||||
): void {
|
||||
const cachedReplaceableIdentifiersNamesMap: TReplaceableIdentifiersNames | undefined = this.replaceableIdentifiers.get(scopeNode);
|
||||
|
||||
cachedReplaceableIdentifiers.forEach((replaceableIdentifier: ESTree.Identifier) => {
|
||||
const newReplaceableIdentifier: ESTree.Identifier = this.identifierObfuscatingReplacer
|
||||
.replace(replaceableIdentifier.name, nodeIdentifier);
|
||||
if (!cachedReplaceableIdentifiersNamesMap) {
|
||||
return;
|
||||
}
|
||||
|
||||
replaceableIdentifier.name = newReplaceableIdentifier.name;
|
||||
const identifierNames: string[] = [];
|
||||
|
||||
this.traverseDeclarationIdentifiers(variableDeclarationNode, (identifierNode: ESTree.Identifier) => {
|
||||
identifierNames.push(identifierNode.name);
|
||||
});
|
||||
|
||||
identifierNames.forEach((identifierName: string) => {
|
||||
const cachedReplaceableIdentifiers: ESTree.Identifier[] | undefined = cachedReplaceableIdentifiersNamesMap.get(identifierName);
|
||||
|
||||
if (!cachedReplaceableIdentifiers) {
|
||||
return;
|
||||
}
|
||||
|
||||
const cachedReplaceableIdentifierLength: number = cachedReplaceableIdentifiers.length;
|
||||
|
||||
for (let i: number = 0; i < cachedReplaceableIdentifierLength; i++) {
|
||||
const replaceableIdentifier: ESTree.Identifier = cachedReplaceableIdentifiers[i];
|
||||
|
||||
if (identifierName !== replaceableIdentifier.name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const newReplaceableIdentifier: ESTree.Identifier = this.identifierObfuscatingReplacer
|
||||
.replace(replaceableIdentifier.name, nodeIdentifier);
|
||||
|
||||
replaceableIdentifier.name = newReplaceableIdentifier.name;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -143,7 +165,7 @@ export class VariableDeclarationTransformer extends AbstractNodeTransformer {
|
||||
* @param {number} nodeIdentifier
|
||||
*/
|
||||
private replaceScopeIdentifiers (blockScopeNode: ESTree.Node, nodeIdentifier: number): void {
|
||||
const storedReplaceableIdentifiers: ESTree.Identifier[] = [];
|
||||
const storedReplaceableIdentifiersNamesMap: TReplaceableIdentifiersNames = new Map();
|
||||
|
||||
estraverse.replace(blockScopeNode, {
|
||||
enter: (node: ESTree.Node, parentNode: ESTree.Node | null): any => {
|
||||
@@ -154,12 +176,39 @@ export class VariableDeclarationTransformer extends AbstractNodeTransformer {
|
||||
if (node.name !== newIdentifierName) {
|
||||
node.name = newIdentifierName;
|
||||
} else {
|
||||
const storedReplaceableIdentifiers: ESTree.Identifier[] = storedReplaceableIdentifiersNamesMap.get(node.name) || [];
|
||||
|
||||
storedReplaceableIdentifiers.push(node);
|
||||
storedReplaceableIdentifiersNamesMap.set(node.name, storedReplaceableIdentifiers);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.replaceableIdentifiers.set(blockScopeNode, storedReplaceableIdentifiers);
|
||||
this.replaceableIdentifiers.set(blockScopeNode, storedReplaceableIdentifiersNamesMap);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {VariableDeclaration} variableDeclarationNode
|
||||
* @param {(identifier: Identifier) => void} callback
|
||||
*/
|
||||
private traverseDeclarationIdentifiers (
|
||||
variableDeclarationNode: ESTree.VariableDeclaration,
|
||||
callback: (identifier: ESTree.Identifier) => void
|
||||
): void {
|
||||
variableDeclarationNode.declarations
|
||||
.forEach((declarationNode: ESTree.VariableDeclarator) => {
|
||||
if (NodeGuards.isObjectPatternNode(declarationNode.id)) {
|
||||
return estraverse.VisitorOption.Skip;
|
||||
}
|
||||
|
||||
estraverse.traverse(declarationNode.id, {
|
||||
enter: (node: ESTree.Node) => {
|
||||
if (NodeGuards.isIdentifierNode(node)) {
|
||||
callback(node);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,20 +66,9 @@ export class CommentsTransformer extends AbstractNodeTransformer {
|
||||
* @returns {Comment[]}
|
||||
*/
|
||||
private transformComments (comments: ESTree.Comment[]): ESTree.Comment[] {
|
||||
let i: number = comments.length;
|
||||
|
||||
while (i--) {
|
||||
const comment: ESTree.Comment = comments[i];
|
||||
const commentHasPreservedWords: boolean = CommentsTransformer.preservedWords
|
||||
.some((availableWord: string) => comment.value.includes(availableWord));
|
||||
|
||||
if (commentHasPreservedWords) {
|
||||
continue;
|
||||
}
|
||||
|
||||
comments.splice(i, 1);
|
||||
}
|
||||
|
||||
return comments;
|
||||
return comments.filter((comment: ESTree.Comment) =>
|
||||
CommentsTransformer.preservedWords
|
||||
.some((availableWord: string) => comment.value.includes(availableWord))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,8 @@ export class ObfuscatingGuardsTransformer extends AbstractNodeTransformer {
|
||||
* @returns {Node}
|
||||
*/
|
||||
public transformNode (node: ESTree.Node, parentNode: ESTree.Node | null): ESTree.Node {
|
||||
const obfuscationAllowed: boolean = this.obfuscatingGuards.every((nodeGuard: IObfuscatingGuard) => nodeGuard.check(node));
|
||||
const obfuscationAllowed: boolean = this.obfuscatingGuards
|
||||
.every((nodeGuard: IObfuscatingGuard) => nodeGuard.check(node));
|
||||
|
||||
node.ignoredNode = !obfuscationAllowed;
|
||||
|
||||
|
||||
+3
-1
@@ -4,6 +4,8 @@ import * as ESTree from 'estree';
|
||||
|
||||
import { IObfuscatingGuard } from '../../../interfaces/node-transformers/preparing-transformers/obfuscating-guards/IObfuscatingGuard';
|
||||
|
||||
import { NodeGuards } from '../../../node/NodeGuards';
|
||||
|
||||
@injectable()
|
||||
export class ConditionalCommentObfuscatingGuard implements IObfuscatingGuard {
|
||||
/**
|
||||
@@ -36,7 +38,7 @@ export class ConditionalCommentObfuscatingGuard implements IObfuscatingGuard {
|
||||
this.obfuscationAllowedForNextNode = null;
|
||||
}
|
||||
|
||||
if (!node.leadingComments && !node.trailingComments) {
|
||||
if (!NodeGuards.isNodeWithComments(node)) {
|
||||
return this.obfuscationAllowedForCurrentNode;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import * as ESTree from 'estree';
|
||||
|
||||
export type TReplaceableIdentifiers = Map <ESTree.Node, Map<string, ESTree.Identifier[]>>;
|
||||
@@ -0,0 +1,3 @@
|
||||
import * as ESTree from 'estree';
|
||||
|
||||
export type TReplaceableIdentifiersNames = Map<string, ESTree.Identifier[]>;
|
||||
Reference in New Issue
Block a user