Merge pull request #180 from javascript-obfuscator/identifirs-prefix

`identifiersPrefix` option
This commit is contained in:
Timofey Kachalov
2018-01-24 17:55:31 +03:00
committed by GitHub
44 changed files with 637 additions and 175 deletions
+1
View File
@@ -2,6 +2,7 @@ Change Log
===
v0.14.0
---
* **New option:** `identifiersPrefix` sets prefix for all generated identifiers.
* **New option:** `transformObjectKeys` enables object keys transformation and obfuscation.
* **New feature:** `eval` expressions obfuscation.
* **Breaking change:** Now CLI obfuscating directory recursively. Fixed https://github.com/javascript-obfuscator/javascript-obfuscator/issues/157
+9
View File
@@ -277,6 +277,7 @@ Following options are available for the JS Obfuscator:
disableConsoleOutput: false,
domainLock: [],
identifierNamesGenerator: 'hexadecimal',
identifiersPrefix: '',
log: false,
renameGlobals: false,
reservedNames: [],
@@ -314,6 +315,7 @@ Following options are available for the JS Obfuscator:
--disable-console-output <boolean>
--domain-lock '<list>' (comma separated)
--identifier-names-generator <string> [hexadecimal, mangled]
--identifiers-prefix <string>
--log <boolean>
--rename-globals <boolean>
--reserved-names '<list>' (comma separated)
@@ -570,6 +572,13 @@ Available values:
* `hexadecimal`: identifier names like `_0xabc123`
* `mangled`: short identifier names like `a`, `b`, `c`
### `identifiersPrefix`
Type: `string` Default: `''`
Sets prefix for all generated identifiers.
Use this option when you want to obfuscate multiple files. This option helps to avoid conflicts between identifiers of these files. Prefix should be different for every file.
### `log`
Type: `boolean` Default: `false`
+1 -1
View File
File diff suppressed because one or more lines are too long
+11 -11
View File
@@ -1,6 +1,6 @@
{
"name": "javascript-obfuscator",
"version": "0.14.0-beta.2",
"version": "0.14.0-beta.3",
"description": "JavaScript obfuscator",
"keywords": [
"obfuscator",
@@ -21,9 +21,9 @@
"dependencies": {
"chalk": "2.3.0",
"chance": "1.0.13",
"class-validator": "0.7.3",
"class-validator": "0.8.1",
"commander": "2.13.0",
"escodegen-wallaby": "1.6.16",
"escodegen-wallaby": "1.6.17",
"esprima": "4.0.0",
"estraverse": "4.2.0",
"inversify": "4.9.0",
@@ -32,13 +32,13 @@
"mkdirp": "0.5.1",
"opencollective": "1.0.3",
"pjson": "1.0.9",
"reflect-metadata": "0.1.10",
"source-map-support": "0.5.0",
"reflect-metadata": "0.1.12",
"source-map-support": "0.5.2",
"string-template": "1.0.0",
"tslib": "1.8.1"
"tslib": "1.9.0"
},
"devDependencies": {
"@types/chai": "4.1.0",
"@types/chai": "4.1.2",
"@types/chance": "0.7.36",
"@types/escodegen": "0.0.6",
"@types/esprima": "4.0.1",
@@ -46,7 +46,7 @@
"@types/estree": "0.0.38",
"@types/md5": "2.1.32",
"@types/mkdirp": "0.5.2",
"@types/mocha": "2.2.46",
"@types/mocha": "2.2.47",
"@types/node": "9.3.0",
"@types/rimraf": "2.0.2",
"@types/sinon": "4.1.3",
@@ -60,11 +60,11 @@
"chai": "4.1.2",
"coveralls": "3.0.0",
"istanbul": "1.1.0-alpha.1",
"mocha": "4.1.0",
"mocha": "5.0.0",
"pre-commit": "1.2.2",
"rimraf": "2.6.2",
"sinon": "4.1.5",
"threads": "0.10.0",
"sinon": "4.2.1",
"threads": "0.10.1",
"ts-node": "4.1.0",
"tslint": "5.9.1",
"tslint-eslint-rules": "4.1.1",
+31 -6
View File
@@ -44,6 +44,11 @@ export class JavaScriptObfuscatorCLI implements IInitializable {
*/
public static obfuscatedFilePrefix: string = '-obfuscated';
/**
* @type {string}
*/
private static readonly baseIdentifiersPrefix: string = 'a';
/**
* @type {string[]}
*/
@@ -244,6 +249,10 @@ export class JavaScriptObfuscatorCLI implements IInitializable {
'--identifier-names-generator <string> [hexadecimal, mangled]', 'Sets identifier names generator (Default: hexadecimal)',
IdentifierNamesGeneratorSanitizer
)
.option(
'--identifiers-prefix <string>',
'Sets prefix for all generated identifiers.'
)
.option(
'--log <boolean>', 'Enables logging of the information to the console',
BooleanSanitizer
@@ -295,7 +304,7 @@ export class JavaScriptObfuscatorCLI implements IInitializable {
BooleanSanitizer
)
.option(
'--string-array-encoding <boolean|string> [true, false, base64, rc4]',
'--string-array-encoding <string|boolean> [true, false, base64, rc4]',
'Encodes all strings in strings array using base64 or rc4 (this option can slow down your code speed',
StringArrayEncodingSanitizer
)
@@ -343,14 +352,14 @@ export class JavaScriptObfuscatorCLI implements IInitializable {
if (!Array.isArray(sourceCodeData)) {
const outputCodePath: string = outputPath || CLIUtils.getOutputCodePath(this.inputPath);
this.processSourceCode(sourceCodeData, outputCodePath);
this.processSourceCode(sourceCodeData, outputCodePath, null);
} else {
sourceCodeData.forEach(({ filePath, content }: IFileData) => {
sourceCodeData.forEach(({ filePath, content }: IFileData, index: number) => {
const outputCodePath: string = outputPath
? path.join(outputPath, filePath)
: CLIUtils.getOutputCodePath(filePath);
this.processSourceCode(content, outputCodePath);
this.processSourceCode(content, outputCodePath, index);
});
}
}
@@ -358,9 +367,25 @@ export class JavaScriptObfuscatorCLI implements IInitializable {
/**
* @param {string} sourceCode
* @param {string} outputCodePath
* @param {number | null} sourceCodeIndex
*/
private processSourceCode (sourceCode: string, outputCodePath: string): void {
const options: TInputOptions = this.buildOptions();
private processSourceCode (
sourceCode: string,
outputCodePath: string,
sourceCodeIndex: number | null
): void {
let options: TInputOptions = this.buildOptions();
if (sourceCodeIndex !== null) {
const baseIdentifiersPrefix: string = this.inputCLIOptions.identifiersPrefix
|| JavaScriptObfuscatorCLI.baseIdentifiersPrefix;
const identifiersPrefix: string = `${baseIdentifiersPrefix}${sourceCodeIndex}`;
options = {
...options,
identifiersPrefix
};
}
if (options.sourceMap) {
JavaScriptObfuscatorCLI.processSourceCodeWithSourceMap(sourceCode, outputCodePath, options);
+4 -4
View File
@@ -9,6 +9,7 @@ import { finalizingTransformersModule } from './modules/node-transformers/Finali
import { generatorsModule } from './modules/generators/GeneratorsModule';
import { nodeTransformersModule } from './modules/node-transformers/NodeTransformersModule';
import { obfuscatingTransformersModule } from './modules/node-transformers/ObfuscatingTransformersModule';
import { optionsModule } from './modules/options/OptionsModule';
import { preparingTransformersModule } from './modules/node-transformers/PreparingTransformersModule';
import { storagesModule } from './modules/storages/StoragesModule';
import { utilsModule } from './modules/utils/UtilsModule';
@@ -20,7 +21,6 @@ import { IJavaScriptObfuscator } from '../interfaces/IJavaScriptObfsucator';
import { ILogger } from '../interfaces/logger/ILogger';
import { IObfuscationEventEmitter } from '../interfaces/event-emitters/IObfuscationEventEmitter';
import { IObfuscationResult } from '../interfaces/IObfuscationResult';
import { IOptions } from '../interfaces/options/IOptions';
import { ISourceCode } from '../interfaces/ISourceCode';
import { ISourceMapCorrector } from '../interfaces/source-map/ISourceMapCorrector';
import { ITransformersRunner } from '../interfaces/node-transformers/ITransformersRunner';
@@ -29,7 +29,6 @@ import { JavaScriptObfuscator } from '../JavaScriptObfuscator';
import { Logger } from '../logger/Logger';
import { ObfuscationEventEmitter } from '../event-emitters/ObfuscationEventEmitter';
import { ObfuscationResult } from '../ObfuscationResult';
import { Options } from "../options/Options";
import { SourceCode } from '../SourceCode';
import { SourceMapCorrector } from '../source-map/SourceMapCorrector';
import { TransformersRunner } from '../node-transformers/TransformersRunner';
@@ -147,8 +146,8 @@ export class InversifyContainerFacade implements IInversifyContainerFacade {
.inSingletonScope();
this.container
.bind<IOptions>(ServiceIdentifiers.IOptions)
.toDynamicValue(() => new Options(options))
.bind<TInputOptions>(ServiceIdentifiers.TInputOptions)
.toDynamicValue(() => options)
.inSingletonScope();
this.container
@@ -203,6 +202,7 @@ export class InversifyContainerFacade implements IInversifyContainerFacade {
this.container.load(generatorsModule);
this.container.load(nodeTransformersModule);
this.container.load(obfuscatingTransformersModule);
this.container.load(optionsModule);
this.container.load(preparingTransformersModule);
this.container.load(storagesModule);
this.container.load(utilsModule);
+2
View File
@@ -28,6 +28,7 @@ export enum ServiceIdentifiers {
IObfuscationEventEmitter = 'IObfuscationEventEmitter',
IObfuscationResult = 'IObfuscationResult',
IOptions = 'IOptions',
IOptionsNormalizer = 'IOptionsNormalizer',
IObfuscatingReplacer = 'IObfuscatingReplacer',
IRandomGenerator = 'IRandomGenerator',
ISourceCode = 'ISourceCode',
@@ -37,5 +38,6 @@ export enum ServiceIdentifiers {
Newable__ICustomNode = 'Newable<ICustomNode>',
Newable__TControlFlowStorage = 'Newable<TControlFlowStorage>',
TCustomNodeGroupStorage = 'TCustomNodeGroupStorage',
TInputOptions = 'TInputOptions',
TStringArrayStorage = 'TStringArrayStorage'
}
@@ -0,0 +1,18 @@
import { ContainerModule, interfaces } from 'inversify';
import { ServiceIdentifiers } from '../../ServiceIdentifiers';
import { IOptions } from '../../../interfaces/options/IOptions';
import { IOptionsNormalizer } from '../../../interfaces/options/IOptionsNormalizer';
import { Options } from '../../../options/Options';
import { OptionsNormalizer } from '../../../options/OptionsNormalizer';
export const optionsModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
bind<IOptions>(ServiceIdentifiers.IOptions)
.to(Options)
.inSingletonScope();
bind<IOptionsNormalizer>(ServiceIdentifiers.IOptionsNormalizer)
.to(OptionsNormalizer)
.inSingletonScope();
});
@@ -64,7 +64,7 @@ export class ConsoleOutputDisableExpressionNode extends AbstractCustomNode {
: GlobalVariableNoEvalTemplate();
return format(ConsoleOutputDisableExpressionTemplate(), {
consoleLogDisableFunctionName: this.identifierNamesGenerator.generate(6),
consoleLogDisableFunctionName: this.identifierNamesGenerator.generate(),
globalVariableTemplate,
singleNodeCallControllerFunctionName: this.callsControllerFunctionName
});
@@ -92,7 +92,7 @@ export class ConsoleOutputCustomNodeGroup extends AbstractCustomNodeGroup {
return;
}
const callsControllerFunctionName: string = this.identifierNamesGenerator.generate(6);
const callsControllerFunctionName: string = this.identifierNamesGenerator.generate();
const consoleOutputDisableExpressionNode: ICustomNode = this.customNodeFactory(CustomNode.ConsoleOutputDisableExpressionNode);
const nodeCallsControllerFunctionNode: ICustomNode = this.customNodeFactory(CustomNode.NodeCallsControllerFunctionNode);
@@ -105,8 +105,8 @@ export class DebugProtectionCustomNodeGroup extends AbstractCustomNodeGroup {
return;
}
const debugProtectionFunctionName: string = this.identifierNamesGenerator.generate(6);
const callsControllerFunctionName: string = this.identifierNamesGenerator.generate(6);
const debugProtectionFunctionName: string = this.identifierNamesGenerator.generate();
const callsControllerFunctionName: string = this.identifierNamesGenerator.generate();
const debugProtectionFunctionNode: ICustomNode = this.customNodeFactory(CustomNode.DebugProtectionFunctionNode);
const debugProtectionFunctionCallNode: ICustomNode = this.customNodeFactory(CustomNode.DebugProtectionFunctionCallNode);
@@ -79,7 +79,7 @@ export class DomainLockNode extends AbstractCustomNode {
: GlobalVariableNoEvalTemplate();
return format(DomainLockNodeTemplate(), {
domainLockFunctionName: this.identifierNamesGenerator.generate(6),
domainLockFunctionName: this.identifierNamesGenerator.generate(),
diff: diff,
domains: hiddenDomainsString,
globalVariableTemplate,
@@ -92,7 +92,7 @@ export class DomainLockCustomNodeGroup extends AbstractCustomNodeGroup {
return;
}
const callsControllerFunctionName: string = this.identifierNamesGenerator.generate(6);
const callsControllerFunctionName: string = this.identifierNamesGenerator.generate();
const domainLockNode: ICustomNode = this.customNodeFactory(CustomNode.DomainLockNode);
const nodeCallsControllerFunctionNode: ICustomNode = this.customNodeFactory(CustomNode.NodeCallsControllerFunctionNode);
@@ -71,7 +71,7 @@ export class SelfDefendingUnicodeNode extends AbstractCustomNode {
protected getTemplate (): string {
return JavaScriptObfuscator.obfuscate(
format(SelfDefendingTemplate(this.escapeSequenceEncoder), {
selfDefendingFunctionName: this.identifierNamesGenerator.generate(6),
selfDefendingFunctionName: this.identifierNamesGenerator.generate(),
singleNodeCallControllerFunctionName: this.callsControllerFunctionName
}),
{
@@ -92,7 +92,7 @@ export class SelfDefendingCustomNodeGroup extends AbstractCustomNodeGroup {
return;
}
const callsControllerFunctionName: string = this.identifierNamesGenerator.generate(6);
const callsControllerFunctionName: string = this.identifierNamesGenerator.generate();
const selfDefendingUnicodeNode: ICustomNode = this.customNodeFactory(CustomNode.SelfDefendingUnicodeNode);
const nodeCallsControllerFunctionNode: ICustomNode = this.customNodeFactory(CustomNode.NodeCallsControllerFunctionNode);
@@ -82,8 +82,8 @@ export class StringArrayRotateFunctionNode extends AbstractCustomNode {
* @returns {string}
*/
protected getTemplate (): string {
const timesName: string = this.identifierNamesGenerator.generate(6);
const whileFunctionName: string = this.identifierNamesGenerator.generate(6);
const timesName: string = this.identifierNamesGenerator.generate();
const whileFunctionName: string = this.identifierNamesGenerator.generate();
let code: string = '';
@@ -30,8 +30,12 @@ export abstract class AbstractIdentifierNamesGenerator implements IIdentifierNam
}
/**
* @param {number} length
* @returns {string}
*/
public abstract generate (length: number): string;
public abstract generate (): string;
/**
* @returns {string}
*/
public abstract generateWithPrefix (): string;
}
@@ -9,6 +9,11 @@ import { Utils } from '../../utils/Utils';
@injectable()
export class HexadecimalIdentifierNamesGenerator extends AbstractIdentifierNamesGenerator {
/**
* @type {number}
*/
private static baseIdentifierNameLength: number = 6;
/**
* @type {Set<string>}
*/
@@ -26,23 +31,31 @@ export class HexadecimalIdentifierNamesGenerator extends AbstractIdentifierNames
}
/**
* @param {number} length
* @returns {string}
*/
public generate (length: number): string {
const prefix: string = `_${Utils.hexadecimalPrefix}`;
public generate (): string {
const rangeMinInteger: number = 10000;
const rangeMaxInteger: number = 99999999;
const randomInteger: number = this.randomGenerator.getRandomInteger(rangeMinInteger, rangeMaxInteger);
const hexadecimalNumber: string = Utils.decToHex(randomInteger);
const randomVariableName: string = `${prefix}${hexadecimalNumber.substr(0, length)}`;
const baseIdentifierName: string = hexadecimalNumber.substr(0, HexadecimalIdentifierNamesGenerator.baseIdentifierNameLength);
const identifierName: string = `_${Utils.hexadecimalPrefix}${baseIdentifierName}`;
if (this.randomVariableNameSet.has(randomVariableName)) {
return this.generate(length);
if (this.randomVariableNameSet.has(identifierName)) {
return this.generate();
}
this.randomVariableNameSet.add(randomVariableName);
this.randomVariableNameSet.add(identifierName);
return randomVariableName;
return identifierName;
}
/**
* @returns {string}
*/
public generateWithPrefix (): string {
const identifierName: string = this.generate();
return `${this.options.identifiersPrefix}${identifierName}`.replace('__', '_');
}
}
@@ -98,14 +98,25 @@ export class MangledIdentifierNamesGenerator extends AbstractIdentifierNamesGene
}
/**
* @param {number} length
* @returns {string}
*/
public generate (length: number): string {
const newName: string = MangledIdentifierNamesGenerator.generateNewMangledName(this.previousMangledName);
public generate (): string {
const identifierName: string = MangledIdentifierNamesGenerator.generateNewMangledName(this.previousMangledName);
this.previousMangledName = newName;
this.previousMangledName = identifierName;
return newName;
return identifierName;
}
/**
* @returns {string}
*/
public generateWithPrefix (): string {
const prefix: string = this.options.identifiersPrefix ?
`${this.options.identifiersPrefix}_`
: '';
const identifierName: string = this.generate();
return `${prefix}${identifierName}`;
}
}
@@ -1,7 +1,11 @@
export interface IIdentifierNamesGenerator {
/**
* @param {number} length
* @returns {string}
*/
generate (length: number): string;
generate (): string;
/**
* @returns {string}
*/
generateWithPrefix (): string;
}
@@ -4,8 +4,14 @@ import { IObfuscatingReplacer } from './IObfuscatingReplacer';
export interface IIdentifierObfuscatingReplacer extends IObfuscatingReplacer <ESTree.Identifier> {
/**
* @param nodeValue
* @param {string} nodeValue
* @param {number} nodeIdentifier
*/
storeNames (nodeValue: any, nodeIdentifier: number): void;
storeGlobalName (nodeValue: string, nodeIdentifier: number): void;
/**
* @param {string} nodeValue
* @param {number} nodeIdentifier
*/
storeLocalName (nodeValue: string, nodeIdentifier: number): void;
}
+1
View File
@@ -15,6 +15,7 @@ export interface IOptions {
readonly disableConsoleOutput: boolean;
readonly domainLock: string[];
readonly identifierNamesGenerator: IdentifierNamesGenerator;
readonly identifiersPrefix: string;
readonly log: boolean;
readonly renameGlobals: boolean;
readonly reservedNames: string[];
+9
View File
@@ -0,0 +1,9 @@
import { IOptions } from './IOptions';
export interface IOptionsNormalizer {
/**
* @param {IOptions} options
* @returns {IOptions}
*/
normalize (options: IOptions): IOptions;
}
@@ -90,7 +90,7 @@ export class CatchClauseTransformer extends AbstractNodeTransformer {
*/
private storeCatchClauseParam (catchClauseNode: ESTree.CatchClause, nodeIdentifier: number): void {
if (NodeGuards.isIdentifierNode(catchClauseNode.param)) {
this.identifierObfuscatingReplacer.storeNames(catchClauseNode.param.name, nodeIdentifier);
this.identifierObfuscatingReplacer.storeLocalName(catchClauseNode.param.name, nodeIdentifier);
}
}
@@ -86,14 +86,14 @@ export class ClassDeclarationTransformer extends AbstractNodeTransformer {
*/
public transformNode (classDeclarationNode: ESTree.ClassDeclaration, parentNode: ESTree.Node): ESTree.Node {
const nodeIdentifier: number = this.nodeIdentifier++;
const blockScopeNode: TNodeWithBlockScope = NodeUtils
.getBlockScopesOfNode(classDeclarationNode)[0];
const blockScopeNode: TNodeWithBlockScope = NodeUtils.getBlockScopesOfNode(classDeclarationNode)[0];
const isGlobalDeclaration: boolean = blockScopeNode.type === NodeType.Program;
if (!this.options.renameGlobals && blockScopeNode.type === NodeType.Program) {
if (!this.options.renameGlobals && isGlobalDeclaration) {
return classDeclarationNode;
}
this.storeClassName(classDeclarationNode, nodeIdentifier);
this.storeClassName(classDeclarationNode, isGlobalDeclaration, nodeIdentifier);
// check for cached identifiers for current scope node. If exist - loop through them.
if (this.replaceableIdentifiers.has(blockScopeNode)) {
@@ -107,10 +107,19 @@ export class ClassDeclarationTransformer extends AbstractNodeTransformer {
/**
* @param {ClassDeclaration} classDeclarationNode
* @param {boolean} isGlobalDeclaration
* @param {number} nodeIdentifier
*/
private storeClassName (classDeclarationNode: ESTree.ClassDeclaration, nodeIdentifier: number): void {
this.identifierObfuscatingReplacer.storeNames(classDeclarationNode.id.name, nodeIdentifier);
private storeClassName (
classDeclarationNode: ESTree.ClassDeclaration,
isGlobalDeclaration: boolean,
nodeIdentifier: number
): void {
if (isGlobalDeclaration) {
this.identifierObfuscatingReplacer.storeGlobalName(classDeclarationNode.id.name, nodeIdentifier);
} else {
this.identifierObfuscatingReplacer.storeLocalName(classDeclarationNode.id.name, nodeIdentifier);
}
}
/**
@@ -88,14 +88,14 @@ export class FunctionDeclarationTransformer extends AbstractNodeTransformer {
*/
public transformNode (functionDeclarationNode: ESTree.FunctionDeclaration, parentNode: ESTree.Node): ESTree.Node {
const nodeIdentifier: number = this.nodeIdentifier++;
const blockScopeNode: TNodeWithBlockScope = NodeUtils
.getBlockScopesOfNode(functionDeclarationNode)[0];
const blockScopeNode: TNodeWithBlockScope = NodeUtils.getBlockScopesOfNode(functionDeclarationNode)[0];
const isGlobalDeclaration: boolean = blockScopeNode.type === NodeType.Program;
if (!this.options.renameGlobals && blockScopeNode.type === NodeType.Program) {
if (!this.options.renameGlobals && isGlobalDeclaration) {
return functionDeclarationNode;
}
this.storeFunctionName(functionDeclarationNode, nodeIdentifier);
this.storeFunctionName(functionDeclarationNode, isGlobalDeclaration, nodeIdentifier);
// check for cached identifiers for current scope node. If exist - loop through them.
if (this.replaceableIdentifiers.has(blockScopeNode)) {
@@ -109,10 +109,19 @@ export class FunctionDeclarationTransformer extends AbstractNodeTransformer {
/**
* @param {FunctionDeclaration} functionDeclarationNode
* @param {boolean} isGlobalDeclaration
* @param {number} nodeIdentifier
*/
private storeFunctionName (functionDeclarationNode: ESTree.FunctionDeclaration, nodeIdentifier: number): void {
this.identifierObfuscatingReplacer.storeNames(functionDeclarationNode.id.name, nodeIdentifier);
private storeFunctionName (
functionDeclarationNode: ESTree.FunctionDeclaration,
isGlobalDeclaration: boolean,
nodeIdentifier: number
): void {
if (isGlobalDeclaration) {
this.identifierObfuscatingReplacer.storeGlobalName(functionDeclarationNode.id.name, nodeIdentifier);
} else {
this.identifierObfuscatingReplacer.storeLocalName(functionDeclarationNode.id.name, nodeIdentifier);
}
}
/**
@@ -104,13 +104,13 @@ export class FunctionTransformer extends AbstractNodeTransformer {
estraverse.traverse(paramsNode, {
enter: (node: ESTree.Node): any => {
if (NodeGuards.isAssignmentPatternNode(node) && NodeGuards.isIdentifierNode(node.left)) {
this.identifierObfuscatingReplacer.storeNames(node.left.name, nodeIdentifier);
this.identifierObfuscatingReplacer.storeLocalName(node.left.name, nodeIdentifier);
return estraverse.VisitorOption.Skip;
}
if (NodeGuards.isIdentifierNode(node)) {
this.identifierObfuscatingReplacer.storeNames(node.name, nodeIdentifier);
this.identifierObfuscatingReplacer.storeLocalName(node.name, nodeIdentifier);
}
}
});
@@ -97,8 +97,7 @@ export class LabeledStatementTransformer extends AbstractNodeTransformer {
* @param {number} nodeIdentifier
*/
private storeLabeledStatementName (labeledStatementNode: ESTree.LabeledStatement, nodeIdentifier: number): void {
this.identifierObfuscatingReplacer
.storeNames(labeledStatementNode.label.name, nodeIdentifier);
this.identifierObfuscatingReplacer.storeLocalName(labeledStatementNode.label.name, nodeIdentifier);
}
/**
@@ -88,10 +88,10 @@ export class VariableDeclarationTransformer extends AbstractNodeTransformer {
* @returns {NodeGuards}
*/
public transformNode (variableDeclarationNode: ESTree.VariableDeclaration, parentNode: ESTree.Node): ESTree.Node {
const blockScopeNode: TNodeWithBlockScope = NodeUtils
.getBlockScopesOfNode(variableDeclarationNode)[0];
const blockScopeNode: TNodeWithBlockScope = NodeUtils.getBlockScopesOfNode(variableDeclarationNode)[0];
const isGlobalDeclaration: boolean = blockScopeNode.type === NodeType.Program;
if (!this.options.renameGlobals && blockScopeNode.type === NodeType.Program) {
if (!this.options.renameGlobals && isGlobalDeclaration) {
return variableDeclarationNode;
}
@@ -100,7 +100,7 @@ export class VariableDeclarationTransformer extends AbstractNodeTransformer {
? blockScopeNode
: parentNode;
this.storeVariableNames(variableDeclarationNode, nodeIdentifier);
this.storeVariableNames(variableDeclarationNode, isGlobalDeclaration, nodeIdentifier);
// check for cached identifiers for current scope node. If exist - loop through them.
if (this.replaceableIdentifiers.has(scopeNode)) {
@@ -114,11 +114,20 @@ export class VariableDeclarationTransformer extends AbstractNodeTransformer {
/**
* @param {VariableDeclaration} variableDeclarationNode
* @param {boolean} isGlobalDeclaration
* @param {number} nodeIdentifier
*/
private storeVariableNames (variableDeclarationNode: ESTree.VariableDeclaration, nodeIdentifier: number): void {
private storeVariableNames (
variableDeclarationNode: ESTree.VariableDeclaration,
isGlobalDeclaration: boolean,
nodeIdentifier: number
): void {
this.traverseDeclarationIdentifiers(variableDeclarationNode, (identifierNode: ESTree.Identifier) => {
this.identifierObfuscatingReplacer.storeNames(identifierNode.name, nodeIdentifier);
if (isGlobalDeclaration) {
this.identifierObfuscatingReplacer.storeGlobalName(identifierNode.name, nodeIdentifier);
} else {
this.identifierObfuscatingReplacer.storeLocalName(identifierNode.name, nodeIdentifier);
}
});
}
@@ -54,18 +54,37 @@ export class BaseIdentifierObfuscatingReplacer extends AbstractObfuscatingReplac
}
/**
* Store all `nodeIdentifier`'s as keys in given `namesMap` with random names as value.
* Reserved names will be ignored.
* Store `nodeName` of global identifiers as key in map with random name as value.
* Reserved name will be ignored.
*
* @param {string} nodeName
* @param {number} nodeIdentifier
*/
public storeNames (nodeName: string, nodeIdentifier: number): void {
public storeGlobalName (nodeName: string, nodeIdentifier: number): void {
if (this.isReservedName(nodeName)) {
return;
}
this.namesMap.set(`${nodeName}-${String(nodeIdentifier)}`, this.identifierNamesGenerator.generate(6));
const identifierName: string = this.identifierNamesGenerator.generateWithPrefix();
this.namesMap.set(`${nodeName}-${String(nodeIdentifier)}`, identifierName);
}
/**
* Store `nodeName` of local identifier as key in map with random name as value.
* Reserved name will be ignored.
*
* @param {string} nodeName
* @param {number} nodeIdentifier
*/
public storeLocalName (nodeName: string, nodeIdentifier: number): void {
if (this.isReservedName(nodeName)) {
return;
}
const identifierName: string = this.identifierNamesGenerator.generate();
this.namesMap.set(`${nodeName}-${String(nodeIdentifier)}`, identifierName);
}
/**
+16 -4
View File
@@ -1,4 +1,5 @@
import { injectable } from 'inversify';
import { inject, injectable } from 'inversify';
import { ServiceIdentifiers } from '../container/ServiceIdentifiers';
import {
ArrayUnique,
@@ -20,6 +21,7 @@ import { TInputOptions } from '../types/options/TInputOptions';
import { TStringArrayEncoding } from '../types/options/TStringArrayEncoding';
import { IOptions } from '../interfaces/options/IOptions';
import { IOptionsNormalizer } from '../interfaces/options/IOptionsNormalizer';
import { IdentifierNamesGenerator } from '../enums/generators/identifier-names-generators/IdentifierNamesGenerator';
import { ObfuscationTarget } from '../enums/ObfuscationTarget';
@@ -28,7 +30,6 @@ import { StringArrayEncoding } from '../enums/StringArrayEncoding';
import { DEFAULT_PRESET } from './presets/Default';
import { OptionsNormalizer } from './OptionsNormalizer';
import { ValidationErrorsFormatter } from './ValidationErrorsFormatter';
@injectable()
@@ -111,6 +112,12 @@ export class Options implements IOptions {
])
public readonly identifierNamesGenerator: IdentifierNamesGenerator;
/**
* @type {string}
*/
@IsString()
public readonly identifiersPrefix: string;
/**
* @type {boolean}
*/
@@ -164,6 +171,7 @@ export class Options implements IOptions {
@ValidateIf((options: IOptions) => Boolean(options.sourceMapBaseUrl))
@IsUrl({
require_protocol: true,
require_tld: false,
require_valid_protocol: true
})
public readonly sourceMapBaseUrl: string;
@@ -220,8 +228,12 @@ export class Options implements IOptions {
/**
* @param {TInputOptions} inputOptions
* @param {IOptionsNormalizer} optionsNormalizer
*/
constructor (inputOptions: TInputOptions) {
constructor (
@inject(ServiceIdentifiers.TInputOptions) inputOptions: TInputOptions,
@inject(ServiceIdentifiers.IOptionsNormalizer) optionsNormalizer: IOptionsNormalizer
) {
Object.assign(this, DEFAULT_PRESET, inputOptions);
const errors: ValidationError[] = validateSync(this, Options.validatorOptions);
@@ -230,6 +242,6 @@ export class Options implements IOptions {
throw new ReferenceError(`Validation failed. errors:\n${ValidationErrorsFormatter.format(errors)}`);
}
Object.assign(this, OptionsNormalizer.normalizeOptions(this));
Object.assign(this, optionsNormalizer.normalize(this));
}
}
+6 -2
View File
@@ -1,6 +1,9 @@
import { injectable } from 'inversify';
import { TOptionsNormalizerRule } from '../types/options/TOptionsNormalizerRule';
import { IOptions } from '../interfaces/options/IOptions';
import { IOptionsNormalizer } from '../interfaces/options/IOptionsNormalizer';
import { ControlFlowFlatteningThresholdRule } from './normalizer-rules/ControlFlowFlatteningThresholdRule';
import { DeadCodeInjectionRule } from './normalizer-rules/DeadCodeInjectionRule';
@@ -13,7 +16,8 @@ import { StringArrayRule } from './normalizer-rules/StringArrayRule';
import { StringArrayEncodingRule } from './normalizer-rules/StringArrayEncodingRule';
import { StringArrayThresholdRule } from './normalizer-rules/StringArrayThresholdRule';
export class OptionsNormalizer {
@injectable()
export class OptionsNormalizer implements IOptionsNormalizer {
/**
* @type {TOptionsNormalizerRule[]}
*/
@@ -34,7 +38,7 @@ export class OptionsNormalizer {
* @param {IOptions} options
* @returns {IOptions}
*/
public static normalizeOptions (options: IOptions): IOptions {
public normalize (options: IOptions): IOptions {
let normalizedOptions: IOptions = {
...options
};
+1
View File
@@ -16,6 +16,7 @@ export const DEFAULT_PRESET: TInputOptions = Object.freeze({
disableConsoleOutput: false,
domainLock: [],
identifierNamesGenerator: IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator,
identifiersPrefix: '',
log: false,
renameGlobals: false,
reservedNames: [],
+1
View File
@@ -15,6 +15,7 @@ export const NO_ADDITIONAL_NODES_PRESET: TInputOptions = Object.freeze({
disableConsoleOutput: false,
domainLock: [],
identifierNamesGenerator: IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator,
identifiersPrefix: '',
log: false,
renameGlobals: false,
reservedNames: [],
@@ -12,6 +12,11 @@ import { ArrayStorage } from '../ArrayStorage';
@injectable()
export class StringArrayStorage extends ArrayStorage <string> {
/**
* @type {number}
*/
private static readonly stringArrayNameLength: number = 7;
/**
* @type {IArrayUtils}
*/
@@ -45,8 +50,14 @@ export class StringArrayStorage extends ArrayStorage <string> {
public initialize (): void {
super.initialize();
const stringArrayName: string = this.identifierNamesGenerator.generate(4);
const stringArrayCallsWrapperName: string = this.identifierNamesGenerator.generate(4);
const baseStringArrayName: string = this.identifierNamesGenerator
.generate()
.slice(0, StringArrayStorage.stringArrayNameLength);
const baseStringArrayCallsWrapperName: string = this.identifierNamesGenerator
.generate()
.slice(0, StringArrayStorage.stringArrayNameLength);
const stringArrayName: string = `${this.options.identifiersPrefix}${baseStringArrayName}`;
const stringArrayCallsWrapperName: string = `${this.options.identifiersPrefix}${baseStringArrayCallsWrapperName}`;
this.storageId = `${stringArrayName}|${stringArrayCallsWrapperName}`;
}
+7 -6
View File
@@ -6,17 +6,18 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../src/options/presets/NoCustomNo
let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
`
var bar = 1;
var baz = 2;
(function(){
function foo () {
eval('var s = 1;');
}
foo();
var bark = bar + baz;
})();
`,
{
...NO_ADDITIONAL_NODES_PRESET,
compact: false
compact: false,
identifiersPrefix: 'foo',
identifierNamesGenerator: 'mangled',
renameGlobals: true
}
).getObfuscatedCode();
@@ -134,13 +134,18 @@ describe('JavaScriptObfuscatorCLI', function (): void {
const outputFileName1: string = 'foo-obfuscated.js';
const outputFileName2: string = 'bar-obfuscated.js';
const outputFileName3: string = 'baz-obfuscated.js';
const readFileEncoding: string = 'utf8';
const regExp1: RegExp = /^var *a1_0x(\w){4,6} *= *0x1;$/;
const regExp2: RegExp = /^var *a0_0x(\w){4,6} *= *0x2;$/;
let outputFixturesFilePath1: string,
outputFixturesFilePath2: string,
outputFixturesFilePath3: string,
isFileExist1: boolean,
isFileExist2: boolean,
isFileExist3: boolean;
isFileExist3: boolean,
fileContent1: string,
fileContent2: string;
before(() => {
outputFixturesFilePath1 = `${directoryPath}/${outputFileName1}`;
@@ -150,12 +155,17 @@ describe('JavaScriptObfuscatorCLI', function (): void {
JavaScriptObfuscator.runCLI([
'node',
'javascript-obfuscator',
directoryPath
directoryPath,
'--rename-globals',
'true'
]);
isFileExist1 = fs.existsSync(outputFixturesFilePath1);
isFileExist2 = fs.existsSync(outputFixturesFilePath2);
isFileExist3 = fs.existsSync(outputFixturesFilePath3);
fileContent1 = fs.readFileSync(outputFixturesFilePath1, readFileEncoding);
fileContent2 = fs.readFileSync(outputFixturesFilePath2, readFileEncoding);
});
it(`should create file \`${outputFileName1}\` with obfuscated code in \`${fixturesDirName}\` directory`, () => {
@@ -170,13 +180,80 @@ describe('JavaScriptObfuscatorCLI', function (): void {
assert.equal(isFileExist3, false);
});
it(`match #1: should create file with obfuscated code with prefixed identifier`, () => {
assert.match(fileContent1, regExp1);
});
it(`match #2: should create file with obfuscated code with prefixed identifier`, () => {
assert.match(fileContent2, regExp2);
});
after(() => {
rimraf.sync(outputFixturesFilePath1);
rimraf.sync(outputFixturesFilePath2);
});
});
describe('Variant #3: obfuscation of directory with `output` option', () => {
describe('Variant #3: obfuscation of directory with `identifiersPrefix` option value', () => {
const directoryPath: string = `${fixturesDirName}/directory-obfuscation`;
const identifiersPrefix: string = 'foo';
const outputFileName1: string = 'foo-obfuscated.js';
const outputFileName2: string = 'bar-obfuscated.js';
const readFileEncoding: string = 'utf8';
const regExp1: RegExp = /^var *foo1_0x(\w){4,6} *= *0x1;$/;
const regExp2: RegExp = /^var *foo0_0x(\w){4,6} *= *0x2;$/;
let outputFixturesFilePath1: string,
outputFixturesFilePath2: string,
isFileExist1: boolean,
isFileExist2: boolean,
fileContent1: string,
fileContent2: string;
before(() => {
outputFixturesFilePath1 = `${directoryPath}/${outputFileName1}`;
outputFixturesFilePath2 = `${directoryPath}/${outputFileName2}`;
JavaScriptObfuscator.runCLI([
'node',
'javascript-obfuscator',
directoryPath,
'--identifiers-prefix',
identifiersPrefix,
'--rename-globals',
'true'
]);
isFileExist1 = fs.existsSync(outputFixturesFilePath1);
isFileExist2 = fs.existsSync(outputFixturesFilePath2);
fileContent1 = fs.readFileSync(outputFixturesFilePath1, readFileEncoding);
fileContent2 = fs.readFileSync(outputFixturesFilePath2, readFileEncoding);
});
it(`should create file \`${outputFileName1}\` with obfuscated code in \`${fixturesDirName}\` directory`, () => {
assert.equal(isFileExist1, true);
});
it(`should create file \`${outputFileName2}\` with obfuscated code in \`${fixturesDirName}\` directory`, () => {
assert.equal(isFileExist2, true);
});
it(`match #1: should create file with obfuscated code with prefixed identifier`, () => {
assert.match(fileContent1, regExp1);
});
it(`match #2: should create file with obfuscated code with prefixed identifier`, () => {
assert.match(fileContent2, regExp2);
});
after(() => {
rimraf.sync(outputFixturesFilePath1);
rimraf.sync(outputFixturesFilePath2);
});
});
describe('Variant #4: obfuscation of directory with `output` option', () => {
const directoryPath: string = `${fixturesDirName}/directory-obfuscation`;
const outputDirectoryName: string = 'obfuscated';
const outputDirectoryPath: string = `${directoryPath}/${outputDirectoryName}`;
@@ -186,28 +186,108 @@ describe('JavaScriptObfuscator', () => {
});
describe('variable inside global scope', () => {
const regExp: RegExp = /^var *test *= *0x\d+;$/;
describe('variant #1: without `renameGlobals` option', () => {
const regExp: RegExp = /^var *test *= *0x\d+;$/;
let obfuscatedCode: string;
let obfuscatedCode: string;
beforeEach(() => {
const code: string = readFileAsString(__dirname + '/fixtures/simple-input-1.js');
const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET
}
);
beforeEach(() => {
const code: string = readFileAsString(__dirname + '/fixtures/simple-input-1.js');
const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET
}
);
obfuscatedCode = obfuscationResult.getObfuscatedCode();
obfuscatedCode = obfuscationResult.getObfuscatedCode();
});
it('should return correct obfuscated code', () => {
assert.match(obfuscatedCode, regExp);
});
});
it('should return correct obfuscated code', () => {
assert.match(obfuscatedCode, regExp);
describe('variant #2: with `renameGlobals` option', () => {
const regExp: RegExp = /^var *_0x(\w){4,6} *= *0x\d+;$/;
let obfuscatedCode: string;
beforeEach(() => {
const code: string = readFileAsString(__dirname + '/fixtures/simple-input-1.js');
const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
renameGlobals: true
}
);
obfuscatedCode = obfuscationResult.getObfuscatedCode();
});
it('should return correct obfuscated code', () => {
assert.match(obfuscatedCode, regExp);
});
});
describe('variant #3: with `renameGlobals` and `identifiersPrefix` options', () => {
const regExp: RegExp = /^var *foo_0x(\w){4,6} *= *0x\d+;$/;
let obfuscatedCode: string;
beforeEach(() => {
const code: string = readFileAsString(__dirname + '/fixtures/simple-input-1.js');
const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
renameGlobals: true,
identifiersPrefix: 'foo'
}
);
obfuscatedCode = obfuscationResult.getObfuscatedCode();
});
it('should return correct obfuscated code', () => {
assert.match(obfuscatedCode, regExp);
});
});
describe('variant #4: with `stringArray`, `renameGlobals` and `identifiersPrefix` options', () => {
const stringArrayRegExp: RegExp = /^var foo_0x(\w){4} *= *\['abc'\];/;
const stringArrayCallRegExp: RegExp = /var *foo_0x(\w){4,6} *= *foo_0x(\w){4}\('0x0'\);$/;
let obfuscatedCode: string;
beforeEach(() => {
const code: string = readFileAsString(__dirname + '/fixtures/simple-input-2.js');
const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
renameGlobals: true,
identifiersPrefix: 'foo',
stringArray: true,
stringArrayThreshold: 1
}
);
obfuscatedCode = obfuscationResult.getObfuscatedCode();
});
it('match #1: should return correct obfuscated code', () => {
assert.match(obfuscatedCode, stringArrayRegExp);
});
it('match #2: should return correct obfuscated code', () => {
assert.match(obfuscatedCode, stringArrayCallRegExp);
});
});
});
describe('variable inside global scope', () => {
describe('variable inside block scope', () => {
const regExp: RegExp = /^\(function *\(\) *\{ *var *_0x[\w]+ *= *0x\d+; *\}(\(\)\)|\)\(\));?$/;
let obfuscatedCode: string;
@@ -229,6 +309,47 @@ describe('JavaScriptObfuscator', () => {
});
});
describe('variables inside global and block scopes', () => {
describe('variant #1: with `renameGlobals` and `identifiersPrefix` options', () => {
const variableDeclaration1: RegExp = /var foo_0x(\w){4,6} *= *0x1;/;
const variableDeclaration2: RegExp = /var foo_0x(\w){4,6} *= *0x2;/;
const variableDeclaration3: RegExp = /var _0x(\w){4,6} *= *foo_0x(\w){4,6} *\+ *foo_0x(\w){4,6}/;
const functionDeclaration: RegExp = /var foo_0x(\w){4,6} *= *function/;
let obfuscatedCode: string;
beforeEach(() => {
const code: string = readFileAsString(__dirname + '/fixtures/identifiers-prefix.js');
const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
renameGlobals: true,
identifiersPrefix: 'foo'
}
);
obfuscatedCode = obfuscationResult.getObfuscatedCode();
});
it('match #1: should return correct obfuscated code', () => {
assert.match(obfuscatedCode, variableDeclaration1);
});
it('match #2: should return correct obfuscated code', () => {
assert.match(obfuscatedCode, variableDeclaration2);
});
it('match #3: should return correct obfuscated code', () => {
assert.match(obfuscatedCode, variableDeclaration3);
});
it('match #4: should return correct obfuscated code', () => {
assert.match(obfuscatedCode, functionDeclaration);
});
});
});
describe('latin literal variable value', () => {
const stringArrayLatinRegExp: RegExp = /^var _0x(\w){4} *= *\['abc'\];/;
const stringArrayCallRegExp: RegExp = /var *test *= *_0x(\w){4}\('0x0'\);$/;
@@ -0,0 +1,7 @@
var foo = 1;
var bar = 2;
var baz = function () {
var bark = foo + bar;
return bark;
};
@@ -1,28 +1,40 @@
import 'reflect-metadata';
import { ServiceIdentifiers } from '../../../src/container/ServiceIdentifiers';
import { assert } from 'chai';
import { TInputOptions } from '../../../src/types/options/TInputOptions';
import { IInversifyContainerFacade } from '../../../src/interfaces/container/IInversifyContainerFacade';
import { IOptions } from '../../../src/interfaces/options/IOptions';
import { IOptionsNormalizer } from '../../../src/interfaces/options/IOptionsNormalizer';
import { StringArrayEncoding } from '../../../src/enums/StringArrayEncoding';
import { DEFAULT_PRESET } from '../../../src/options/presets/Default';
import { Options } from '../../../src/options/Options';
import { OptionsNormalizer } from '../../../src/options/OptionsNormalizer';
import { InversifyContainerFacade } from '../../../src/container/InversifyContainerFacade';
/**
* @param optionsPreset
* @returns {IOptions}
*/
function getNormalizedOptions (optionsPreset: TInputOptions): TInputOptions {
const options: IOptions = new Options(optionsPreset);
const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade();
return OptionsNormalizer.normalizeOptions(options);
inversifyContainerFacade.load('', optionsPreset);
const options: IOptions = inversifyContainerFacade
.get<IOptions>(ServiceIdentifiers.IOptions);
const optionsNormalizer: IOptionsNormalizer = inversifyContainerFacade
.get<IOptionsNormalizer>(ServiceIdentifiers.IOptionsNormalizer);
return optionsNormalizer.normalize(options);
}
describe('OptionsNormalizer', () => {
describe('normalizeOptions (options: IObfuscatorOptions): IObfuscatorOptions', () => {
describe('normalize (options: IObfuscatorOptions): IObfuscatorOptions', () => {
let optionsPreset: TInputOptions,
expectedOptionsPreset: TInputOptions;
+1 -1
View File
@@ -24,7 +24,6 @@ import './unit-tests/node/node-guards/NodeGuards.spec';
import './unit-tests/node/node-utils/NodeUtils.spec';
import './unit-tests/node-transformers/preparing-transformers/ObfuscatingGuardsTransformer.spec';
import './unit-tests/obfuscation-result/ObfuscationResult.spec';
import './unit-tests/options/OptionsNormalizer.spec';
import './unit-tests/options/ValidationErrorsFormatter.spec';
import './unit-tests/source-map/SourceMapCorrector.spec';
import './unit-tests/storages/ArrayStorage.spec';
@@ -68,6 +67,7 @@ import './functional-tests/node-transformers/preparing-transformers/eval-call-ex
import './functional-tests/node-transformers/preparing-transformers/comments-transformer/CommentsTransformer.spec';
import './functional-tests/node-transformers/preparing-transformers/obfuscating-guards/black-list-obfuscating-guard/BlackListObfuscatingGuard.spec';
import './functional-tests/node-transformers/preparing-transformers/obfuscating-guards/conditional-comment-obfuscating-guard/ConditionalCommentObfuscatingGuard.spec';
import './functional-tests/options/OptionsNormalizer.spec';
import './functional-tests/templates/debug-protection-nodes/DebugProtectionFunctionCallTemplate.spec';
import './functional-tests/templates/domain-lock-nodes/DomainLockNodeTemplate.spec';
import './functional-tests/templates/GlobalVariableNoEvalTemplate.spec';
@@ -12,7 +12,7 @@ import { IdentifierNamesGenerator } from '../../../../src/enums/generators/ident
import { InversifyContainerFacade } from '../../../../src/container/InversifyContainerFacade';
describe('HexadecimalIdentifierNamesGenerator', () => {
describe('generate (length: number): string', () => {
describe('generate (): string', () => {
let identifierNamesGenerator: IIdentifierNamesGenerator,
hexadecimalIdentifierName: string,
regExp: RegExp;
@@ -24,29 +24,39 @@ describe('HexadecimalIdentifierNamesGenerator', () => {
identifierNamesGenerator = inversifyContainerFacade.getNamed<IIdentifierNamesGenerator>(
ServiceIdentifiers.IIdentifierNamesGenerator,
IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator
)
);
hexadecimalIdentifierName = identifierNamesGenerator.generate();
regExp = /^_0x(\w){4,6}$/;
});
describe('variant #1: hexadecimal name with length `4`', () => {
before(() => {
hexadecimalIdentifierName = identifierNamesGenerator.generate(4);
regExp = /^_0x(\w){4}$/;
it('should return hexadecimal name', () => {
assert.match(hexadecimalIdentifierName, regExp);
})
});
describe('generateWithPrefix (): string', () => {
const regExp: RegExp = /^foo_0x(\w){4,6}$/;
let identifierNamesGenerator: IIdentifierNamesGenerator,
hexadecimalIdentifierName: string;
before(() => {
const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade();
inversifyContainerFacade.load('', {
identifiersPrefix: 'foo'
});
identifierNamesGenerator = inversifyContainerFacade.getNamed<IIdentifierNamesGenerator>(
ServiceIdentifiers.IIdentifierNamesGenerator,
IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator
);
it('should return hexadecimal name', () => {
assert.match(hexadecimalIdentifierName, regExp);
})
hexadecimalIdentifierName = identifierNamesGenerator.generateWithPrefix();
});
describe('variant #2: hexadecimal name with length `6`', () => {
before(() => {
hexadecimalIdentifierName = identifierNamesGenerator.generate(6);
regExp = /^_0x(\w){4,6}$/;
});
it('should return hexadecimal name', () => {
assert.match(hexadecimalIdentifierName, regExp);
})
});
it('should return hexadecimal name with prefix', () => {
assert.match(hexadecimalIdentifierName, regExp);
})
});
});
@@ -12,7 +12,7 @@ import { IdentifierNamesGenerator } from '../../../../src/enums/generators/ident
import { InversifyContainerFacade } from '../../../../src/container/InversifyContainerFacade';
describe('MangledIdentifierNamesGenerator', () => {
describe('generate (length: number): string', () => {
describe('generate (): string', () => {
let identifierNamesGenerator: IIdentifierNamesGenerator,
mangledIdentifierName: string;
@@ -30,7 +30,7 @@ describe('MangledIdentifierNamesGenerator', () => {
const expectedMangledIdentifierName: string = 'a';
beforeEach(() => {
mangledIdentifierName = identifierNamesGenerator.generate(4);
mangledIdentifierName = identifierNamesGenerator.generate();
});
it('should return mangled name', () => {
@@ -44,7 +44,7 @@ describe('MangledIdentifierNamesGenerator', () => {
beforeEach(() => {
for (let i: number = 0; i <= expectedMangledIdentifierPosition; i++) {
mangledIdentifierName = identifierNamesGenerator.generate(6);
mangledIdentifierName = identifierNamesGenerator.generate();
}
});
@@ -59,7 +59,7 @@ describe('MangledIdentifierNamesGenerator', () => {
beforeEach(() => {
for (let i: number = 0; i <= expectedMangledIdentifierPosition; i++) {
mangledIdentifierName = identifierNamesGenerator.generate(6);
mangledIdentifierName = identifierNamesGenerator.generate();
}
});
@@ -74,7 +74,7 @@ describe('MangledIdentifierNamesGenerator', () => {
beforeEach(() => {
for (let i: number = 0; i <= expectedMangledIdentifierPosition; i++) {
mangledIdentifierName = identifierNamesGenerator.generate(6);
mangledIdentifierName = identifierNamesGenerator.generate();
}
});
@@ -89,7 +89,7 @@ describe('MangledIdentifierNamesGenerator', () => {
beforeEach(() => {
for (let i: number = 0; i <= expectedMangledIdentifierPosition; i++) {
mangledIdentifierName = identifierNamesGenerator.generate(6);
mangledIdentifierName = identifierNamesGenerator.generate();
}
});
@@ -109,7 +109,7 @@ describe('MangledIdentifierNamesGenerator', () => {
beforeEach(() => {
for (let i: number = 0; i <= expectedMangledIdentifierPosition2; i++) {
mangledIdentifierName = identifierNamesGenerator.generate(6);
mangledIdentifierName = identifierNamesGenerator.generate();
if (i === expectedMangledIdentifierPosition1) {
mangledIdentifierName1 = mangledIdentifierName;
@@ -128,4 +128,45 @@ describe('MangledIdentifierNamesGenerator', () => {
});
});
});
describe('generateWithPrefix (): string', () => {
let identifierNamesGenerator: IIdentifierNamesGenerator,
mangledIdentifierName: string;
before(() => {
const inversifyContainerFacade: IInversifyContainerFacade = new InversifyContainerFacade();
inversifyContainerFacade.load('', {
identifiersPrefix: 'foo'
});
identifierNamesGenerator = inversifyContainerFacade.getNamed<IIdentifierNamesGenerator>(
ServiceIdentifiers.IIdentifierNamesGenerator,
IdentifierNamesGenerator.MangledIdentifierNamesGenerator
);
});
describe('variant #1: initial mangled name', () => {
const expectedMangledIdentifierName: string = 'foo_a';
beforeEach(() => {
mangledIdentifierName = identifierNamesGenerator.generateWithPrefix();
});
it('should return mangled name with prefix', () => {
assert.equal(mangledIdentifierName, expectedMangledIdentifierName);
});
});
describe('variant #2: second mangled name', () => {
const expectedMangledIdentifierName: string = 'foo_b';
beforeEach(() => {
mangledIdentifierName = identifierNamesGenerator.generateWithPrefix();
});
it('should return mangled name with prefix', () => {
assert.equal(mangledIdentifierName, expectedMangledIdentifierName);
});
});
});
});
+50 -34
View File
@@ -2,9 +2,9 @@
# yarn lockfile v1
"@types/chai@4.1.0":
version "4.1.0"
resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.1.0.tgz#d9008fa4c06f6801f93396d121f0227cd4244ac6"
"@types/chai@4.1.2":
version "4.1.2"
resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.1.2.tgz#f1af664769cfb50af805431c407425ed619daa21"
"@types/chance@0.7.36":
version "0.7.36"
@@ -58,9 +58,9 @@
dependencies:
"@types/node" "*"
"@types/mocha@2.2.46":
version "2.2.46"
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.46.tgz#b04713f7759d1cf752effdaae7b3969e285ebc16"
"@types/mocha@2.2.47":
version "2.2.47"
resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.47.tgz#30bbd880834d4af0f609025f282a69b8d4458f06"
"@types/node@*":
version "8.0.53"
@@ -1016,11 +1016,11 @@ class-utils@^0.3.5:
lazy-cache "^2.0.2"
static-extend "^0.1.1"
class-validator@0.7.3:
version "0.7.3"
resolved "https://registry.yarnpkg.com/class-validator/-/class-validator-0.7.3.tgz#3c2821b8cf35fd8d5f4fcb8063bc57fb50049e7e"
class-validator@0.8.1:
version "0.8.1"
resolved "https://registry.yarnpkg.com/class-validator/-/class-validator-0.8.1.tgz#f5efd5c613927e3c2f68692e8f14d53a2644fb2f"
dependencies:
validator "^7.0.0"
validator "9.2.0"
cli-cursor@^2.1.0:
version "2.1.0"
@@ -1446,9 +1446,9 @@ escape-string-regexp@1.0.5, escape-string-regexp@^1.0.2, escape-string-regexp@^1
version "1.0.5"
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
escodegen-wallaby@1.6.16:
version "1.6.16"
resolved "https://registry.yarnpkg.com/escodegen-wallaby/-/escodegen-wallaby-1.6.16.tgz#f55b65d1a846d98584f1be18a2bf463f96280527"
escodegen-wallaby@1.6.17:
version "1.6.17"
resolved "https://registry.yarnpkg.com/escodegen-wallaby/-/escodegen-wallaby-1.6.17.tgz#3e1f334884d4214c94309cf734ec7cfa0b3d438d"
dependencies:
esprima "^2.7.1"
estraverse "^1.9.1"
@@ -2566,9 +2566,9 @@ mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.1, mkdirp@~0.5.0:
dependencies:
minimist "0.0.8"
mocha@4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/mocha/-/mocha-4.1.0.tgz#7d86cfbcf35cb829e2754c32e17355ec05338794"
mocha@5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/mocha/-/mocha-5.0.0.tgz#cccac988b0bc5477119cba0e43de7af6d6ad8f4e"
dependencies:
browser-stdout "1.3.0"
commander "2.11.0"
@@ -3107,9 +3107,9 @@ readdirp@^2.0.0:
readable-stream "^2.0.2"
set-immediate-shim "^1.0.1"
reflect-metadata@0.1.10:
version "0.1.10"
resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.10.tgz#b4f83704416acad89988c9b15635d47e03b9344a"
reflect-metadata@0.1.12:
version "0.1.12"
resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.12.tgz#311bf0c6b63cd782f228a81abe146a2bfa9c56f2"
regenerate@^1.2.1:
version "1.3.3"
@@ -3329,16 +3329,16 @@ signal-exit@^3.0.0, signal-exit@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
sinon@4.1.4:
version "4.1.4"
resolved "https://registry.yarnpkg.com/sinon/-/sinon-4.1.4.tgz#36bb237bae38ddf9cc92dcc1b16c51e7785bbc9c"
sinon@4.2.1:
version "4.2.1"
resolved "https://registry.yarnpkg.com/sinon/-/sinon-4.2.1.tgz#3664e90ea4bccec6ebde3c06e3da8179983371d9"
dependencies:
diff "^3.1.0"
formatio "1.2.0"
lodash.get "^4.4.2"
lolex "^2.2.0"
nise "^1.2.0"
supports-color "^4.4.0"
supports-color "^5.1.0"
type-detect "^4.0.5"
slash@^1.0.0:
@@ -3392,9 +3392,9 @@ source-map-resolve@^0.5.0:
source-map-url "^0.4.0"
urix "^0.1.0"
source-map-support@0.5.0, source-map-support@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.0.tgz#2018a7ad2bdf8faf2691e5fddab26bed5a2bacab"
source-map-support@0.5.2:
version "0.5.2"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.2.tgz#1a6297fd5b2e762b39688c7fc91233b60984f0a5"
dependencies:
source-map "^0.6.0"
@@ -3404,6 +3404,12 @@ source-map-support@^0.4.15:
dependencies:
source-map "^0.5.6"
source-map-support@^0.5.0:
version "0.5.0"
resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.0.tgz#2018a7ad2bdf8faf2691e5fddab26bed5a2bacab"
dependencies:
source-map "^0.6.0"
source-map-url@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
@@ -3576,12 +3582,18 @@ supports-color@^3.1.2:
dependencies:
has-flag "^1.0.0"
supports-color@^4.0.0, supports-color@^4.2.1, supports-color@^4.4.0:
supports-color@^4.0.0, supports-color@^4.2.1:
version "4.5.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-4.5.0.tgz#be7a0de484dec5c5cddf8b3d59125044912f635b"
dependencies:
has-flag "^2.0.0"
supports-color@^5.1.0:
version "5.1.0"
resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.1.0.tgz#058a021d1b619f7ddf3980d712ea3590ce7de3d5"
dependencies:
has-flag "^2.0.0"
tapable@^0.2.5, tapable@^0.2.7:
version "0.2.8"
resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.8.tgz#99372a5c999bf2df160afc0d74bed4f47948cd22"
@@ -3611,9 +3623,9 @@ text-encoding@^0.6.4:
version "0.6.4"
resolved "https://registry.yarnpkg.com/text-encoding/-/text-encoding-0.6.4.tgz#e399a982257a276dae428bb92845cb71bdc26d19"
threads@0.10.0:
version "0.10.0"
resolved "https://registry.yarnpkg.com/threads/-/threads-0.10.0.tgz#a6b0bc5d916fa75434b166c612769684b65fead5"
threads@0.10.1:
version "0.10.1"
resolved "https://registry.yarnpkg.com/threads/-/threads-0.10.1.tgz#637765dc434ab3373d3c14754c8f7ac6515d6815"
dependencies:
eventemitter3 "^2.0.2"
native-promise-only "^0.8.1"
@@ -3697,7 +3709,11 @@ tsconfig@^7.0.0:
strip-bom "^3.0.0"
strip-json-comments "^2.0.0"
tslib@1.8.1, tslib@^1.0.0, tslib@^1.7.1, tslib@^1.8.0:
tslib@1.9.0:
version "1.9.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.0.tgz#e37a86fda8cbbaf23a057f473c9f4dc64e5fc2e8"
tslib@^1.0.0, tslib@^1.7.1, tslib@^1.8.0:
version "1.8.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.8.1.tgz#6946af2d1d651a7b1863b531d6e5afa41aa44eac"
@@ -3879,9 +3895,9 @@ validate-npm-package-license@^3.0.1:
spdx-correct "~1.0.0"
spdx-expression-parse "~1.0.0"
validator@^7.0.0:
version "7.2.0"
resolved "https://registry.yarnpkg.com/validator/-/validator-7.2.0.tgz#a63dcbaba51d4350bf8df20988e0d5a54d711791"
validator@9.2.0:
version "9.2.0"
resolved "https://registry.yarnpkg.com/validator/-/validator-9.2.0.tgz#ad216eed5f37cac31a6fe00ceab1f6b88bded03e"
verror@1.10.0:
version "1.10.0"