Files
javascript-obfuscator-javas…/src/generators/identifier-names-generators/MangledIdentifierNamesGenerator.ts
T

121 lines
4.0 KiB
TypeScript

import { inject, injectable } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import { IOptions } from '../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
import { AbstractIdentifierNamesGenerator } from './AbstractIdentifierNamesGenerator';
@injectable()
export class MangledIdentifierNamesGenerator extends AbstractIdentifierNamesGenerator {
/**
* @type {string}
*/
private static initMangledNameCharacter: string = '9';
/**
* @type {string[]}
*/
private static nameSequence: string[] = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.split('');
/**
* Reserved JS words with length of 2-4 symbols that can be possible generated with this replacer
*
* @type {string[]}
*/
private static reservedNames: string[] = [
'byte', 'case', 'char', 'do', 'else', 'enum', 'eval', 'for', 'goto',
'if', 'in', 'int', 'let', 'long', 'new', 'null', 'this', 'true', 'try',
'var', 'void', 'with'
];
/**
* @type {string}
*/
private previousMangledName: string = MangledIdentifierNamesGenerator.initMangledNameCharacter;
/**
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
*/
constructor (
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
super(randomGenerator, options);
}
/**
* @param {string} previousMangledName
* @returns {string}
*/
private static generateNewMangledName (previousMangledName: string): string {
const generateNewMangledName: (name: string) => string = (name: string): string => {
const nameSequence: string[] = MangledIdentifierNamesGenerator.nameSequence;
const zeroSequenceCache: string[] = [];
const nameLength: number = name.length;
const zeroSequence: (num: number) => string = (num: number): string => {
let result: string = zeroSequenceCache[num];
if (result !== undefined) {
return result;
}
result = '0'.repeat(num);
zeroSequenceCache[num] = result;
return result;
};
let index: number = nameLength - 1;
do {
const character: string = name.charAt(index);
const indexInSequence: number = nameSequence.indexOf(character);
const lastNameSequenceIndex: number = nameSequence.length - 1;
if (indexInSequence !== lastNameSequenceIndex) {
const previousNamePart: string = name.substring(0, index);
const nextCharacter: string = nameSequence[indexInSequence + 1];
const zeroSequenceCharacters: string = zeroSequence(nameLength - (index + 1));
return previousNamePart + nextCharacter + zeroSequenceCharacters;
}
--index;
} while (index >= 0);
return `a${zeroSequence(nameLength)}`;
};
let newMangledName: string = generateNewMangledName(previousMangledName);
if (!MangledIdentifierNamesGenerator.validateMangledName(newMangledName)) {
newMangledName = MangledIdentifierNamesGenerator.generateNewMangledName(newMangledName);
}
return newMangledName;
}
/**
* @param {string} mangledName
* @returns {boolean}
*/
private static validateMangledName (mangledName: string): boolean {
return !MangledIdentifierNamesGenerator.reservedNames.includes(mangledName);
}
/**
* @param {number} length
* @returns {string}
*/
public generate (length: number): string {
const newName: string = MangledIdentifierNamesGenerator.generateNewMangledName(this.previousMangledName);
this.previousMangledName = newName;
return newName;
}
}