mirror of
https://github.com/javascript-obfuscator/javascript-obfuscator
synced 2026-08-09 12:42:29 +00:00
Refactoring of StringArrayTransformer.ts: moved logic to StringArrayWrappersTransformer, StringArrayScopeCallsWrapperDataStorage and VisitedLexicalScopeNodesStackStorage
This commit is contained in:
Vendored
+7
-7
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
@@ -86,6 +86,7 @@ export class JavaScriptObfuscator implements IJavaScriptObfuscator {
|
||||
NodeTransformer.ParentificationTransformer,
|
||||
NodeTransformer.ScopeIdentifiersTransformer,
|
||||
NodeTransformer.SplitStringTransformer,
|
||||
NodeTransformer.StringArrayScopeCallsWrapperTransformer,
|
||||
NodeTransformer.StringArrayTransformer,
|
||||
NodeTransformer.TemplateLiteralTransformer,
|
||||
NodeTransformer.VariableDeclarationsMergeTransformer,
|
||||
|
||||
@@ -37,6 +37,7 @@ export enum ServiceIdentifiers {
|
||||
INodeGuard = 'INodeGuard',
|
||||
INodeTransformer = 'INodeTransformer',
|
||||
INodeTransformerNamesGroupsBuilder = 'INodeTransformerNamesGroupsBuilder',
|
||||
INodeTransformersRunner = 'INodeTransformersRunner',
|
||||
INumberNumericalExpressionAnalyzer = 'INumberNumericalExpressionAnalyzer',
|
||||
IObfuscationEventEmitter = 'IObfuscationEventEmitter',
|
||||
IObfuscatedCode = 'IObfuscatedCode',
|
||||
@@ -49,9 +50,10 @@ export enum ServiceIdentifiers {
|
||||
IScopeIdentifiersTraverser = 'IScopeIdentifiersTraverser',
|
||||
ISourceCode = 'ISourceCode',
|
||||
IScopeAnalyzer = 'IScopeAnalyzer',
|
||||
IStringArrayScopeCallsWrapperDataStorage = 'IStringArrayScopeCallsWrapperDataStorage',
|
||||
IStringArrayStorage = 'IStringArrayStorage',
|
||||
IStringArrayStorageAnalyzer = 'IStringArrayStorageAnalyzer',
|
||||
INodeTransformersRunner = 'INodeTransformersRunner',
|
||||
IVisitedLexicalScopeNodesStackStorage = 'IVisitedLexicalScopeNodesStackStorage',
|
||||
Newable__ICustomNode = 'Newable<ICustomNode>',
|
||||
Newable__TControlFlowStorage = 'Newable<TControlFlowStorage>',
|
||||
TCustomNodeGroupStorage = 'TCustomNodeGroupStorage',
|
||||
|
||||
@@ -5,10 +5,15 @@ import { INodeTransformer } from '../../../interfaces/node-transformers/INodeTra
|
||||
|
||||
import { NodeTransformer } from '../../../enums/node-transformers/NodeTransformer';
|
||||
|
||||
import { StringArrayScopeCallsWrapperTransformer } from '../../../node-transformers/string-array-transformers/StringArrayScopeCallsWrapperTransformer';
|
||||
import { StringArrayTransformer } from '../../../node-transformers/string-array-transformers/StringArrayTransformer';
|
||||
|
||||
export const stringArrayTransformersModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
|
||||
// string array transformers
|
||||
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
|
||||
.to(StringArrayScopeCallsWrapperTransformer)
|
||||
.whenTargetNamed(NodeTransformer.StringArrayScopeCallsWrapperTransformer);
|
||||
|
||||
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
|
||||
.to(StringArrayTransformer)
|
||||
.whenTargetNamed(NodeTransformer.StringArrayTransformer);
|
||||
|
||||
@@ -7,12 +7,16 @@ import { TCustomCodeHelperGroupStorage } from '../../../types/storages/TCustomCo
|
||||
import { ILiteralNodesCacheStorage } from '../../../interfaces/storages/string-array-transformers/ILiteralNodesCacheStorage';
|
||||
import { IOptions } from '../../../interfaces/options/IOptions';
|
||||
import { IRandomGenerator } from '../../../interfaces/utils/IRandomGenerator';
|
||||
import { IStringArrayScopeCallsWrapperDataStorage } from '../../../interfaces/storages/string-array-transformers/IStringArrayScopeCallsWrapperDataStorage';
|
||||
import { IStringArrayStorage } from '../../../interfaces/storages/string-array-transformers/IStringArrayStorage';
|
||||
import { IVisitedLexicalScopeNodesStackStorage } from '../../../interfaces/storages/string-array-transformers/IVisitedLexicalScopeNodesStackStorage';
|
||||
|
||||
import { ControlFlowStorage } from '../../../storages/custom-nodes/ControlFlowStorage';
|
||||
import { CustomCodeHelperGroupStorage } from '../../../storages/custom-code-helpers/CustomCodeHelperGroupStorage';
|
||||
import { LiteralNodesCacheStorage } from '../../../storages/string-array-transformers/LiteralNodesCacheStorage';
|
||||
import { StringArrayScopeCallsWrapperDataStorage } from '../../../storages/string-array-transformers/StringArrayScopeCallsWrapperDataStorage';
|
||||
import { StringArrayStorage } from '../../../storages/string-array-transformers/StringArrayStorage';
|
||||
import { VisitedLexicalScopeNodesStackStorage } from '../../../storages/string-array-transformers/VisitedLexicalScopeNodesStackStorage';
|
||||
|
||||
export const storagesModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
|
||||
// storages
|
||||
@@ -28,6 +32,14 @@ export const storagesModule: interfaces.ContainerModule = new ContainerModule((b
|
||||
.to(StringArrayStorage)
|
||||
.inSingletonScope();
|
||||
|
||||
bind<IStringArrayScopeCallsWrapperDataStorage>(ServiceIdentifiers.IStringArrayScopeCallsWrapperDataStorage)
|
||||
.to(StringArrayScopeCallsWrapperDataStorage)
|
||||
.inSingletonScope();
|
||||
|
||||
bind<IVisitedLexicalScopeNodesStackStorage>(ServiceIdentifiers.IVisitedLexicalScopeNodesStackStorage)
|
||||
.to(VisitedLexicalScopeNodesStackStorage)
|
||||
.inSingletonScope();
|
||||
|
||||
bind<interfaces.Newable<TControlFlowStorage>>(ServiceIdentifiers.Newable__TControlFlowStorage)
|
||||
.toConstructor(ControlFlowStorage);
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ export enum NodeTransformer {
|
||||
ScopeThroughIdentifiersTransformer = 'ScopeThroughIdentifiersTransformer',
|
||||
SplitStringTransformer = 'SplitStringTransformer',
|
||||
StringArrayTransformer = 'StringArrayTransformer',
|
||||
StringArrayScopeCallsWrapperTransformer = 'StringArrayScopeCallsWrapperTransformer',
|
||||
TemplateLiteralTransformer = 'TemplateLiteralTransformer',
|
||||
VariableDeclarationsMergeTransformer = 'VariableDeclarationsMergeTransformer',
|
||||
VariablePreserveTransformer = 'VariablePreserveTransformer'
|
||||
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import { TNodeWithLexicalScope } from '../../../types/node/TNodeWithLexicalScope';
|
||||
import { TStringArrayScopeCallsWrapperDataByEncoding } from '../../../types/node-transformers/string-array-transformers/TStringArrayScopeCallsWrapperDataByEncoding';
|
||||
|
||||
import { IMapStorage } from '../IMapStorage';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface IStringArrayScopeCallsWrapperDataStorage extends IMapStorage<
|
||||
TNodeWithLexicalScope,
|
||||
TStringArrayScopeCallsWrapperDataByEncoding
|
||||
> {}
|
||||
+21
@@ -0,0 +1,21 @@
|
||||
import { TNodeWithLexicalScopeAndStatements } from '../../../types/node/TNodeWithLexicalScopeAndStatements';
|
||||
|
||||
import { IArrayStorage } from '../IArrayStorage';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
export interface IVisitedLexicalScopeNodesStackStorage extends IArrayStorage<TNodeWithLexicalScopeAndStatements> {
|
||||
/**
|
||||
* @returns {TNodeWithLexicalScopeAndStatements | undefined}
|
||||
*/
|
||||
getLastElement (): TNodeWithLexicalScopeAndStatements | undefined;
|
||||
|
||||
/**
|
||||
* @returns {TNodeWithLexicalScopeAndStatements | undefined}
|
||||
*/
|
||||
pop (): TNodeWithLexicalScopeAndStatements | undefined;
|
||||
|
||||
/**
|
||||
* @param {TNodeWithLexicalScopeAndStatements} lexicalScopeNode
|
||||
*/
|
||||
push (lexicalScopeNode: TNodeWithLexicalScopeAndStatements): void;
|
||||
}
|
||||
@@ -13,9 +13,9 @@ export interface IArrayUtils {
|
||||
|
||||
/**
|
||||
* @param {T[]} array
|
||||
* @returns {T | null}
|
||||
* @returns {T | undefined}
|
||||
*/
|
||||
getLastElement <T> (array: T[]): T | null;
|
||||
getLastElement <T> (array: T[]): T | undefined;
|
||||
|
||||
/**
|
||||
* @param array
|
||||
|
||||
+211
@@ -0,0 +1,211 @@
|
||||
import { inject, injectable, } from 'inversify';
|
||||
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
|
||||
|
||||
import * as ESTree from 'estree';
|
||||
|
||||
import { TInitialData } from '../../types/TInitialData';
|
||||
import { TNodeWithLexicalScope } from '../../types/node/TNodeWithLexicalScope';
|
||||
import { TNodeWithLexicalScopeAndStatements } from '../../types/node/TNodeWithLexicalScopeAndStatements';
|
||||
import { TStringArrayEncoding } from '../../types/options/TStringArrayEncoding';
|
||||
import { TStringArrayScopeCallsWrapperDataByEncoding } from '../../types/node-transformers/string-array-transformers/TStringArrayScopeCallsWrapperDataByEncoding';
|
||||
import { TStringArrayTransformerCustomNodeFactory } from '../../types/container/custom-nodes/TStringArrayTransformerCustomNodeFactory';
|
||||
|
||||
import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
|
||||
import { IOptions } from '../../interfaces/options/IOptions';
|
||||
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
|
||||
import { IStringArrayScopeCallsWrapperData } from '../../interfaces/node-transformers/string-array-transformers/IStringArrayScopeCallsWrapperData';
|
||||
import { IStringArrayScopeCallsWrapperDataStorage } from '../../interfaces/storages/string-array-transformers/IStringArrayScopeCallsWrapperDataStorage';
|
||||
import { IStringArrayStorage } from '../../interfaces/storages/string-array-transformers/IStringArrayStorage';
|
||||
import { IVisitedLexicalScopeNodesStackStorage } from '../../interfaces/storages/string-array-transformers/IVisitedLexicalScopeNodesStackStorage';
|
||||
import { IVisitor } from '../../interfaces/node-transformers/IVisitor';
|
||||
|
||||
import { NodeTransformationStage } from '../../enums/node-transformers/NodeTransformationStage';
|
||||
import { StringArrayTransformerCustomNode } from '../../enums/custom-nodes/StringArrayTransformerCustomNode';
|
||||
|
||||
import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
|
||||
import { NodeAppender } from '../../node/NodeAppender';
|
||||
import { NodeGuards } from '../../node/NodeGuards';
|
||||
import { StringArrayScopeCallsWrapperNode } from '../../custom-nodes/string-array-nodes/StringArrayScopeCallsWrapperNode';
|
||||
|
||||
@injectable()
|
||||
export class StringArrayScopeCallsWrapperTransformer extends AbstractNodeTransformer {
|
||||
/**
|
||||
* @type {IStringArrayStorage}
|
||||
*/
|
||||
private readonly stringArrayStorage: IStringArrayStorage;
|
||||
|
||||
/**
|
||||
* @type {IStringArrayScopeCallsWrapperDataStorage}
|
||||
*/
|
||||
private readonly stringArrayScopeCallsWrapperDataStorage: IStringArrayScopeCallsWrapperDataStorage;
|
||||
|
||||
/**
|
||||
* @type {TStringArrayTransformerCustomNodeFactory}
|
||||
*/
|
||||
private readonly stringArrayTransformerCustomNodeFactory: TStringArrayTransformerCustomNodeFactory;
|
||||
|
||||
/**
|
||||
* @type {IVisitedLexicalScopeNodesStackStorage}
|
||||
*/
|
||||
private readonly visitedLexicalScopeNodesStackStorage: IVisitedLexicalScopeNodesStackStorage;
|
||||
|
||||
/**
|
||||
* @param {IRandomGenerator} randomGenerator
|
||||
* @param {IOptions} options
|
||||
* @param {IVisitedLexicalScopeNodesStackStorage} visitedLexicalScopeNodesStackStorage
|
||||
* @param {IStringArrayStorage} stringArrayStorage
|
||||
* @param {IStringArrayScopeCallsWrapperDataStorage} stringArrayScopeCallsWrapperDataStorage
|
||||
* @param {TStringArrayTransformerCustomNodeFactory} stringArrayTransformerCustomNodeFactory
|
||||
*/
|
||||
public constructor (
|
||||
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
|
||||
@inject(ServiceIdentifiers.IOptions) options: IOptions,
|
||||
@inject(ServiceIdentifiers.IVisitedLexicalScopeNodesStackStorage) visitedLexicalScopeNodesStackStorage: IVisitedLexicalScopeNodesStackStorage,
|
||||
@inject(ServiceIdentifiers.IStringArrayStorage) stringArrayStorage: IStringArrayStorage,
|
||||
@inject(ServiceIdentifiers.IStringArrayScopeCallsWrapperDataStorage) stringArrayScopeCallsWrapperDataStorage: IStringArrayScopeCallsWrapperDataStorage,
|
||||
@inject(ServiceIdentifiers.Factory__IStringArrayTransformerCustomNode)
|
||||
stringArrayTransformerCustomNodeFactory: TStringArrayTransformerCustomNodeFactory
|
||||
) {
|
||||
super(randomGenerator, options);
|
||||
|
||||
this.visitedLexicalScopeNodesStackStorage = visitedLexicalScopeNodesStackStorage;
|
||||
this.stringArrayStorage = stringArrayStorage;
|
||||
this.stringArrayScopeCallsWrapperDataStorage = stringArrayScopeCallsWrapperDataStorage;
|
||||
this.stringArrayTransformerCustomNodeFactory = stringArrayTransformerCustomNodeFactory;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {NodeTransformationStage} nodeTransformationStage
|
||||
* @returns {IVisitor | null}
|
||||
*/
|
||||
public getVisitor (nodeTransformationStage: NodeTransformationStage): IVisitor | null {
|
||||
switch (nodeTransformationStage) {
|
||||
case NodeTransformationStage.StringArray:
|
||||
return {
|
||||
enter: (node: ESTree.Node): void => {
|
||||
if (NodeGuards.isNodeWithLexicalScopeAndStatements(node)) {
|
||||
this.onLexicalScopeNodeEnter(node);
|
||||
}
|
||||
},
|
||||
leave: (node: ESTree.Node): ESTree.Node | undefined => {
|
||||
if (NodeGuards.isNodeWithLexicalScopeAndStatements(node)) {
|
||||
this.onLexicalScopeNodeLeave();
|
||||
|
||||
return this.transformNode(node);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {TNodeWithLexicalScopeAndStatements} lexicalScopeNode
|
||||
* @returns {TNodeWithLexicalScopeAndStatements}
|
||||
*/
|
||||
public transformNode (lexicalScopeNode: TNodeWithLexicalScopeAndStatements): TNodeWithLexicalScopeAndStatements {
|
||||
if (!this.options.stringArrayWrappersCount) {
|
||||
return lexicalScopeNode;
|
||||
}
|
||||
|
||||
const lexicalScopeBodyNode: ESTree.Program | ESTree.BlockStatement =
|
||||
NodeGuards.isProgramNode(lexicalScopeNode)
|
||||
? lexicalScopeNode
|
||||
: lexicalScopeNode.body;
|
||||
|
||||
const stringArrayScopeCallsWrapperDataByEncoding: TStringArrayScopeCallsWrapperDataByEncoding | null =
|
||||
this.stringArrayScopeCallsWrapperDataStorage.get(lexicalScopeNode) ?? null;
|
||||
|
||||
if (!stringArrayScopeCallsWrapperDataByEncoding) {
|
||||
return lexicalScopeNode;
|
||||
}
|
||||
|
||||
const stringArrayScopeCallsWrapperDataList: (IStringArrayScopeCallsWrapperData | undefined)[] =
|
||||
Object.values(stringArrayScopeCallsWrapperDataByEncoding);
|
||||
|
||||
// iterates over data for each encoding type
|
||||
for (const stringArrayScopeCallsWrapperData of stringArrayScopeCallsWrapperDataList) {
|
||||
if (!stringArrayScopeCallsWrapperData) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const {encoding, names} = stringArrayScopeCallsWrapperData;
|
||||
const namesLength: number = names.length;
|
||||
|
||||
/**
|
||||
* Iterates over each name of scope wrapper name
|
||||
* Reverse iteration appends wrappers at index `0` at the correct order
|
||||
*/
|
||||
for (let i = namesLength - 1; i >= 0; i--) {
|
||||
const stringArrayScopeCallsWrapperName: string = names[i];
|
||||
const upperStringArrayCallsWrapperName: string = this.getUpperStringArrayCallsWrapperName(encoding);
|
||||
|
||||
const stringArrayScopeCallsWrapperNode: ICustomNode<TInitialData<StringArrayScopeCallsWrapperNode>> =
|
||||
this.stringArrayTransformerCustomNodeFactory(
|
||||
StringArrayTransformerCustomNode.StringArrayScopeCallsWrapperNode
|
||||
);
|
||||
|
||||
stringArrayScopeCallsWrapperNode.initialize(
|
||||
stringArrayScopeCallsWrapperName,
|
||||
upperStringArrayCallsWrapperName
|
||||
);
|
||||
|
||||
NodeAppender.prepend(
|
||||
lexicalScopeBodyNode,
|
||||
stringArrayScopeCallsWrapperNode.getNode()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return lexicalScopeNode;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {TStringArrayEncoding} encoding
|
||||
* @returns {string}
|
||||
*/
|
||||
private getRootStringArrayCallsWrapperName (encoding: TStringArrayEncoding): string {
|
||||
return this.stringArrayStorage.getStorageCallsWrapperName(encoding);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {TStringArrayEncoding} encoding
|
||||
* @returns {string}
|
||||
*/
|
||||
private getUpperStringArrayCallsWrapperName (encoding: TStringArrayEncoding): string {
|
||||
const rootStringArrayCallsWrapperName: string = this.getRootStringArrayCallsWrapperName(encoding);
|
||||
|
||||
if (!this.options.stringArrayWrappersChainedCalls) {
|
||||
return rootStringArrayCallsWrapperName;
|
||||
}
|
||||
|
||||
const parentLexicalScope: TNodeWithLexicalScope | undefined = this.visitedLexicalScopeNodesStackStorage.getLastElement();
|
||||
|
||||
if (!parentLexicalScope) {
|
||||
return rootStringArrayCallsWrapperName;
|
||||
}
|
||||
|
||||
const parentLexicalScopeDataByEncoding = this.stringArrayScopeCallsWrapperDataStorage
|
||||
.get(parentLexicalScope) ?? null;
|
||||
const parentLexicalScopeNames: string[] | null = parentLexicalScopeDataByEncoding?.[encoding]?.names ?? null;
|
||||
|
||||
return parentLexicalScopeNames?.length
|
||||
? this.randomGenerator
|
||||
.getRandomGenerator()
|
||||
.pickone(parentLexicalScopeNames)
|
||||
: rootStringArrayCallsWrapperName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {TNodeWithLexicalScopeAndStatements} lexicalScopeNode
|
||||
*/
|
||||
private onLexicalScopeNodeEnter (lexicalScopeNode: TNodeWithLexicalScopeAndStatements): void {
|
||||
this.visitedLexicalScopeNodesStackStorage.push(lexicalScopeNode);
|
||||
}
|
||||
|
||||
private onLexicalScopeNodeLeave (): void {
|
||||
this.visitedLexicalScopeNodesStackStorage.pop();
|
||||
}
|
||||
}
|
||||
@@ -5,13 +5,11 @@ import * as ESTree from 'estree';
|
||||
|
||||
import { TInitialData } from '../../types/TInitialData';
|
||||
import { TNodeWithLexicalScope } from '../../types/node/TNodeWithLexicalScope';
|
||||
import { TNodeWithLexicalScopeAndStatements } from '../../types/node/TNodeWithLexicalScopeAndStatements';
|
||||
import { TStatement } from '../../types/node/TStatement';
|
||||
import { TStringArrayEncoding } from '../../types/options/TStringArrayEncoding';
|
||||
import { TStringArrayScopeCallsWrapperDataByEncoding } from '../../types/node-transformers/string-array-transformers/TStringArrayScopeCallsWrapperDataByEncoding';
|
||||
import { TStringArrayTransformerCustomNodeFactory } from '../../types/container/custom-nodes/TStringArrayTransformerCustomNodeFactory';
|
||||
|
||||
import { IArrayUtils } from '../../interfaces/utils/IArrayUtils';
|
||||
import { ICustomNode } from '../../interfaces/custom-nodes/ICustomNode';
|
||||
import { IEscapeSequenceEncoder } from '../../interfaces/utils/IEscapeSequenceEncoder';
|
||||
import { IIdentifierNamesGenerator } from '../../interfaces/generators/identifier-names-generators/IIdentifierNamesGenerator';
|
||||
@@ -19,32 +17,26 @@ import { TIdentifierNamesGeneratorFactory } from '../../types/container/generato
|
||||
import { ILiteralNodesCacheStorage } from '../../interfaces/storages/string-array-transformers/ILiteralNodesCacheStorage';
|
||||
import { IOptions } from '../../interfaces/options/IOptions';
|
||||
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
|
||||
import { IStringArrayScopeCallsWrapperData } from '../../interfaces/node-transformers/string-array-transformers/IStringArrayScopeCallsWrapperData';
|
||||
import { IStringArrayScopeCallsWrapperDataStorage } from '../../interfaces/storages/string-array-transformers/IStringArrayScopeCallsWrapperDataStorage';
|
||||
import { IStringArrayStorage } from '../../interfaces/storages/string-array-transformers/IStringArrayStorage';
|
||||
import { IStringArrayStorageAnalyzer } from '../../interfaces/analyzers/string-array-storage-analyzer/IStringArrayStorageAnalyzer';
|
||||
import { IStringArrayStorageItemData } from '../../interfaces/storages/string-array-transformers/IStringArrayStorageItem';
|
||||
import { IVisitedLexicalScopeNodesStackStorage } from '../../interfaces/storages/string-array-transformers/IVisitedLexicalScopeNodesStackStorage';
|
||||
import { IVisitor } from '../../interfaces/node-transformers/IVisitor';
|
||||
|
||||
import { NodeTransformationStage } from '../../enums/node-transformers/NodeTransformationStage';
|
||||
import { StringArrayTransformerCustomNode } from '../../enums/custom-nodes/StringArrayTransformerCustomNode';
|
||||
|
||||
import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
|
||||
import { NodeAppender } from '../../node/NodeAppender';
|
||||
import { NodeFactory } from '../../node/NodeFactory';
|
||||
import { NodeGuards } from '../../node/NodeGuards';
|
||||
import { NodeLiteralUtils } from '../../node/NodeLiteralUtils';
|
||||
import { NodeMetadata } from '../../node/NodeMetadata';
|
||||
import { NodeUtils } from '../../node/NodeUtils';
|
||||
import { StringArrayCallNode } from '../../custom-nodes/string-array-nodes/StringArrayCallNode';
|
||||
import { StringArrayScopeCallsWrapperNode } from '../../custom-nodes/string-array-nodes/StringArrayScopeCallsWrapperNode';
|
||||
|
||||
@injectable()
|
||||
export class StringArrayTransformer extends AbstractNodeTransformer {
|
||||
/**
|
||||
* @type {IArrayUtils}
|
||||
*/
|
||||
private readonly arrayUtils: IArrayUtils;
|
||||
|
||||
/**
|
||||
* @type {IEscapeSequenceEncoder}
|
||||
*/
|
||||
@@ -60,14 +52,6 @@ export class StringArrayTransformer extends AbstractNodeTransformer {
|
||||
*/
|
||||
private readonly literalNodesCacheStorage: ILiteralNodesCacheStorage;
|
||||
|
||||
/**
|
||||
* @type {Map<TNodeWithLexicalScope, TStringArrayScopeCallsWrapperDataByEncoding>}
|
||||
*/
|
||||
private readonly stringArrayScopeCallsWrapperDataByEncodingMap: Map<
|
||||
TNodeWithLexicalScope,
|
||||
TStringArrayScopeCallsWrapperDataByEncoding
|
||||
> = new Map();
|
||||
|
||||
/**
|
||||
* @type {IStringArrayStorage}
|
||||
*/
|
||||
@@ -78,23 +62,29 @@ export class StringArrayTransformer extends AbstractNodeTransformer {
|
||||
*/
|
||||
private readonly stringArrayStorageAnalyzer: IStringArrayStorageAnalyzer;
|
||||
|
||||
/**
|
||||
* @type {IStringArrayScopeCallsWrapperDataStorage}
|
||||
*/
|
||||
private readonly stringArrayScopeCallsWrapperDataStorage: IStringArrayScopeCallsWrapperDataStorage;
|
||||
|
||||
/**
|
||||
* @type {TStringArrayTransformerCustomNodeFactory}
|
||||
*/
|
||||
private readonly stringArrayTransformerCustomNodeFactory: TStringArrayTransformerCustomNodeFactory;
|
||||
|
||||
/**
|
||||
* @type {TNodeWithLexicalScope[]}
|
||||
* @type {IVisitedLexicalScopeNodesStackStorage}
|
||||
*/
|
||||
private readonly visitedLexicalScopeNodesStack: TNodeWithLexicalScope[] = [];
|
||||
private readonly visitedLexicalScopeNodesStackStorage: IVisitedLexicalScopeNodesStackStorage;
|
||||
|
||||
/**
|
||||
* @param {IRandomGenerator} randomGenerator
|
||||
* @param {IOptions} options
|
||||
* @param {IArrayUtils} arrayUtils
|
||||
* @param {IEscapeSequenceEncoder} escapeSequenceEncoder
|
||||
* @param {ILiteralNodesCacheStorage} literalNodesCacheStorage
|
||||
* @param {IVisitedLexicalScopeNodesStackStorage} visitedLexicalScopeNodesStackStorage
|
||||
* @param {IStringArrayStorage} stringArrayStorage
|
||||
* @param {IStringArrayScopeCallsWrapperDataStorage} stringArrayScopeCallsWrapperDataStorage
|
||||
* @param {IStringArrayStorageAnalyzer} stringArrayStorageAnalyzer
|
||||
* @param {TIdentifierNamesGeneratorFactory} identifierNamesGeneratorFactory
|
||||
* @param {TStringArrayTransformerCustomNodeFactory} stringArrayTransformerCustomNodeFactory
|
||||
@@ -102,10 +92,11 @@ export class StringArrayTransformer extends AbstractNodeTransformer {
|
||||
public constructor (
|
||||
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
|
||||
@inject(ServiceIdentifiers.IOptions) options: IOptions,
|
||||
@inject(ServiceIdentifiers.IArrayUtils) arrayUtils: IArrayUtils,
|
||||
@inject(ServiceIdentifiers.IEscapeSequenceEncoder) escapeSequenceEncoder: IEscapeSequenceEncoder,
|
||||
@inject(ServiceIdentifiers.ILiteralNodesCacheStorage) literalNodesCacheStorage: ILiteralNodesCacheStorage,
|
||||
@inject(ServiceIdentifiers.IVisitedLexicalScopeNodesStackStorage) visitedLexicalScopeNodesStackStorage: IVisitedLexicalScopeNodesStackStorage,
|
||||
@inject(ServiceIdentifiers.IStringArrayStorage) stringArrayStorage: IStringArrayStorage,
|
||||
@inject(ServiceIdentifiers.IStringArrayScopeCallsWrapperDataStorage) stringArrayScopeCallsWrapperDataStorage: IStringArrayScopeCallsWrapperDataStorage,
|
||||
@inject(ServiceIdentifiers.IStringArrayStorageAnalyzer) stringArrayStorageAnalyzer: IStringArrayStorageAnalyzer,
|
||||
@inject(ServiceIdentifiers.Factory__IIdentifierNamesGenerator)
|
||||
identifierNamesGeneratorFactory: TIdentifierNamesGeneratorFactory,
|
||||
@@ -114,10 +105,11 @@ export class StringArrayTransformer extends AbstractNodeTransformer {
|
||||
) {
|
||||
super(randomGenerator, options);
|
||||
|
||||
this.arrayUtils = arrayUtils;
|
||||
this.escapeSequenceEncoder = escapeSequenceEncoder;
|
||||
this.literalNodesCacheStorage = literalNodesCacheStorage;
|
||||
this.visitedLexicalScopeNodesStackStorage = visitedLexicalScopeNodesStackStorage;
|
||||
this.stringArrayStorage = stringArrayStorage;
|
||||
this.stringArrayScopeCallsWrapperDataStorage = stringArrayScopeCallsWrapperDataStorage;
|
||||
this.stringArrayStorageAnalyzer = stringArrayStorageAnalyzer;
|
||||
this.identifierNamesGenerator = identifierNamesGeneratorFactory(options);
|
||||
this.stringArrayTransformerCustomNodeFactory = stringArrayTransformerCustomNodeFactory;
|
||||
@@ -136,20 +128,9 @@ export class StringArrayTransformer extends AbstractNodeTransformer {
|
||||
this.prepareNode(node);
|
||||
}
|
||||
|
||||
if (NodeGuards.isNodeWithLexicalScopeAndStatements(node)) {
|
||||
this.onLexicalScopeNodeEnter(node);
|
||||
}
|
||||
|
||||
if (parentNode && NodeGuards.isLiteralNode(node) && !NodeMetadata.isReplacedLiteral(node)) {
|
||||
return this.transformNode(node, parentNode);
|
||||
}
|
||||
},
|
||||
leave: (node: ESTree.Node): ESTree.Node | undefined => {
|
||||
if (NodeGuards.isNodeWithLexicalScopeAndStatements(node)) {
|
||||
this.onLexicalScopeNodeLeave();
|
||||
|
||||
return this.transformLexicalScopeNode(node);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -251,111 +232,10 @@ export class StringArrayTransformer extends AbstractNodeTransformer {
|
||||
private getStringArrayCallsWrapperName (stringArrayStorageItemData: IStringArrayStorageItemData): string {
|
||||
const {encoding} = stringArrayStorageItemData;
|
||||
|
||||
const stringArrayCallsWrapperName: string = this.stringArrayStorage.getStorageCallsWrapperName(encoding);
|
||||
return !this.options.stringArrayWrappersCount
|
||||
? this.getRootStringArrayCallsWrapperName(encoding)
|
||||
: this.getUpperStringArrayCallsWrapperName(encoding);
|
||||
|
||||
if (!this.options.stringArrayWrappersCount) {
|
||||
return stringArrayCallsWrapperName;
|
||||
}
|
||||
|
||||
const currentLexicalScopeNode: TNodeWithLexicalScope | null = this.arrayUtils.getLastElement(this.visitedLexicalScopeNodesStack);
|
||||
|
||||
if (!currentLexicalScopeNode) {
|
||||
throw new Error('Cannot find current lexical scope node');
|
||||
}
|
||||
|
||||
const stringArrayScopeCallsWrapperDataByEncoding: TStringArrayScopeCallsWrapperDataByEncoding =
|
||||
this.stringArrayScopeCallsWrapperDataByEncodingMap.get(currentLexicalScopeNode) ?? {};
|
||||
const stringArrayScopeCallsWrapperNames: string[] = stringArrayScopeCallsWrapperDataByEncoding[encoding]?.names ?? [];
|
||||
const isFilledScopeCallsWrapperNamesList: boolean = stringArrayScopeCallsWrapperNames.length === this.options.stringArrayWrappersCount;
|
||||
|
||||
if (!isFilledScopeCallsWrapperNamesList) {
|
||||
const nextScopeCallsWrapperName: string = this.identifierNamesGenerator.generateNext();
|
||||
|
||||
stringArrayScopeCallsWrapperNames.push(nextScopeCallsWrapperName);
|
||||
stringArrayScopeCallsWrapperDataByEncoding[encoding] = {
|
||||
encoding,
|
||||
names: stringArrayScopeCallsWrapperNames
|
||||
};
|
||||
|
||||
this.stringArrayScopeCallsWrapperDataByEncodingMap.set(
|
||||
currentLexicalScopeNode,
|
||||
stringArrayScopeCallsWrapperDataByEncoding
|
||||
);
|
||||
}
|
||||
|
||||
return this.randomGenerator.getRandomGenerator().pickone(stringArrayScopeCallsWrapperNames);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {TNodeWithLexicalScope} lexicalScopeNode
|
||||
*/
|
||||
private onLexicalScopeNodeEnter (lexicalScopeNode: TNodeWithLexicalScope): void {
|
||||
this.visitedLexicalScopeNodesStack.push(lexicalScopeNode);
|
||||
}
|
||||
|
||||
private onLexicalScopeNodeLeave (): void {
|
||||
this.visitedLexicalScopeNodesStack.pop();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {TNodeWithLexicalScopeAndStatements} lexicalScopeNode
|
||||
* @returns {TNodeWithLexicalScopeAndStatements}
|
||||
*/
|
||||
private transformLexicalScopeNode (lexicalScopeNode: TNodeWithLexicalScopeAndStatements): TNodeWithLexicalScopeAndStatements {
|
||||
if (!this.options.stringArrayWrappersCount) {
|
||||
return lexicalScopeNode;
|
||||
}
|
||||
|
||||
const lexicalScopeBodyNode: ESTree.Program | ESTree.BlockStatement =
|
||||
NodeGuards.isProgramNode(lexicalScopeNode)
|
||||
? lexicalScopeNode
|
||||
: lexicalScopeNode.body;
|
||||
|
||||
const stringArrayScopeCallsWrapperDataByEncoding: TStringArrayScopeCallsWrapperDataByEncoding | null =
|
||||
this.stringArrayScopeCallsWrapperDataByEncodingMap.get(lexicalScopeNode) ?? null;
|
||||
|
||||
if (!stringArrayScopeCallsWrapperDataByEncoding) {
|
||||
return lexicalScopeNode;
|
||||
}
|
||||
|
||||
const stringArrayScopeCallsWrapperDataList: (IStringArrayScopeCallsWrapperData | undefined)[] =
|
||||
Object.values(stringArrayScopeCallsWrapperDataByEncoding);
|
||||
|
||||
// iterates over data for each encoding type
|
||||
for (const stringArrayScopeCallsWrapperData of stringArrayScopeCallsWrapperDataList) {
|
||||
if (!stringArrayScopeCallsWrapperData) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const {encoding, names} = stringArrayScopeCallsWrapperData;
|
||||
const namesLength: number = names.length;
|
||||
|
||||
/**
|
||||
* Iterates over each name of scope wrapper name
|
||||
* Reverse iteration appends wrappers at index `0` at the correct order
|
||||
*/
|
||||
for (let i = namesLength - 1; i >= 0; i--) {
|
||||
const stringArrayScopeCallsWrapperName: string = names[i];
|
||||
const upperStringArrayCallsWrapperName: string = this.getUpperStringArrayCallsWrapperName(encoding);
|
||||
|
||||
const stringArrayScopeCallsWrapperNode: ICustomNode<TInitialData<StringArrayScopeCallsWrapperNode>> =
|
||||
this.stringArrayTransformerCustomNodeFactory(
|
||||
StringArrayTransformerCustomNode.StringArrayScopeCallsWrapperNode
|
||||
);
|
||||
|
||||
stringArrayScopeCallsWrapperNode.initialize(
|
||||
stringArrayScopeCallsWrapperName,
|
||||
upperStringArrayCallsWrapperName
|
||||
);
|
||||
|
||||
NodeAppender.prepend(
|
||||
lexicalScopeBodyNode,
|
||||
stringArrayScopeCallsWrapperNode.getNode()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return lexicalScopeNode;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -371,27 +251,33 @@ export class StringArrayTransformer extends AbstractNodeTransformer {
|
||||
* @returns {string}
|
||||
*/
|
||||
private getUpperStringArrayCallsWrapperName (encoding: TStringArrayEncoding): string {
|
||||
const rootStringArrayCallsWrapperName: string = this.getRootStringArrayCallsWrapperName(encoding);
|
||||
const currentLexicalScopeNode: TNodeWithLexicalScope | undefined = this.visitedLexicalScopeNodesStackStorage.getLastElement();
|
||||
|
||||
if (!this.options.stringArrayWrappersChainedCalls) {
|
||||
return rootStringArrayCallsWrapperName;
|
||||
if (!currentLexicalScopeNode) {
|
||||
throw new Error('Cannot find current lexical scope node');
|
||||
}
|
||||
|
||||
const parentLexicalScope: TNodeWithLexicalScope | null = this.arrayUtils.getLastElement(this.visitedLexicalScopeNodesStack);
|
||||
const stringArrayScopeCallsWrapperDataByEncoding: TStringArrayScopeCallsWrapperDataByEncoding =
|
||||
this.stringArrayScopeCallsWrapperDataStorage.get(currentLexicalScopeNode) ?? {};
|
||||
const stringArrayScopeCallsWrapperNames: string[] = stringArrayScopeCallsWrapperDataByEncoding[encoding]?.names ?? [];
|
||||
const isFilledScopeCallsWrapperNamesList: boolean = stringArrayScopeCallsWrapperNames.length === this.options.stringArrayWrappersCount;
|
||||
|
||||
if (!parentLexicalScope) {
|
||||
return rootStringArrayCallsWrapperName;
|
||||
if (!isFilledScopeCallsWrapperNamesList) {
|
||||
const nextScopeCallsWrapperName: string = this.identifierNamesGenerator.generateNext();
|
||||
|
||||
stringArrayScopeCallsWrapperNames.push(nextScopeCallsWrapperName);
|
||||
stringArrayScopeCallsWrapperDataByEncoding[encoding] = {
|
||||
encoding,
|
||||
names: stringArrayScopeCallsWrapperNames
|
||||
};
|
||||
|
||||
this.stringArrayScopeCallsWrapperDataStorage.set(
|
||||
currentLexicalScopeNode,
|
||||
stringArrayScopeCallsWrapperDataByEncoding
|
||||
);
|
||||
}
|
||||
|
||||
const parentLexicalScopeDataByEncoding = this.stringArrayScopeCallsWrapperDataByEncodingMap
|
||||
.get(parentLexicalScope) ?? null;
|
||||
const parentLexicalScopeNames: string[] | null = parentLexicalScopeDataByEncoding?.[encoding]?.names ?? null;
|
||||
|
||||
return parentLexicalScopeNames?.length
|
||||
? this.randomGenerator
|
||||
.getRandomGenerator()
|
||||
.pickone(parentLexicalScopeNames)
|
||||
: rootStringArrayCallsWrapperName;
|
||||
return this.randomGenerator.getRandomGenerator().pickone(stringArrayScopeCallsWrapperNames);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
|
||||
|
||||
import { TNodeWithLexicalScope } from '../../types/node/TNodeWithLexicalScope';
|
||||
import { TStringArrayScopeCallsWrapperDataByEncoding } from '../../types/node-transformers/string-array-transformers/TStringArrayScopeCallsWrapperDataByEncoding';
|
||||
|
||||
import { IOptions } from '../../interfaces/options/IOptions';
|
||||
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
|
||||
import { IStringArrayScopeCallsWrapperDataStorage } from '../../interfaces/storages/string-array-transformers/IStringArrayScopeCallsWrapperDataStorage';
|
||||
|
||||
import { MapStorage } from '../MapStorage';
|
||||
|
||||
@injectable()
|
||||
export class StringArrayScopeCallsWrapperDataStorage extends MapStorage <
|
||||
TNodeWithLexicalScope,
|
||||
TStringArrayScopeCallsWrapperDataByEncoding
|
||||
> implements IStringArrayScopeCallsWrapperDataStorage {
|
||||
/**
|
||||
* @param {IRandomGenerator} randomGenerator
|
||||
* @param {IOptions} options
|
||||
*/
|
||||
public constructor (
|
||||
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
|
||||
@inject(ServiceIdentifiers.IOptions) options: IOptions
|
||||
) {
|
||||
super(randomGenerator, options);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
import { inject, injectable } from 'inversify';
|
||||
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
|
||||
|
||||
import { TNodeWithLexicalScopeAndStatements } from '../../types/node/TNodeWithLexicalScopeAndStatements';
|
||||
|
||||
import { IArrayUtils } from '../../interfaces/utils/IArrayUtils';
|
||||
import { IOptions } from '../../interfaces/options/IOptions';
|
||||
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
|
||||
import { IVisitedLexicalScopeNodesStackStorage } from '../../interfaces/storages/string-array-transformers/IVisitedLexicalScopeNodesStackStorage';
|
||||
|
||||
import { ArrayStorage } from '../ArrayStorage';
|
||||
|
||||
@injectable()
|
||||
export class VisitedLexicalScopeNodesStackStorage extends ArrayStorage <TNodeWithLexicalScopeAndStatements> implements IVisitedLexicalScopeNodesStackStorage {
|
||||
/**
|
||||
* @type {IArrayUtils}
|
||||
*/
|
||||
private readonly arrayUtils: IArrayUtils;
|
||||
|
||||
/**
|
||||
* @param {IRandomGenerator} randomGenerator
|
||||
* @param {IOptions} options
|
||||
* @param {IArrayUtils} arrayUtils
|
||||
*/
|
||||
public constructor (
|
||||
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
|
||||
@inject(ServiceIdentifiers.IOptions) options: IOptions,
|
||||
@inject(ServiceIdentifiers.IArrayUtils) arrayUtils: IArrayUtils,
|
||||
) {
|
||||
super(randomGenerator, options);
|
||||
|
||||
this.arrayUtils = arrayUtils;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {TNodeWithLexicalScopeAndStatements | undefined}
|
||||
*/
|
||||
public getLastElement (): TNodeWithLexicalScopeAndStatements | undefined {
|
||||
return this.arrayUtils.getLastElement(this.getStorage());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {TNodeWithLexicalScopeAndStatements} lexicalScopeNode
|
||||
*/
|
||||
public push (lexicalScopeNode: TNodeWithLexicalScopeAndStatements): void {
|
||||
this.storage.push(lexicalScopeNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {TNodeWithLexicalScopeAndStatements | undefined}
|
||||
*/
|
||||
public pop (): TNodeWithLexicalScopeAndStatements | undefined {
|
||||
return this.storage.pop();
|
||||
}
|
||||
}
|
||||
@@ -67,12 +67,12 @@ export class ArrayUtils implements IArrayUtils {
|
||||
|
||||
/**
|
||||
* @param {T[]} array
|
||||
* @returns {T | null}
|
||||
* @returns {T | undefined}
|
||||
*/
|
||||
public getLastElement <T> (array: T[]): T | null {
|
||||
public getLastElement <T> (array: T[]): T | undefined {
|
||||
const arrayLength: number = array.length;
|
||||
|
||||
return array[arrayLength - 1] ?? null;
|
||||
return array[arrayLength - 1] ?? undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+766
@@ -0,0 +1,766 @@
|
||||
import { assert } from 'chai';
|
||||
|
||||
import { IdentifierNamesGenerator } from '../../../../../src/enums/generators/identifier-names-generators/IdentifierNamesGenerator';
|
||||
import { StringArrayEncoding } from '../../../../../src/enums/StringArrayEncoding';
|
||||
|
||||
import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes';
|
||||
|
||||
import { readFileAsString } from '../../../../helpers/readFileAsString';
|
||||
|
||||
import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade';
|
||||
|
||||
describe('StringArrayScopeCallsWrapperTransformer', function () {
|
||||
this.timeout(120000);
|
||||
|
||||
describe('Variant #1: base', () => {
|
||||
describe('Variant #1: root scope', () => {
|
||||
describe('Variant #1: option value value is lower then count `literal` nodes in the scope', () => {
|
||||
const stringArrayCallRegExp: RegExp = new RegExp(
|
||||
'return _0x([a-f0-9]){4,6};' +
|
||||
'};' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
'const foo *= *_0x([a-f0-9]){4,6}\\(\'0x0\'\\);' +
|
||||
'const bar *= *_0x([a-f0-9]){4,6}\\(\'0x1\'\\);' +
|
||||
'const baz *= *_0x([a-f0-9]){4,6}\\(\'0x2\'\\);'
|
||||
);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/wrappers-count-const.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayWrappersCount: 2
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should add scope calls wrappers', () => {
|
||||
assert.match(obfuscatedCode, stringArrayCallRegExp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: option value is bigger then count `literal` nodes in the scope', () => {
|
||||
const stringArrayCallRegExp: RegExp = new RegExp(
|
||||
'return _0x([a-f0-9]){4,6};' +
|
||||
'};' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
'const foo *= *_0x([a-f0-9]){4,6}\\(\'0x0\'\\);' +
|
||||
'const bar *= *_0x([a-f0-9]){4,6}\\(\'0x1\'\\);' +
|
||||
'const baz *= *_0x([a-f0-9]){4,6}\\(\'0x2\'\\);'
|
||||
);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/wrappers-count-const.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayWrappersCount: 5
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should add scope calls wrappers', () => {
|
||||
assert.match(obfuscatedCode, stringArrayCallRegExp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #3: correct wrappers order', () => {
|
||||
const stringArrayCallRegExp: RegExp = new RegExp(
|
||||
'const f *= *b;' +
|
||||
'const g *= *b;' +
|
||||
'const foo *= *[f|g]\\(\'0x0\'\\);' +
|
||||
'const bar *= *[f|g]\\(\'0x1\'\\);' +
|
||||
'const baz *= *[f|g]\\(\'0x2\'\\);'
|
||||
);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/wrappers-count-const.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
identifierNamesGenerator: IdentifierNamesGenerator.MangledIdentifierNamesGenerator,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayWrappersCount: 2
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should add scope calls wrappers', () => {
|
||||
assert.match(obfuscatedCode, stringArrayCallRegExp);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: function scope', () => {
|
||||
describe('Variant #1: option value is lower then count `literal` nodes in the scope', () => {
|
||||
const stringArrayCallRegExp: RegExp = new RegExp(
|
||||
'function test *\\( *\\) *{' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x3\'\\);' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x4\'\\);' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x5\'\\);' +
|
||||
'}'
|
||||
);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/wrappers-count-const.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayWrappersCount: 2
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should add scope calls wrappers', () => {
|
||||
assert.match(obfuscatedCode, stringArrayCallRegExp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: option value is bigger then count `literal` nodes in the scope', () => {
|
||||
const stringArrayCallRegExp: RegExp = new RegExp(
|
||||
'function test *\\(\\) *{' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x3\'\\);' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x4\'\\);' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x5\'\\);' +
|
||||
'}'
|
||||
);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/wrappers-count-const.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayWrappersCount: 5
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should add scope calls wrappers', () => {
|
||||
assert.match(obfuscatedCode, stringArrayCallRegExp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #3: correct wrappers order', () => {
|
||||
const stringArrayCallRegExp: RegExp = new RegExp(
|
||||
'function test *\\( *\\) *{' +
|
||||
'const h *= *b;' +
|
||||
'const i *= *b;' +
|
||||
'const c *= *[h|i]\\(\'0x3\'\\);' +
|
||||
'const d *= *[h|i]\\(\'0x4\'\\);' +
|
||||
'const e *= *[h|i]\\(\'0x5\'\\);' +
|
||||
'}'
|
||||
);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/wrappers-count-const.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
identifierNamesGenerator: IdentifierNamesGenerator.MangledIdentifierNamesGenerator,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayWrappersCount: 2
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should add scope calls wrappers', () => {
|
||||
assert.match(obfuscatedCode, stringArrayCallRegExp);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #3: prohibited scopes', () => {
|
||||
describe('Variant #1: if statement scope', () => {
|
||||
const stringArrayCallRegExp: RegExp = new RegExp(
|
||||
'var c *= *b;' +
|
||||
'if *\\(!!\\[]\\) *{' +
|
||||
'var foo *= *c\\(\'0x0\'\\);' +
|
||||
'}'
|
||||
);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/prohibited-scope-1.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
identifierNamesGenerator: IdentifierNamesGenerator.MangledIdentifierNamesGenerator,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayWrappersCount: 1
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should not add scope calls wrappers to a prohibited scope', () => {
|
||||
assert.match(obfuscatedCode, stringArrayCallRegExp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: arrow function scope without statements', () => {
|
||||
const stringArrayCallRegExp: RegExp = new RegExp(
|
||||
'var c *= *b;' +
|
||||
'\\[]\\[c\\(\'0x0\'\\)]\\(\\(\\) *=> *c\\(\'0x1\'\\)\\);'
|
||||
);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/prohibited-scope-2.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
identifierNamesGenerator: IdentifierNamesGenerator.MangledIdentifierNamesGenerator,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayWrappersCount: 1
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should not add scope calls wrappers to a prohibited scope', () => {
|
||||
assert.match(obfuscatedCode, stringArrayCallRegExp);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #4: prevailing kind of variables', () => {
|
||||
const stringArrayCallRegExp: RegExp = new RegExp(
|
||||
'return _0x([a-f0-9]){4,6};' +
|
||||
'};' +
|
||||
'var _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
'var _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
'var foo *= *_0x([a-f0-9]){4,6}\\(\'0x0\'\\);' +
|
||||
'var bar *= *_0x([a-f0-9]){4,6}\\(\'0x1\'\\);' +
|
||||
'var baz *= *_0x([a-f0-9]){4,6}\\(\'0x2\'\\);'
|
||||
);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/wrappers-count-var.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayWrappersCount: 2
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should add scope calls wrappers with a correct variables kind', () => {
|
||||
assert.match(obfuscatedCode, stringArrayCallRegExp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #5: correct evaluation of the scope calls wrappers', () => {
|
||||
const expectedEvaluationResult: string = 'aaabbbcccdddeee';
|
||||
let evaluationResult: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/wrappers-count-eval.js');
|
||||
|
||||
const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayWrappersCount: 5
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
|
||||
evaluationResult = eval(obfuscatedCode);
|
||||
});
|
||||
|
||||
it('should correctly evaluate scope calls wrappers', () => {
|
||||
assert.equal(evaluationResult, expectedEvaluationResult);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #6: `stringArrayWrappersChainedCalls` option is enabled', () => {
|
||||
describe('Variant #1: correct chained calls', () => {
|
||||
describe('Variant #1: `Mangled` identifier names generator', () => {
|
||||
const stringArrayCallRegExp: RegExp = new RegExp(
|
||||
'const q *= *b;' +
|
||||
'const foo *= *q\\(\'0x0\'\\);' +
|
||||
'function test\\(c, *d\\) *{' +
|
||||
'const r *= *q;' +
|
||||
'const e *= *r\\(\'0x1\'\\);' +
|
||||
'const f *= *r\\(\'0x2\'\\);' +
|
||||
'function g\\(h, *i\\) *{' +
|
||||
'const s *= *r;' +
|
||||
'const j *= *s\\(\'0x3\'\\);' +
|
||||
'const k *= *s\\(\'0x4\'\\);' +
|
||||
'function l\\(m, *n *\\) *{' +
|
||||
'const t *= *s;' +
|
||||
'const o *= *t\\(\'0x3\'\\);' +
|
||||
'const p *= *t\\(\'0x4\'\\);' +
|
||||
'return o *\\+ *p;' +
|
||||
'}' +
|
||||
'return j *\\+ *k;' +
|
||||
'}' +
|
||||
'return e *\\+ *f *\\+ *g\\(\\);' +
|
||||
'}'
|
||||
);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/chained-calls-1.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
identifierNamesGenerator: IdentifierNamesGenerator.MangledIdentifierNamesGenerator,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayWrappersChainedCalls: true,
|
||||
stringArrayWrappersCount: 1
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should add correct scope calls wrappers', () => {
|
||||
assert.match(obfuscatedCode, stringArrayCallRegExp);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: correct evaluation of the string array wrappers chained calls', () => {
|
||||
describe('Variant #1: base', () => {
|
||||
describe('Variant #1: `Hexadecimal` identifier names generator', () => {
|
||||
const samplesCount: number = 50;
|
||||
const expectedEvaluationResult: string = 'aaabbbcccdddeee';
|
||||
let isEvaluationSuccessful: boolean = true;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/chained-calls-1.js');
|
||||
|
||||
for (let i = 0; i < samplesCount; i++) {
|
||||
const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
identifierNamesGenerator: IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayEncoding: [
|
||||
StringArrayEncoding.None,
|
||||
StringArrayEncoding.Rc4
|
||||
],
|
||||
stringArrayWrappersChainedCalls: true,
|
||||
stringArrayWrappersCount: 5
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
|
||||
const evaluationResult: string = eval(obfuscatedCode);
|
||||
|
||||
if (evaluationResult !== expectedEvaluationResult) {
|
||||
isEvaluationSuccessful = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('should correctly evaluate string array wrappers chained calls', () => {
|
||||
assert.equal(isEvaluationSuccessful, true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: `Mangled` identifier names generator', () => {
|
||||
const samplesCount: number = 50;
|
||||
const expectedEvaluationResult: string = 'aaabbbcccdddeee';
|
||||
let isEvaluationSuccessful: boolean = true;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/chained-calls-1.js');
|
||||
|
||||
for (let i = 0; i < samplesCount; i++) {
|
||||
const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
identifierNamesGenerator: IdentifierNamesGenerator.MangledIdentifierNamesGenerator,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayEncoding: [
|
||||
StringArrayEncoding.None,
|
||||
StringArrayEncoding.Rc4
|
||||
],
|
||||
stringArrayWrappersChainedCalls: true,
|
||||
stringArrayWrappersCount: 5
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
|
||||
const evaluationResult: string = eval(obfuscatedCode);
|
||||
|
||||
if (evaluationResult !== expectedEvaluationResult) {
|
||||
isEvaluationSuccessful = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('should correctly evaluate string array wrappers chained calls', () => {
|
||||
assert.equal(isEvaluationSuccessful, true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: advanced', () => {
|
||||
describe('Variant #1: `Hexadecimal` identifier names generator', () => {
|
||||
const samplesCount: number = 50;
|
||||
const expectedEvaluationResult: string = 'aaabbbcccdddeee';
|
||||
let isEvaluationSuccessful: boolean = true;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/chained-calls-2.js');
|
||||
|
||||
for (let i = 0; i < samplesCount; i++) {
|
||||
const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
identifierNamesGenerator: IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayEncoding: [
|
||||
StringArrayEncoding.None,
|
||||
StringArrayEncoding.Rc4
|
||||
],
|
||||
stringArrayWrappersChainedCalls: true,
|
||||
stringArrayWrappersCount: 5
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
|
||||
const evaluationResult: string = eval(obfuscatedCode);
|
||||
|
||||
if (evaluationResult !== expectedEvaluationResult) {
|
||||
isEvaluationSuccessful = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('should correctly evaluate string array wrappers chained calls', () => {
|
||||
assert.equal(isEvaluationSuccessful, true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: `Mangled` identifier names generator', () => {
|
||||
const samplesCount: number = 50;
|
||||
const expectedEvaluationResult: string = 'aaabbbcccdddeee';
|
||||
let isEvaluationSuccessful: boolean = true;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/chained-calls-2.js');
|
||||
|
||||
for (let i = 0; i < samplesCount; i++) {
|
||||
const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
identifierNamesGenerator: IdentifierNamesGenerator.MangledIdentifierNamesGenerator,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayEncoding: [
|
||||
StringArrayEncoding.None,
|
||||
StringArrayEncoding.Rc4
|
||||
],
|
||||
stringArrayWrappersChainedCalls: true,
|
||||
stringArrayWrappersCount: 5
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
|
||||
const evaluationResult: string = eval(obfuscatedCode);
|
||||
|
||||
if (evaluationResult !== expectedEvaluationResult) {
|
||||
isEvaluationSuccessful = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('should correctly evaluate string array wrappers chained calls', () => {
|
||||
assert.equal(isEvaluationSuccessful, true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: none and base64 encoding', () => {
|
||||
describe('Variant #1: root scope', () => {
|
||||
describe('Variant #1: `1` scope calls wrapper for each encoding type', () => {
|
||||
const stringArrayWrappersRegExp: RegExp = new RegExp(
|
||||
'return _0x([a-f0-9]){4,6};' +
|
||||
'};' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
// this one may be added or not depends on:
|
||||
// if all literal values encoded with a single encoding or not
|
||||
'(?:const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};)?' +
|
||||
'const foo *= *_0x([a-f0-9]){4,6}\\(\'0x0\'\\);' +
|
||||
'const bar *= *_0x([a-f0-9]){4,6}\\(\'0x1\'\\);' +
|
||||
'const baz *= *_0x([a-f0-9]){4,6}\\(\'0x2\'\\);'
|
||||
);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/wrappers-count-const.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayEncoding: [
|
||||
StringArrayEncoding.None,
|
||||
StringArrayEncoding.Base64
|
||||
],
|
||||
stringArrayWrappersCount: 1,
|
||||
stringArrayThreshold: 1
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should add scope calls wrappers for both `none` and `base64` string array wrappers', () => {
|
||||
assert.match(obfuscatedCode, stringArrayWrappersRegExp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: `2` scope calls wrappers for each encoding type', () => {
|
||||
const stringArrayWrappersRegExp: RegExp = new RegExp(
|
||||
'return _0x([a-f0-9]){4,6};' +
|
||||
'};' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
// this one may be added or not depends on:
|
||||
// if all literal values encoded with a single encoding or not
|
||||
'(?:const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};)?' +
|
||||
'const foo *= *_0x([a-f0-9]){4,6}\\(\'0x0\'\\);' +
|
||||
'const bar *= *_0x([a-f0-9]){4,6}\\(\'0x1\'\\);' +
|
||||
'const baz *= *_0x([a-f0-9]){4,6}\\(\'0x2\'\\);'
|
||||
);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/wrappers-count-const.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayEncoding: [
|
||||
StringArrayEncoding.None,
|
||||
StringArrayEncoding.Base64
|
||||
],
|
||||
stringArrayWrappersCount: 2,
|
||||
stringArrayThreshold: 1
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should add scope calls wrappers for both `none` and `base64` string array wrappers', () => {
|
||||
assert.match(obfuscatedCode, stringArrayWrappersRegExp);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: function scope', () => {
|
||||
describe('Variant #1: `1` scope calls wrapper for each encoding type', () => {
|
||||
const stringArrayWrappersRegExp: RegExp = new RegExp(
|
||||
'function test *\\( *\\) *{' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
// this one may be added or not depends on:
|
||||
// if all literal values encoded with a single encoding or not
|
||||
'(?:const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};)?' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x3\'\\);' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x4\'\\);' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x5\'\\);' +
|
||||
'}'
|
||||
);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/wrappers-count-const.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayEncoding: [
|
||||
StringArrayEncoding.None,
|
||||
StringArrayEncoding.Base64
|
||||
],
|
||||
stringArrayWrappersCount: 1,
|
||||
stringArrayThreshold: 1
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should add scope calls wrappers for both `none` and `base64` string array wrappers', () => {
|
||||
assert.match(obfuscatedCode, stringArrayWrappersRegExp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: `2` scope calls wrappers for each encoding type', () => {
|
||||
const stringArrayWrappersRegExp: RegExp = new RegExp(
|
||||
'function test *\\( *\\) *{' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
// this one may be added or not depends on:
|
||||
// if all literal values encoded with a single encoding or not
|
||||
'(?:const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};)?' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x3\'\\);' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x4\'\\);' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x5\'\\);' +
|
||||
'}'
|
||||
);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/wrappers-count-const.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayEncoding: [
|
||||
StringArrayEncoding.None,
|
||||
StringArrayEncoding.Base64
|
||||
],
|
||||
stringArrayWrappersCount: 2,
|
||||
stringArrayThreshold: 1
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should add scope calls wrappers for both `none` and `base64` string array wrappers', () => {
|
||||
assert.match(obfuscatedCode, stringArrayWrappersRegExp);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #3: none and rc4 encoding', () => {
|
||||
describe('Variant #1: correct evaluation of the scope calls wrappers', () => {
|
||||
const expectedEvaluationResult: string = 'aaabbbcccdddeee';
|
||||
let evaluationResult: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/wrappers-count-eval.js');
|
||||
|
||||
const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayEncoding: [
|
||||
StringArrayEncoding.None,
|
||||
StringArrayEncoding.Rc4
|
||||
],
|
||||
stringArrayWrappersCount: 5
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
|
||||
evaluationResult = eval(obfuscatedCode);
|
||||
});
|
||||
|
||||
it('should correctly evaluate scope calls wrappers', () => {
|
||||
assert.equal(evaluationResult, expectedEvaluationResult);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #4: base64 and rc4 encoding', () => {
|
||||
describe('Variant #1: correct evaluation of the scope calls wrappers', () => {
|
||||
const expectedEvaluationResult: string = 'aaabbbcccdddeee';
|
||||
let evaluationResult: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/wrappers-count-eval.js');
|
||||
|
||||
const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayEncoding: [
|
||||
StringArrayEncoding.Base64,
|
||||
StringArrayEncoding.Rc4
|
||||
],
|
||||
stringArrayWrappersCount: 5
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
|
||||
evaluationResult = eval(obfuscatedCode);
|
||||
});
|
||||
|
||||
it('should correctly evaluate scope calls wrappers', () => {
|
||||
assert.equal(evaluationResult, expectedEvaluationResult);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
+17
-769
@@ -63,537 +63,7 @@ describe('StringArrayTransformer', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #3: `stringArrayWrappersCount` option is enabled', () => {
|
||||
describe('Variant #1: root scope', () => {
|
||||
describe('Variant #1: option value value is lower then count `literal` nodes in the scope', () => {
|
||||
const stringArrayCallRegExp: RegExp = new RegExp(
|
||||
'return _0x([a-f0-9]){4,6};' +
|
||||
'};' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
'const foo *= *_0x([a-f0-9]){4,6}\\(\'0x0\'\\);' +
|
||||
'const bar *= *_0x([a-f0-9]){4,6}\\(\'0x1\'\\);' +
|
||||
'const baz *= *_0x([a-f0-9]){4,6}\\(\'0x2\'\\);'
|
||||
);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-count-const.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayWrappersCount: 2
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should add scope calls wrappers', () => {
|
||||
assert.match(obfuscatedCode, stringArrayCallRegExp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: option value is bigger then count `literal` nodes in the scope', () => {
|
||||
const stringArrayCallRegExp: RegExp = new RegExp(
|
||||
'return _0x([a-f0-9]){4,6};' +
|
||||
'};' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
'const foo *= *_0x([a-f0-9]){4,6}\\(\'0x0\'\\);' +
|
||||
'const bar *= *_0x([a-f0-9]){4,6}\\(\'0x1\'\\);' +
|
||||
'const baz *= *_0x([a-f0-9]){4,6}\\(\'0x2\'\\);'
|
||||
);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-count-const.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayWrappersCount: 5
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should add scope calls wrappers', () => {
|
||||
assert.match(obfuscatedCode, stringArrayCallRegExp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #3: correct wrappers order', () => {
|
||||
const stringArrayCallRegExp: RegExp = new RegExp(
|
||||
'const f *= *b;' +
|
||||
'const g *= *b;' +
|
||||
'const foo *= *[f|g]\\(\'0x0\'\\);' +
|
||||
'const bar *= *[f|g]\\(\'0x1\'\\);' +
|
||||
'const baz *= *[f|g]\\(\'0x2\'\\);'
|
||||
);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-count-const.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
identifierNamesGenerator: IdentifierNamesGenerator.MangledIdentifierNamesGenerator,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayWrappersCount: 2
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should add scope calls wrappers', () => {
|
||||
assert.match(obfuscatedCode, stringArrayCallRegExp);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: function scope', () => {
|
||||
describe('Variant #1: option value is lower then count `literal` nodes in the scope', () => {
|
||||
const stringArrayCallRegExp: RegExp = new RegExp(
|
||||
'function test *\\( *\\) *{' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x3\'\\);' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x4\'\\);' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x5\'\\);' +
|
||||
'}'
|
||||
);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-count-const.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayWrappersCount: 2
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should add scope calls wrappers', () => {
|
||||
assert.match(obfuscatedCode, stringArrayCallRegExp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: option value is bigger then count `literal` nodes in the scope', () => {
|
||||
const stringArrayCallRegExp: RegExp = new RegExp(
|
||||
'function test *\\(\\) *{' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x3\'\\);' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x4\'\\);' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x5\'\\);' +
|
||||
'}'
|
||||
);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-count-const.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayWrappersCount: 5
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should add scope calls wrappers', () => {
|
||||
assert.match(obfuscatedCode, stringArrayCallRegExp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #3: correct wrappers order', () => {
|
||||
const stringArrayCallRegExp: RegExp = new RegExp(
|
||||
'function test *\\( *\\) *{' +
|
||||
'const h *= *b;' +
|
||||
'const i *= *b;' +
|
||||
'const c *= *[h|i]\\(\'0x3\'\\);' +
|
||||
'const d *= *[h|i]\\(\'0x4\'\\);' +
|
||||
'const e *= *[h|i]\\(\'0x5\'\\);' +
|
||||
'}'
|
||||
);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-count-const.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
identifierNamesGenerator: IdentifierNamesGenerator.MangledIdentifierNamesGenerator,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayWrappersCount: 2
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should add scope calls wrappers', () => {
|
||||
assert.match(obfuscatedCode, stringArrayCallRegExp);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #3: prohibited scopes', () => {
|
||||
describe('Variant #1: if statement scope', () => {
|
||||
const stringArrayCallRegExp: RegExp = new RegExp(
|
||||
'var c *= *b;' +
|
||||
'if *\\(!!\\[]\\) *{' +
|
||||
'var foo *= *c\\(\'0x0\'\\);' +
|
||||
'}'
|
||||
);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-count-prohibited-scope-1.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
identifierNamesGenerator: IdentifierNamesGenerator.MangledIdentifierNamesGenerator,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayWrappersCount: 1
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should not add scope calls wrappers to a prohibited scope', () => {
|
||||
assert.match(obfuscatedCode, stringArrayCallRegExp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: arrow function scope without statements', () => {
|
||||
const stringArrayCallRegExp: RegExp = new RegExp(
|
||||
'var c *= *b;' +
|
||||
'\\[]\\[c\\(\'0x0\'\\)]\\(\\(\\) *=> *c\\(\'0x1\'\\)\\);'
|
||||
);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-count-prohibited-scope-2.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
identifierNamesGenerator: IdentifierNamesGenerator.MangledIdentifierNamesGenerator,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayWrappersCount: 1
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should not add scope calls wrappers to a prohibited scope', () => {
|
||||
assert.match(obfuscatedCode, stringArrayCallRegExp);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #4: prevailing kind of variables', () => {
|
||||
const stringArrayCallRegExp: RegExp = new RegExp(
|
||||
'return _0x([a-f0-9]){4,6};' +
|
||||
'};' +
|
||||
'var _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
'var _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
'var foo *= *_0x([a-f0-9]){4,6}\\(\'0x0\'\\);' +
|
||||
'var bar *= *_0x([a-f0-9]){4,6}\\(\'0x1\'\\);' +
|
||||
'var baz *= *_0x([a-f0-9]){4,6}\\(\'0x2\'\\);'
|
||||
);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-count-var.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayWrappersCount: 2
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should add scope calls wrappers with a correct variables kind', () => {
|
||||
assert.match(obfuscatedCode, stringArrayCallRegExp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #5: correct evaluation of the scope calls wrappers', () => {
|
||||
const expectedEvaluationResult: string = 'aaabbbcccdddeee';
|
||||
let evaluationResult: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-count-eval.js');
|
||||
|
||||
const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayWrappersCount: 5
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
|
||||
evaluationResult = eval(obfuscatedCode);
|
||||
});
|
||||
|
||||
it('should correctly evaluate scope calls wrappers', () => {
|
||||
assert.equal(evaluationResult, expectedEvaluationResult);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #6: `stringArrayWrappersChainedCalls` option is enabled', () => {
|
||||
describe('Variant #1: correct chained calls', () => {
|
||||
describe('Variant #1: `Mangled` identifier names generator', () => {
|
||||
const stringArrayCallRegExp: RegExp = new RegExp(
|
||||
'const q *= *b;' +
|
||||
'const foo *= *q\\(\'0x0\'\\);' +
|
||||
'function test\\(c, *d\\) *{' +
|
||||
'const r *= *q;' +
|
||||
'const e *= *r\\(\'0x1\'\\);' +
|
||||
'const f *= *r\\(\'0x2\'\\);' +
|
||||
'function g\\(h, *i\\) *{' +
|
||||
'const s *= *r;' +
|
||||
'const j *= *s\\(\'0x3\'\\);' +
|
||||
'const k *= *s\\(\'0x4\'\\);' +
|
||||
'function l\\(m, *n *\\) *{' +
|
||||
'const t *= *s;' +
|
||||
'const o *= *t\\(\'0x3\'\\);' +
|
||||
'const p *= *t\\(\'0x4\'\\);' +
|
||||
'return o *\\+ *p;' +
|
||||
'}' +
|
||||
'return j *\\+ *k;' +
|
||||
'}' +
|
||||
'return e *\\+ *f *\\+ *g\\(\\);' +
|
||||
'}'
|
||||
);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-chained-calls-1.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
identifierNamesGenerator: IdentifierNamesGenerator.MangledIdentifierNamesGenerator,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayWrappersChainedCalls: true,
|
||||
stringArrayWrappersCount: 1
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should add correct scope calls wrappers', () => {
|
||||
assert.match(obfuscatedCode, stringArrayCallRegExp);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: correct evaluation of the string array wrappers chained calls', () => {
|
||||
describe('Variant #1: base', () => {
|
||||
describe('Variant #1: `Hexadecimal` identifier names generator', () => {
|
||||
const samplesCount: number = 50;
|
||||
const expectedEvaluationResult: string = 'aaabbbcccdddeee';
|
||||
let isEvaluationSuccessful: boolean = true;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-chained-calls-1.js');
|
||||
|
||||
for (let i = 0; i < samplesCount; i++) {
|
||||
const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
identifierNamesGenerator: IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayEncoding: [
|
||||
StringArrayEncoding.None,
|
||||
StringArrayEncoding.Rc4
|
||||
],
|
||||
stringArrayWrappersChainedCalls: true,
|
||||
stringArrayWrappersCount: 5
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
|
||||
const evaluationResult: string = eval(obfuscatedCode);
|
||||
|
||||
if (evaluationResult !== expectedEvaluationResult) {
|
||||
isEvaluationSuccessful = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('should correctly evaluate string array wrappers chained calls', () => {
|
||||
assert.equal(isEvaluationSuccessful, true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: `Mangled` identifier names generator', () => {
|
||||
const samplesCount: number = 50;
|
||||
const expectedEvaluationResult: string = 'aaabbbcccdddeee';
|
||||
let isEvaluationSuccessful: boolean = true;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-chained-calls-1.js');
|
||||
|
||||
for (let i = 0; i < samplesCount; i++) {
|
||||
const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
identifierNamesGenerator: IdentifierNamesGenerator.MangledIdentifierNamesGenerator,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayEncoding: [
|
||||
StringArrayEncoding.None,
|
||||
StringArrayEncoding.Rc4
|
||||
],
|
||||
stringArrayWrappersChainedCalls: true,
|
||||
stringArrayWrappersCount: 5
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
|
||||
const evaluationResult: string = eval(obfuscatedCode);
|
||||
|
||||
if (evaluationResult !== expectedEvaluationResult) {
|
||||
isEvaluationSuccessful = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('should correctly evaluate string array wrappers chained calls', () => {
|
||||
assert.equal(isEvaluationSuccessful, true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: advanced', () => {
|
||||
describe('Variant #1: `Hexadecimal` identifier names generator', () => {
|
||||
const samplesCount: number = 50;
|
||||
const expectedEvaluationResult: string = 'aaabbbcccdddeee';
|
||||
let isEvaluationSuccessful: boolean = true;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-chained-calls-2.js');
|
||||
|
||||
for (let i = 0; i < samplesCount; i++) {
|
||||
const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
identifierNamesGenerator: IdentifierNamesGenerator.HexadecimalIdentifierNamesGenerator,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayEncoding: [
|
||||
StringArrayEncoding.None,
|
||||
StringArrayEncoding.Rc4
|
||||
],
|
||||
stringArrayWrappersChainedCalls: true,
|
||||
stringArrayWrappersCount: 5
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
|
||||
const evaluationResult: string = eval(obfuscatedCode);
|
||||
|
||||
if (evaluationResult !== expectedEvaluationResult) {
|
||||
isEvaluationSuccessful = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('should correctly evaluate string array wrappers chained calls', () => {
|
||||
assert.equal(isEvaluationSuccessful, true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: `Mangled` identifier names generator', () => {
|
||||
const samplesCount: number = 50;
|
||||
const expectedEvaluationResult: string = 'aaabbbcccdddeee';
|
||||
let isEvaluationSuccessful: boolean = true;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-chained-calls-2.js');
|
||||
|
||||
for (let i = 0; i < samplesCount; i++) {
|
||||
const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
identifierNamesGenerator: IdentifierNamesGenerator.MangledIdentifierNamesGenerator,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayEncoding: [
|
||||
StringArrayEncoding.None,
|
||||
StringArrayEncoding.Rc4
|
||||
],
|
||||
stringArrayWrappersChainedCalls: true,
|
||||
stringArrayWrappersCount: 5
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
|
||||
const evaluationResult: string = eval(obfuscatedCode);
|
||||
|
||||
if (evaluationResult !== expectedEvaluationResult) {
|
||||
isEvaluationSuccessful = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
it('should correctly evaluate string array wrappers chained calls', () => {
|
||||
assert.equal(isEvaluationSuccessful, true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #4: string contains non-latin and non-digit characters and `unicodeEscapeSequence` is disabled', () => {
|
||||
describe('Variant #3: string contains non-latin and non-digit characters and `unicodeEscapeSequence` is disabled', () => {
|
||||
let testFunc: () => void;
|
||||
|
||||
before(() => {
|
||||
@@ -614,7 +84,7 @@ describe('StringArrayTransformer', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #5: same literal node values', () => {
|
||||
describe('Variant #4: same literal node values', () => {
|
||||
const stringArrayRegExp: RegExp = /^var _0x([a-f0-9]){4} *= *\['test'\];/;
|
||||
const stringArrayCallRegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\('0x0'\);/;
|
||||
|
||||
@@ -642,7 +112,7 @@ describe('StringArrayTransformer', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #6: `unicodeEscapeSequence` option is enabled', () => {
|
||||
describe('Variant #5: `unicodeEscapeSequence` option is enabled', () => {
|
||||
const regExp: RegExp = /^var test *= *'\\x74\\x65\\x73\\x74';$/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
@@ -665,7 +135,7 @@ describe('StringArrayTransformer', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #7: `unicodeEscapeSequence` and `stringArray` options are enabled', () => {
|
||||
describe('Variant #6: `unicodeEscapeSequence` and `stringArray` options are enabled', () => {
|
||||
const stringArrayRegExp: RegExp = /^var _0x([a-f0-9]){4} *= *\['\\x74\\x65\\x73\\x74'\];/;
|
||||
const stringArrayCallRegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\('\\x30\\x78\\x30'\);/;
|
||||
|
||||
@@ -694,7 +164,7 @@ describe('StringArrayTransformer', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #8: short literal node value', () => {
|
||||
describe('Variant #7: short literal node value', () => {
|
||||
const regExp: RegExp = /var test *= *'te';/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
@@ -717,7 +187,7 @@ describe('StringArrayTransformer', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #9: base64 encoding', () => {
|
||||
describe('Variant #8: base64 encoding', () => {
|
||||
const stringArrayRegExp: RegExp = new RegExp(`^var _0x([a-f0-9]){4} *= *\\['${swapLettersCase('dGVzdA==')}'];`);
|
||||
const stringArrayCallRegExp: RegExp = /var test *= *_0x([a-f0-9]){4}\('0x0'\);/;
|
||||
|
||||
@@ -746,7 +216,7 @@ describe('StringArrayTransformer', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #10: rc4 encoding', () => {
|
||||
describe('Variant #9: rc4 encoding', () => {
|
||||
describe('Variant #1: single string literal', () => {
|
||||
const regExp: RegExp = /var test *= *_0x([a-f0-9]){4}\('0x0', *'.{4}'\);/;
|
||||
|
||||
@@ -812,7 +282,7 @@ describe('StringArrayTransformer', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #11: none and base64 encoding', () => {
|
||||
describe('Variant #10: none and base64 encoding', () => {
|
||||
describe('Variant #1: string array values', () => {
|
||||
const samplesCount: number = 300;
|
||||
const expectedMatchesChance: number = 0.5;
|
||||
@@ -866,169 +336,9 @@ describe('StringArrayTransformer', function () {
|
||||
assert.closeTo(base64EncodingMatchesChance, expectedMatchesChance, expectedMatchesDelta);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: `stringArrayWrappersCount` option is enabled', () => {
|
||||
describe('Variant #1: root scope', () => {
|
||||
describe('Variant #1: `1` scope calls wrapper for each encoding type', () => {
|
||||
const stringArrayWrappersRegExp: RegExp = new RegExp(
|
||||
'return _0x([a-f0-9]){4,6};' +
|
||||
'};' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
// this one may be added or not depends on:
|
||||
// if all literal values encoded with a single encoding or not
|
||||
'(?:const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};)?' +
|
||||
'const foo *= *_0x([a-f0-9]){4,6}\\(\'0x0\'\\);' +
|
||||
'const bar *= *_0x([a-f0-9]){4,6}\\(\'0x1\'\\);' +
|
||||
'const baz *= *_0x([a-f0-9]){4,6}\\(\'0x2\'\\);'
|
||||
);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-count-const.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayEncoding: [
|
||||
StringArrayEncoding.None,
|
||||
StringArrayEncoding.Base64
|
||||
],
|
||||
stringArrayWrappersCount: 1,
|
||||
stringArrayThreshold: 1
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should add scope calls wrappers for both `none` and `base64` string array wrappers', () => {
|
||||
assert.match(obfuscatedCode, stringArrayWrappersRegExp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: `2` scope calls wrappers for each encoding type', () => {
|
||||
const stringArrayWrappersRegExp: RegExp = new RegExp(
|
||||
'return _0x([a-f0-9]){4,6};' +
|
||||
'};' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
// this one may be added or not depends on:
|
||||
// if all literal values encoded with a single encoding or not
|
||||
'(?:const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};)?' +
|
||||
'const foo *= *_0x([a-f0-9]){4,6}\\(\'0x0\'\\);' +
|
||||
'const bar *= *_0x([a-f0-9]){4,6}\\(\'0x1\'\\);' +
|
||||
'const baz *= *_0x([a-f0-9]){4,6}\\(\'0x2\'\\);'
|
||||
);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-count-const.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayEncoding: [
|
||||
StringArrayEncoding.None,
|
||||
StringArrayEncoding.Base64
|
||||
],
|
||||
stringArrayWrappersCount: 2,
|
||||
stringArrayThreshold: 1
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should add scope calls wrappers for both `none` and `base64` string array wrappers', () => {
|
||||
assert.match(obfuscatedCode, stringArrayWrappersRegExp);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: function scope', () => {
|
||||
describe('Variant #1: `1` scope calls wrapper for each encoding type', () => {
|
||||
const stringArrayWrappersRegExp: RegExp = new RegExp(
|
||||
'function test *\\( *\\) *{' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
// this one may be added or not depends on:
|
||||
// if all literal values encoded with a single encoding or not
|
||||
'(?:const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};)?' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x3\'\\);' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x4\'\\);' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x5\'\\);' +
|
||||
'}'
|
||||
);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-count-const.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayEncoding: [
|
||||
StringArrayEncoding.None,
|
||||
StringArrayEncoding.Base64
|
||||
],
|
||||
stringArrayWrappersCount: 1,
|
||||
stringArrayThreshold: 1
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should add scope calls wrappers for both `none` and `base64` string array wrappers', () => {
|
||||
assert.match(obfuscatedCode, stringArrayWrappersRegExp);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: `2` scope calls wrappers for each encoding type', () => {
|
||||
const stringArrayWrappersRegExp: RegExp = new RegExp(
|
||||
'function test *\\( *\\) *{' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};' +
|
||||
// this one may be added or not depends on:
|
||||
// if all literal values encoded with a single encoding or not
|
||||
'(?:const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4};)?' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x3\'\\);' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x4\'\\);' +
|
||||
'const _0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\\(\'0x5\'\\);' +
|
||||
'}'
|
||||
);
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-count-const.js');
|
||||
|
||||
obfuscatedCode = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayEncoding: [
|
||||
StringArrayEncoding.None,
|
||||
StringArrayEncoding.Base64
|
||||
],
|
||||
stringArrayWrappersCount: 2,
|
||||
stringArrayThreshold: 1
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
});
|
||||
|
||||
it('should add scope calls wrappers for both `none` and `base64` string array wrappers', () => {
|
||||
assert.match(obfuscatedCode, stringArrayWrappersRegExp);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #12: none and rc4 encoding', () => {
|
||||
describe('Variant #11: none and rc4 encoding', () => {
|
||||
describe('Variant #1: string array calls wrapper call', () => {
|
||||
const samplesCount: number = 300;
|
||||
const expectedMatchesChance: number = 0.5;
|
||||
@@ -1082,40 +392,9 @@ describe('StringArrayTransformer', function () {
|
||||
assert.closeTo(rc4EncodingMatchesChance, expectedMatchesChance, expectedMatchesDelta);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: `stringArrayWrappersCount` option is enabled', () => {
|
||||
describe('Variant #1: correct evaluation of the scope calls wrappers', () => {
|
||||
const expectedEvaluationResult: string = 'aaabbbcccdddeee';
|
||||
let evaluationResult: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-count-eval.js');
|
||||
|
||||
const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayEncoding: [
|
||||
StringArrayEncoding.None,
|
||||
StringArrayEncoding.Rc4
|
||||
],
|
||||
stringArrayWrappersCount: 5
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
|
||||
evaluationResult = eval(obfuscatedCode);
|
||||
});
|
||||
|
||||
it('should correctly evaluate scope calls wrappers', () => {
|
||||
assert.equal(evaluationResult, expectedEvaluationResult);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #13: base64 and rc4 encoding', () => {
|
||||
describe('Variant #12: base64 and rc4 encoding', () => {
|
||||
describe('Variant #1: single string literal', () => {
|
||||
const samplesCount: number = 300;
|
||||
const expectedMatchesChance: number = 0.5;
|
||||
@@ -1169,40 +448,9 @@ describe('StringArrayTransformer', function () {
|
||||
assert.closeTo(rc4EncodingMatchesChance, expectedMatchesChance, expectedMatchesDelta);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #2: `stringArrayWrappersCount` option is enabled', () => {
|
||||
describe('Variant #1: correct evaluation of the scope calls wrappers', () => {
|
||||
const expectedEvaluationResult: string = 'aaabbbcccdddeee';
|
||||
let evaluationResult: string;
|
||||
|
||||
before(() => {
|
||||
const code: string = readFileAsString(__dirname + '/fixtures/string-array-wrappers-count-eval.js');
|
||||
|
||||
const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
|
||||
code,
|
||||
{
|
||||
...NO_ADDITIONAL_NODES_PRESET,
|
||||
stringArray: true,
|
||||
stringArrayThreshold: 1,
|
||||
stringArrayEncoding: [
|
||||
StringArrayEncoding.Base64,
|
||||
StringArrayEncoding.Rc4
|
||||
],
|
||||
stringArrayWrappersCount: 5
|
||||
}
|
||||
).getObfuscatedCode();
|
||||
|
||||
evaluationResult = eval(obfuscatedCode);
|
||||
});
|
||||
|
||||
it('should correctly evaluate scope calls wrappers', () => {
|
||||
assert.equal(evaluationResult, expectedEvaluationResult);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #14: `stringArrayThreshold` option value', () => {
|
||||
describe('Variant #13: `stringArrayThreshold` option value', () => {
|
||||
const samples: number = 1000;
|
||||
const stringArrayThreshold: number = 0.5;
|
||||
const delta: number = 0.1;
|
||||
@@ -1245,7 +493,7 @@ describe('StringArrayTransformer', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #15: string array calls wrapper name', () => {
|
||||
describe('Variant #14: string array calls wrapper name', () => {
|
||||
const regExp: RegExp = /console\[b\('0x0'\)]\('a'\);/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
@@ -1269,7 +517,7 @@ describe('StringArrayTransformer', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #16: `reservedStrings` option is enabled', () => {
|
||||
describe('Variant #15: `reservedStrings` option is enabled', () => {
|
||||
describe('Variant #1: base `reservedStrings` values', () => {
|
||||
describe('Variant #1: single reserved string value', () => {
|
||||
const stringLiteralRegExp1: RegExp = /const foo *= *'foo';/;
|
||||
@@ -1441,7 +689,7 @@ describe('StringArrayTransformer', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #17: object expression key literal', () => {
|
||||
describe('Variant #16: object expression key literal', () => {
|
||||
describe('Variant #1: base key literal', () => {
|
||||
const stringArrayRegExp: RegExp = /^var _0x([a-f0-9]){4} *= *\['bar'];/;
|
||||
const objectExpressionRegExp: RegExp = /var test *= *{'foo' *: *_0x([a-f0-9]){4}\('0x0'\)};/;
|
||||
@@ -1499,7 +747,7 @@ describe('StringArrayTransformer', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #18: import declaration source literal', () => {
|
||||
describe('Variant #17: import declaration source literal', () => {
|
||||
const importDeclarationRegExp: RegExp = /import *{ *bar *} *from *'foo';/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
@@ -1522,7 +770,7 @@ describe('StringArrayTransformer', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #19: export all declaration source literal', () => {
|
||||
describe('Variant #18: export all declaration source literal', () => {
|
||||
const exportAllDeclarationRegExp: RegExp = /export *\* *from *'foo';/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
@@ -1545,7 +793,7 @@ describe('StringArrayTransformer', function () {
|
||||
});
|
||||
});
|
||||
|
||||
describe('Variant #20: export named declaration source literal', () => {
|
||||
describe('Variant #19: export named declaration source literal', () => {
|
||||
const exportNamedDeclarationRegExp: RegExp = /export *{ *bar *} *from *'foo';/;
|
||||
|
||||
let obfuscatedCode: string;
|
||||
|
||||
@@ -115,6 +115,7 @@ import './functional-tests/node-transformers/simplifying-transformers/expression
|
||||
import './functional-tests/node-transformers/simplifying-transformers/if-statement-simplify-transformer/IfStatementSimplifyTransformer.spec';
|
||||
import './functional-tests/node-transformers/simplifying-transformers/variable-declarations-merge-transformer/VariableDeclarationsMergeTransformer.spec';
|
||||
import './functional-tests/node-transformers/string-array-transformers/string-array-transformer/StringArrayTransformer.spec';
|
||||
import './functional-tests/node-transformers/string-array-transformers/string-array-scope-calls-wrapper-transformer/StringArrayScopeCallsWrapperTransformer.spec';
|
||||
import './functional-tests/options/OptionsNormalizer.spec';
|
||||
import './functional-tests/options/domain-lock/Validation.spec';
|
||||
import './functional-tests/storages/string-array-transformers/string-array-storage/StringArrayStorage.spec';
|
||||
|
||||
@@ -116,15 +116,15 @@ describe('ArrayUtils', () => {
|
||||
describe('getLastElement', () => {
|
||||
describe('empty array', () => {
|
||||
const array: string[] = [];
|
||||
const expectedLastElement: null = null;
|
||||
const expectedLastElement: undefined = undefined;
|
||||
|
||||
let lastElement: string | null;
|
||||
let lastElement: string | undefined;
|
||||
|
||||
before(() => {
|
||||
lastElement = arrayUtils.getLastElement(array);
|
||||
});
|
||||
|
||||
it('should return null if array is empty', () => {
|
||||
it('should return undefined if array is empty', () => {
|
||||
assert.equal(lastElement, expectedLastElement);
|
||||
});
|
||||
});
|
||||
@@ -133,7 +133,7 @@ describe('ArrayUtils', () => {
|
||||
const array: string[] = ['foo'];
|
||||
const expectedLastElement: string = 'foo';
|
||||
|
||||
let lastElement: string | null;
|
||||
let lastElement: string | undefined;
|
||||
|
||||
before(() => {
|
||||
lastElement = arrayUtils.getLastElement(array);
|
||||
@@ -148,7 +148,7 @@ describe('ArrayUtils', () => {
|
||||
const array: string[] = ['foo', 'bar', 'baz'];
|
||||
const expectedLastElement: string = 'baz';
|
||||
|
||||
let lastElement: string | null;
|
||||
let lastElement: string | undefined;
|
||||
|
||||
before(() => {
|
||||
lastElement = arrayUtils.getLastElement(array);
|
||||
|
||||
Reference in New Issue
Block a user