Merge pull request #667 from javascript-obfuscator/block-statement-simplify

Block statement simplify transformer
This commit is contained in:
Timofey Kachalov
2020-07-15 12:57:02 +03:00
committed by GitHub
26 changed files with 664 additions and 189 deletions
+4
View File
@@ -1,5 +1,9 @@
Change Log
v1.7.0
---
* `simplify` option now affects all block statements. Improved variable declarations merging.
v1.6.0
---
* **New option:** `numbersToExpressions` enables numbers conversion to expressions
+7 -7
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
File diff suppressed because one or more lines are too long
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "javascript-obfuscator",
"version": "1.6.0",
"version": "1.7.0",
"description": "JavaScript obfuscator",
"keywords": [
"obfuscator",
+1
View File
@@ -63,6 +63,7 @@ export class JavaScriptObfuscator implements IJavaScriptObfuscator {
*/
private static readonly nodeTransformersList: NodeTransformer[] = [
NodeTransformer.BlockStatementControlFlowTransformer,
NodeTransformer.BlockStatementSimplifyTransformer,
NodeTransformer.CommentsTransformer,
NodeTransformer.CustomCodeHelpersTransformer,
NodeTransformer.DeadCodeInjectionTransformer,
@@ -5,11 +5,16 @@ import { INodeTransformer } from '../../../interfaces/node-transformers/INodeTra
import { NodeTransformer } from '../../../enums/node-transformers/NodeTransformer';
import { BlockStatementSimplifyTransformer } from '../../../node-transformers/simplifying-transformers/BlockStatementSimplifyTransformer';
import { IfStatementSimplifyTransformer } from '../../../node-transformers/simplifying-transformers/IfStatementSimplifyTransformer';
import { VariableDeclarationsMergeTransformer } from '../../../node-transformers/simplifying-transformers/VariableDeclarationsMergeTransformer';
export const simplifyingTransformersModule: interfaces.ContainerModule = new ContainerModule((bind: interfaces.Bind) => {
// simplifying transformers
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(BlockStatementSimplifyTransformer)
.whenTargetNamed(NodeTransformer.BlockStatementSimplifyTransformer);
bind<INodeTransformer>(ServiceIdentifiers.INodeTransformer)
.to(IfStatementSimplifyTransformer)
.whenTargetNamed(NodeTransformer.IfStatementSimplifyTransformer);
@@ -1,5 +1,6 @@
export enum NodeTransformer {
BlockStatementControlFlowTransformer = 'BlockStatementControlFlowTransformer',
BlockStatementSimplifyTransformer = 'BlockStatementSimplifyTransformer',
CommentsTransformer = 'CommentsTransformer',
CustomCodeHelpersTransformer = 'CustomCodeHelpersTransformer',
DeadCodeInjectionTransformer = 'DeadCodeInjectionTransformer',
@@ -1,6 +1,6 @@
import * as ESTree from 'estree';
export interface IIfStatementIteratedStatementsData {
export interface IIteratedStatementsSimplifyData {
/**
* @type {number | null}
*/
@@ -1,6 +1,6 @@
import * as ESTree from 'estree';
export interface IIfStatementSimplifyData {
export interface IStatementSimplifyData {
/**
* @type {ESTree.Statement[]}
*/
@@ -0,0 +1,193 @@
import { inject, injectable, } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import * as ESTree from 'estree';
import { IIteratedStatementsSimplifyData } from '../../interfaces/node-transformers/simplifying-transformers/IIteratedStatementsSimplifyData';
import { IOptions } from '../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
import { IStatementSimplifyData } from '../../interfaces/node-transformers/simplifying-transformers/IStatementSimplifyData';
import { NodeTransformer } from '../../enums/node-transformers/NodeTransformer';
import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
import { NodeGuards } from '../../node/NodeGuards';
import { NodeFactory } from '../../node/NodeFactory';
/**
* Simplifies `Statement` node
*/
@injectable()
export abstract class AbstractStatementSimplifyTransformer extends AbstractNodeTransformer {
/**
* @type {NodeTransformer[]}
*/
public readonly runAfter: NodeTransformer[] = [
NodeTransformer.VariableDeclarationsMergeTransformer
];
/**
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
*/
protected constructor (
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
super(randomGenerator, options);
}
/**
* Returns IStatementSimplifyData based on `Statement` node
*
* @param {ESTree.Statement | null | undefined} statementNode
* @returns {IStatementSimplifyData | null}
*/
protected getStatementSimplifyData (
statementNode: ESTree.Statement | null | undefined
): IStatementSimplifyData | null {
if (!statementNode) {
return null;
}
if (!NodeGuards.isBlockStatementNode(statementNode)) {
return {
leadingStatements: [statementNode],
trailingStatement: null,
hasReturnStatement: false,
hasSingleExpression: false
};
}
const {
startIndex,
unwrappedExpressions,
hasReturnStatement
} = this.collectIteratedStatementsSimplifyData(statementNode);
const leadingStatements: ESTree.Statement[] = this.getLeadingStatements(statementNode, startIndex);
if (!unwrappedExpressions.length) {
return {
leadingStatements,
trailingStatement: null,
hasReturnStatement,
hasSingleExpression: false
};
}
const hasSingleExpression: boolean = unwrappedExpressions.length === 1;
const expression: ESTree.Expression = hasSingleExpression
? unwrappedExpressions[0]
: NodeFactory.sequenceExpressionNode(unwrappedExpressions);
const statement: ESTree.Statement = hasReturnStatement
? NodeFactory.returnStatementNode(expression)
: NodeFactory.expressionStatementNode(expression);
return {
leadingStatements,
trailingStatement: {
statement,
expression
},
hasReturnStatement,
hasSingleExpression
};
}
/**
* Iterates over `BlockStatement` node body and collects data
*
* @param {ESTree.Statement | null | undefined} statementNode
* @returns {IIteratedStatementsSimplifyData}
*/
protected collectIteratedStatementsSimplifyData (
statementNode: ESTree.BlockStatement
): IIteratedStatementsSimplifyData {
const statementNodeBodyLength: number = statementNode.body.length;
const unwrappedExpressions: ESTree.Expression[] = [];
let hasReturnStatement: boolean = false;
let startIndex: number | null = 0;
for (let i = 0; i < statementNodeBodyLength; i++) {
const statementBodyStatementNode: ESTree.Statement = statementNode.body[i];
if (startIndex === null) {
startIndex = i;
}
if (NodeGuards.isExpressionStatementNode(statementBodyStatementNode)) {
unwrappedExpressions.push(statementBodyStatementNode.expression);
continue;
}
if (
NodeGuards.isReturnStatementNode(statementBodyStatementNode)
&& statementBodyStatementNode.argument
) {
unwrappedExpressions.push(statementBodyStatementNode.argument);
hasReturnStatement = true;
continue;
}
startIndex = null;
unwrappedExpressions.length = 0;
}
return {
startIndex,
unwrappedExpressions,
hasReturnStatement
};
}
/**
* Returns leading statements
*
* @param {ESTree.BlockStatement} statementNode
* @param {number | null} startIndex
* @returns {ESTree.Statement[]}
*/
protected getLeadingStatements (statementNode: ESTree.BlockStatement, startIndex: number | null): ESTree.Statement[] {
// variant #1: no valid statements inside `BlockStatement` are found
if (startIndex === null) {
return statementNode.body;
}
return startIndex === 0
// variant #2: all statements inside `BlockStatement` branch are valid
? []
// variant #3: only last N statements inside `BlockStatement` branch are valid
: statementNode.body.slice(0, startIndex);
}
/**
* @param {IStatementSimplifyData} statementSimplifyData
* @returns {ESTree.Statement}
*/
protected getPartialStatement (statementSimplifyData: IStatementSimplifyData): ESTree.Statement {
// variant #1: all statements inside `BlockStatement` branch are valid
if (!statementSimplifyData.leadingStatements.length && statementSimplifyData.trailingStatement) {
return statementSimplifyData.trailingStatement.statement;
}
// variant #2: only last N statements inside `BlockStatement` branch are valid
return NodeFactory.blockStatementNode([
...statementSimplifyData.leadingStatements.length ? statementSimplifyData.leadingStatements : [],
...statementSimplifyData.trailingStatement ? [statementSimplifyData.trailingStatement.statement] : []
]);
}
/**
* @param {ESTree.Statement} statementNode
* @param {ESTree.Node} parentNode
* @returns {ESTree.Node}
*/
public abstract transformNode (
statementNode: ESTree.Statement,
parentNode: ESTree.Node
): ESTree.Node;
}
@@ -0,0 +1,87 @@
import { inject, injectable, } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import * as ESTree from 'estree';
import { IOptions } from '../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
import { IStatementSimplifyData } from '../../interfaces/node-transformers/simplifying-transformers/IStatementSimplifyData';
import { IVisitor } from '../../interfaces/node-transformers/IVisitor';
import { NodeTransformer } from '../../enums/node-transformers/NodeTransformer';
import { NodeTransformationStage } from '../../enums/node-transformers/NodeTransformationStage';
import { AbstractStatementSimplifyTransformer } from './AbstractStatementSimplifyTransformer';
import { NodeGuards } from '../../node/NodeGuards';
import { NodeFactory } from '../../node/NodeFactory';
import { NodeUtils } from '../../node/NodeUtils';
/**
* Simplifies `BlockStatement` node
*/
@injectable()
export class BlockStatementSimplifyTransformer extends AbstractStatementSimplifyTransformer {
/**
* @type {NodeTransformer[]}
*/
public readonly runAfter: NodeTransformer[] = [
NodeTransformer.VariableDeclarationsMergeTransformer
];
/**
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
*/
public constructor (
@inject(ServiceIdentifiers.IRandomGenerator) randomGenerator: IRandomGenerator,
@inject(ServiceIdentifiers.IOptions) options: IOptions
) {
super(randomGenerator, options);
}
/**
* @param {NodeTransformationStage} nodeTransformationStage
* @returns {IVisitor | null}
*/
public getVisitor (nodeTransformationStage: NodeTransformationStage): IVisitor | null {
switch (nodeTransformationStage) {
case NodeTransformationStage.Simplifying:
return {
leave: (
node: ESTree.Node,
parentNode: ESTree.Node | null
): ESTree.Node | undefined => {
if (parentNode && NodeGuards.isBlockStatementNode(node)) {
return this.transformNode(node, parentNode);
}
}
};
default:
return null;
}
}
/**
* @param {ESTree.Statement} statementNode
* @param {ESTree.Node} parentNode
* @returns {ESTree.Node}
*/
public transformNode (
statementNode: ESTree.Statement,
parentNode: ESTree.Node
): ESTree.Node {
const simplifyData: IStatementSimplifyData | null = this.getStatementSimplifyData(statementNode);
if (!simplifyData) {
return statementNode;
}
const partialStatementNode: ESTree.Statement = this.getPartialStatement(simplifyData);
const transformedNode: ESTree.Node = NodeGuards.isBlockStatementNode(partialStatementNode)
? partialStatementNode
: NodeFactory.blockStatementNode([partialStatementNode]);
return NodeUtils.parentizeNode(transformedNode, parentNode);
}
}
@@ -3,16 +3,14 @@ import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import * as ESTree from 'estree';
import { IIfStatementSimplifyData } from '../../interfaces/node-transformers/simplifying-transformers/IIfStatementSimplifyData';
import { IIfStatementIteratedStatementsData } from '../../interfaces/node-transformers/simplifying-transformers/IIfStatementIteratedStatementsData';
import { IOptions } from '../../interfaces/options/IOptions';
import { IRandomGenerator } from '../../interfaces/utils/IRandomGenerator';
import { IStatementSimplifyData } from '../../interfaces/node-transformers/simplifying-transformers/IStatementSimplifyData';
import { IVisitor } from '../../interfaces/node-transformers/IVisitor';
import { NodeTransformer } from '../../enums/node-transformers/NodeTransformer';
import { NodeTransformationStage } from '../../enums/node-transformers/NodeTransformationStage';
import { AbstractNodeTransformer } from '../AbstractNodeTransformer';
import { AbstractStatementSimplifyTransformer } from './AbstractStatementSimplifyTransformer';
import { NodeGuards } from '../../node/NodeGuards';
import { NodeFactory } from '../../node/NodeFactory';
import { NodeUtils } from '../../node/NodeUtils';
@@ -21,14 +19,7 @@ import { NodeUtils } from '../../node/NodeUtils';
* Simplifies `IfStatement` node
*/
@injectable()
export class IfStatementSimplifyTransformer extends AbstractNodeTransformer {
/**
* @type {NodeTransformer[]}
*/
public readonly runAfter: NodeTransformer[] = [
NodeTransformer.VariableDeclarationsMergeTransformer
];
export class IfStatementSimplifyTransformer extends AbstractStatementSimplifyTransformer {
/**
* @param {IRandomGenerator} randomGenerator
* @param {IOptions} options
@@ -72,7 +63,7 @@ export class IfStatementSimplifyTransformer extends AbstractNodeTransformer {
ifStatementNode: ESTree.IfStatement,
parentNode: ESTree.Node
): ESTree.Node {
const consequentSimplifyData: IIfStatementSimplifyData | null = this.getIfStatementSimplifyData(ifStatementNode.consequent);
const consequentSimplifyData: IStatementSimplifyData | null = this.getStatementSimplifyData(ifStatementNode.consequent);
// Variant #1: no valid consequent expression data
if (!consequentSimplifyData) {
@@ -85,7 +76,7 @@ export class IfStatementSimplifyTransformer extends AbstractNodeTransformer {
// Variant #2: valid data for consequent expression only
transformedNode = this.getConsequentNode(ifStatementNode, consequentSimplifyData);
} else {
const alternateSimplifyData: IIfStatementSimplifyData | null = this.getIfStatementSimplifyData(ifStatementNode.alternate);
const alternateSimplifyData: IStatementSimplifyData | null = this.getStatementSimplifyData(ifStatementNode.alternate);
if (!alternateSimplifyData) {
return ifStatementNode;
@@ -100,12 +91,12 @@ export class IfStatementSimplifyTransformer extends AbstractNodeTransformer {
/**
* @param {ESTree.IfStatement} ifStatementNode
* @param {IIfStatementSimplifyData} consequentSimplifyData
* @param {IStatementSimplifyData} consequentSimplifyData
* @returns {ESTree.Node}
*/
private getConsequentNode (
protected getConsequentNode (
ifStatementNode: ESTree.IfStatement,
consequentSimplifyData: IIfStatementSimplifyData
consequentSimplifyData: IStatementSimplifyData
): ESTree.Node {
/**
* Converts:
@@ -127,7 +118,7 @@ export class IfStatementSimplifyTransformer extends AbstractNodeTransformer {
) {
return NodeFactory.ifStatementNode(
ifStatementNode.test,
this.getPartialIfStatementBranchNode(consequentSimplifyData)
this.getPartialStatement(consequentSimplifyData)
);
}
@@ -168,14 +159,14 @@ export class IfStatementSimplifyTransformer extends AbstractNodeTransformer {
/**
* @param {ESTree.IfStatement} ifStatementNode
* @param {IIfStatementSimplifyData} consequentSimplifyData
* @param {IIfStatementSimplifyData} alternateSimplifyData
* @param {IStatementSimplifyData} consequentSimplifyData
* @param {IStatementSimplifyData} alternateSimplifyData
* @returns {ESTree.Node}
*/
private getConsequentAndAlternateNode (
protected getConsequentAndAlternateNode (
ifStatementNode: ESTree.IfStatement,
consequentSimplifyData: IIfStatementSimplifyData,
alternateSimplifyData: IIfStatementSimplifyData
consequentSimplifyData: IStatementSimplifyData,
alternateSimplifyData: IStatementSimplifyData
): ESTree.Node {
/**
* Converts:
@@ -199,8 +190,8 @@ export class IfStatementSimplifyTransformer extends AbstractNodeTransformer {
) {
return NodeFactory.ifStatementNode(
ifStatementNode.test,
this.getPartialIfStatementBranchNode(consequentSimplifyData),
this.getPartialIfStatementBranchNode(alternateSimplifyData)
this.getPartialStatement(consequentSimplifyData),
this.getPartialStatement(alternateSimplifyData)
);
}
@@ -268,152 +259,20 @@ export class IfStatementSimplifyTransformer extends AbstractNodeTransformer {
}
/**
* Returns IIfStatementSimplifyData based on `IfStatement` node body
*
* @param {ESTree.Statement | null | undefined} statementNode
* @returns {IIfStatementSimplifyData | null}
* @param {IStatementSimplifyData} statementSimplifyData
* @returns {ESTree.Statement}
*/
private getIfStatementSimplifyData (
statementNode: ESTree.Statement | null | undefined
): IIfStatementSimplifyData | null {
if (!statementNode) {
return null;
protected getPartialStatement (statementSimplifyData: IStatementSimplifyData): ESTree.Statement {
const partialStatement: ESTree.Statement = super.getPartialStatement(statementSimplifyData);
if (!NodeGuards.isBlockStatementNode(partialStatement)) {
return partialStatement;
}
if (!NodeGuards.isBlockStatementNode(statementNode)) {
return {
leadingStatements: [statementNode],
trailingStatement: null,
hasReturnStatement: false,
hasSingleExpression: false
};
}
const {
startIndex,
unwrappedExpressions,
hasReturnStatement
} = this.collectIteratedStatementsData(statementNode);
const leadingStatements: ESTree.Statement[] = this.getLeadingStatements(statementNode, startIndex);
if (!unwrappedExpressions.length) {
return {
leadingStatements,
trailingStatement: null,
hasReturnStatement,
hasSingleExpression: false
};
}
const hasSingleExpression: boolean = unwrappedExpressions.length === 1;
const expression: ESTree.Expression = hasSingleExpression
? unwrappedExpressions[0]
: NodeFactory.sequenceExpressionNode(unwrappedExpressions);
const statement: ESTree.Statement = hasReturnStatement
? NodeFactory.returnStatementNode(expression)
: NodeFactory.expressionStatementNode(expression);
return {
leadingStatements,
trailingStatement: {
statement,
expression
},
hasReturnStatement,
hasSingleExpression
};
}
/**
* Iterates over `IfStatement` node body and collects data
*
* @param {ESTree.Statement | null | undefined} statementNode
* @returns {IIfStatementIteratedStatementsData}
*/
private collectIteratedStatementsData (
statementNode: ESTree.BlockStatement
): IIfStatementIteratedStatementsData {
const statementNodeBodyLength: number = statementNode.body.length;
const unwrappedExpressions: ESTree.Expression[] = [];
let hasReturnStatement: boolean = false;
let startIndex: number | null = 0;
for (let i = 0; i < statementNodeBodyLength; i++) {
const statementBodyStatementNode: ESTree.Statement = statementNode.body[i];
if (startIndex === null) {
startIndex = i;
}
if (NodeGuards.isExpressionStatementNode(statementBodyStatementNode)) {
unwrappedExpressions.push(statementBodyStatementNode.expression);
continue;
}
if (
NodeGuards.isReturnStatementNode(statementBodyStatementNode)
&& statementBodyStatementNode.argument
) {
unwrappedExpressions.push(statementBodyStatementNode.argument);
hasReturnStatement = true;
continue;
}
startIndex = null;
unwrappedExpressions.length = 0;
}
return {
startIndex,
unwrappedExpressions,
hasReturnStatement
};
}
/**
* Returns leading statements for IIfStatementSimplifyData
*
* @param {ESTree.BlockStatement} statementNode
* @param {number | null} startIndex
* @returns {ESTree.Statement[]}
*/
private getLeadingStatements (statementNode: ESTree.BlockStatement, startIndex: number | null): ESTree.Statement[] {
// variant #1: no valid statements inside `IfStatement` are found
if (startIndex === null) {
return statementNode.body;
}
return startIndex === 0
// variant #2: all statements inside `IfStatement` branch are valid
? []
// variant #3: only last N statements inside `IfStatement` branch are valid
: statementNode.body.slice(0, startIndex);
}
/**
* @param {IIfStatementSimplifyData} ifStatementSimplifyData
* @returns {ESTree.BlockStatement}
*/
private getPartialIfStatementBranchNode (ifStatementSimplifyData: IIfStatementSimplifyData): ESTree.Statement {
// variant #1: all statements inside `IfStatement` branch are valid
if (!ifStatementSimplifyData.leadingStatements.length && ifStatementSimplifyData.trailingStatement) {
return ifStatementSimplifyData.trailingStatement.statement;
}
// variant #2: only last N statements inside `IfStatement` branch are valid
const blockStatementNode: ESTree.BlockStatement = NodeFactory.blockStatementNode([
...ifStatementSimplifyData.leadingStatements.length ? ifStatementSimplifyData.leadingStatements : [],
...ifStatementSimplifyData.trailingStatement ? [ifStatementSimplifyData.trailingStatement.statement] : []
]);
return blockStatementNode.body.length === 1
&& !this.isProhibitedSingleStatementForIfStatementBranch(blockStatementNode.body[0])
? blockStatementNode.body[0]
: blockStatementNode;
return partialStatement.body.length === 1
&& !this.isProhibitedSingleStatementForIfStatementBranch(partialStatement.body[0])
? partialStatement.body[0]
: partialStatement;
}
@@ -421,7 +280,7 @@ export class IfStatementSimplifyTransformer extends AbstractNodeTransformer {
* @param {ESTree.Statement} statement
* @returns {boolean}
*/
private isProhibitedSingleStatementForIfStatementBranch (statement: ESTree.Statement): boolean {
protected isProhibitedSingleStatementForIfStatementBranch (statement: ESTree.Statement): boolean {
/**
* Function declaration is not allowed outside of block in `strict` mode
*/
@@ -46,7 +46,7 @@ export class VariableDeclarationsMergeTransformer extends AbstractNodeTransforme
switch (nodeTransformationStage) {
case NodeTransformationStage.Simplifying:
return {
enter: (
leave: (
node: ESTree.Node,
parentNode: ESTree.Node | null
): ESTree.Node | estraverse.VisitorOption | undefined => {
+9 -7
View File
@@ -7,17 +7,19 @@ import { NO_ADDITIONAL_NODES_PRESET } from '../../src/options/presets/NoCustomNo
let obfuscatedCode: string = JavaScriptObfuscator.obfuscate(
`
const foo = 0..toString();
const bar = 'abc';
console.log(foo, bar);
var foo = function () {};
var bar = function () {
var baz = function () {};
var bark = function () {
var hawk = 1;
var dog = 2;
};
};
`,
{
...NO_ADDITIONAL_NODES_PRESET,
compact: false,
numbersToExpressions: true,
stringArray: true,
stringArrayThreshold: 1
simplify: true
}
).getObfuscatedCode();
@@ -0,0 +1,245 @@
import { assert } from 'chai';
import { NO_ADDITIONAL_NODES_PRESET } from '../../../../../src/options/presets/NoCustomNodes';
import { readFileAsString } from '../../../../helpers/readFileAsString';
import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscatorFacade';
describe('BlockStatementSimplifyTransformer', () => {
describe('Full `BlockStatement` simplify cases', () => {
describe('No `ReturnStatement`', () => {
describe('Variant #1: single statement', () => {
const regExp: RegExp = new RegExp(
'function foo *\\(\\) *{ *' +
'bar\\(\\); *' +
'}'
);
let obfuscatedCode: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/full-no-return-single-statement.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
simplify: true
}
).getObfuscatedCode();
});
it('should not simplify block statement', () => {
assert.match(obfuscatedCode, regExp);
});
});
describe('Variant #2: multiple statements', () => {
const regExp: RegExp = new RegExp(
'function foo *\\(\\) *{ *' +
'bar\\(\\), *baz\\(\\), *bark\\(\\); *' +
'}'
);
let obfuscatedCode: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/full-no-return-multiple-statements.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
simplify: true
}
).getObfuscatedCode();
});
it('should simplify block statement', () => {
assert.match(obfuscatedCode, regExp);
});
});
});
describe('With `ReturnStatement`', () => {
describe('Variant #1: single statement', () => {
const regExp: RegExp = new RegExp(
'function foo *\\(\\) *{ *' +
'return bar\\(\\); *' +
'}'
);
let obfuscatedCode: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/full-return-single-statement.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
simplify: true
}
).getObfuscatedCode();
});
it('should not simplify block statement', () => {
assert.match(obfuscatedCode, regExp);
});
});
describe('Variant #2: multiple statements', () => {
const regExp: RegExp = new RegExp(
'function foo *\\(\\) *{ *' +
'return bar\\(\\), *baz\\(\\), *bark\\(\\); *' +
'}'
);
let obfuscatedCode: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/full-return-multiple-statements.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
simplify: true
}
).getObfuscatedCode();
});
it('should simplify block statement', () => {
assert.match(obfuscatedCode, regExp);
});
});
});
});
describe('Partial `BlockStatement` simplify cases', () => {
describe('No `ReturnStatement`', () => {
describe('Variant #1: single statement', () => {
const regExp: RegExp = new RegExp(
'function foo *\\(\\) *{ *' +
'var _0x([a-f0-9]){4,6} *= *baz\\(\\);' +
'}'
);
let obfuscatedCode: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/partial-no-return-single-statement.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
simplify: true
}
).getObfuscatedCode();
});
it('should not simplify block statement', () => {
assert.match(obfuscatedCode, regExp);
});
});
describe('Variant #2: multiple statements', () => {
const regExp: RegExp = new RegExp(
'function foo *\\(\\) *{ *' +
'const _0x([a-f0-9]){4,6} *= *baz\\(\\); *' +
'bark\\(\\), *hawk\\(\\);' +
'}'
);
let obfuscatedCode: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/partial-no-return-multiple-statements.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
simplify: true
}
).getObfuscatedCode();
});
it('should simplify block statement', () => {
assert.match(obfuscatedCode, regExp);
});
});
});
describe('With `ReturnStatement`', () => {
describe('Variant #1: multiple statements', () => {
const regExp: RegExp = new RegExp(
'function foo *\\(\\) *{ *' +
'const _0x([a-f0-9]){4,6} *= *baz\\(\\); *' +
'return bark\\(\\), *hawk\\(\\);' +
'}'
);
let obfuscatedCode: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/partial-return-multiple-statements.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
simplify: true
}
).getObfuscatedCode();
});
it('should simplify block statement', () => {
assert.match(obfuscatedCode, regExp);
});
});
});
});
describe('Cases', () => {
describe('Variable declarations merge transformer integration', () => {
describe('Variant #1: three statements', () => {
const regExp: RegExp = new RegExp(
'function foo *\\(\\) *{ *' +
'var _0x([a-f0-9]){4,6} *= *function *\\(\\) *{}, *' +
'_0x([a-f0-9]){4,6} *= *function *\\(\\) *{}, *' +
'_0x([a-f0-9]){4,6} *= *function *\\(\\) *{}; *' +
'}'
);
let obfuscatedCode: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/variable-declarations-merge-transformer-integration-1.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
simplify: true
}
).getObfuscatedCode();
});
it('should simplify block statement', () => {
assert.match(obfuscatedCode, regExp);
});
});
});
});
});
@@ -0,0 +1,7 @@
function foo () {
const bar = baz();
bark();
return hawk();
}
@@ -0,0 +1,5 @@
function foo() {
var bar = function () {};
var baz = function () {};
var bark = function () {};
}
@@ -141,6 +141,38 @@ describe('VariableDeclarationsMergeTransformer', () => {
assert.match(obfuscatedCode, regExp);
});
});
describe('Variant #6: declarations inside nested function expressions', () => {
const regExp: RegExp = new RegExp(
'var foo *= *function *\\(\\) *{ *}, *' +
'bar *= *function *\\(\\) *{ *' +
'var _0x([a-f0-9]){4,6} *= *function *\\(\\) *{ *}, *' +
'_0x([a-f0-9]){4,6} *= *function *\\(\\) *{ *' +
'var _0x([a-f0-9]){4,6} *= *0x1, *' +
'_0x([a-f0-9]){4,6} *= *0x2; *' +
'}; *' +
'};'
);
let obfuscatedCode: string;
before(() => {
const code: string = readFileAsString(__dirname + '/fixtures/declarations-inside-nested-function-expressions.js');
obfuscatedCode = JavaScriptObfuscator.obfuscate(
code,
{
...NO_ADDITIONAL_NODES_PRESET,
simplify: true
}
).getObfuscatedCode();
});
it('should merge variable declarations', () => {
assert.match(obfuscatedCode, regExp);
});
});
});
describe('object pattern as initializer', () => {
@@ -0,0 +1,8 @@
var foo = function () {};
var bar = function () {
var baz = function () {};
var bark = function () {
var hawk = 1;
var dog = 2;
};
};