Optimisations for identifers renaming

Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/146
This commit is contained in:
sanex3339
2017-12-13 00:26:23 +03:00
parent 4bde27915f
commit 292647b519
16 changed files with 219 additions and 91 deletions
+2 -1
View File
@@ -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',
+1 -1
View File
@@ -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;
};
+1 -1
View File
@@ -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;
@@ -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[]>;