Merge branch 'dev' into yarn

Conflicts:
	dist/index.js
	package.json
	scripts/test-coveralls
	scripts/test-full
	scripts/test-mocha
This commit is contained in:
sanex3339
2017-01-20 16:54:57 +03:00
51 changed files with 1388 additions and 457 deletions
+13
View File
@@ -1,5 +1,18 @@
Change Log
===
v0.9.0-beta.2
---
* Transformers refactoring
v0.9.0-beta.1
---
* **New option:** `controlFlowFlattening` allows to enable/disable **Control Flow flattening**. Control flow flattening is a structure transformation of the source code that hinders program comprehension.
* **New option:** `controlFlowFlatteningThreshold` allows to set percentage of nodes that will affected by `controlFlowFlattening`.
* Better `es2015` support: correct obfuscation of `TemplateLiteral`, `ArrayPattern`, `AssignmentPattern` nodes.
* Obfuscation performance boost.
* Huge internal refactoring.
* Various bug fixes.
v0.8.6
---
* additional fixes for https://github.com/javascript-obfuscator/javascript-obfuscator/issues/29
+10 -8
View File
@@ -9,7 +9,7 @@
JavaScript obfuscator for Node.js is a free obfuscator with wide number of features which provides protection for your source code.
* without any limits and sending data to a server;
* compatible with ES6;
* compatible with `es2015`;
* tested on Angular2 bundle.
Online version: [javascriptobfuscator.herokuapp.com](https://javascriptobfuscator.herokuapp.com)
@@ -25,6 +25,8 @@ Example of obfuscated code: [gist.github.com](https://gist.github.com/sanex3339/
[![Build Status](https://travis-ci.org/javascript-obfuscator/javascript-obfuscator.svg?branch=master)](https://travis-ci.org/javascript-obfuscator/javascript-obfuscator)
[![Coverage Status](https://coveralls.io/repos/github/javascript-obfuscator/javascript-obfuscator/badge.svg?branch=master)](https://coveralls.io/github/javascript-obfuscator/javascript-obfuscator?branch=master)
*NOTE! the README on the master branch might not match that of the latest stable release!*
## :warning: Important
#####Obfuscate only the code that belongs to you.
@@ -122,7 +124,7 @@ For available options see [options](#options).
Usage:
```sh
javascript-obfuscator in.js [options]
javascript-obfuscator in.js -output out.js [options]
javascript-obfuscator in.js --output out.js [options]
```
If the destination path is not specified through `--output` option, obfuscated code will saved into input file directory with name like `INPUT_FILE_NAME-obfuscated.js`
@@ -409,7 +411,7 @@ Available values:
* `true` (`boolean`): encode `stringArray` values using `base64`
* `false` (`boolean`): don't encode `stringArray` values
* `'base64'` (`string`): encode `stringArray` values using `base64`
* `'rc4'` (`string`): encode `stringArray` values using `rc4`. **About 30-50% slower then `base64`, but more harder to get initial values.** It is recommended to disable [`unicodeEscapeSequence`](#unicodeescapesequence) option with `rc4` encoding to prevent very large size of obfuscated code.
* `'rc4'` (`string`): encode `stringArray` values using `rc4`. **About 30-50% slower than `base64`, but more harder to get initial values.** It is recommended to disable [`unicodeEscapeSequence`](#unicodeescapesequence) option with `rc4` encoding to prevent very large size of obfuscated code.
### `stringArrayThreshold`
Type: `number` Default: `0.8` Min: `0` Max: `1`
@@ -432,7 +434,7 @@ Unicode escape sequence increases code size greatly. It is recommended to disabl
## Preset Options
### High obfuscation, low performance
Performance will 50-100% slower then without obfuscation
Performance will 50-100% slower than without obfuscation
```javascript
{
@@ -453,7 +455,7 @@ Performance will 50-100% slower then without obfuscation
### Medium obfuscation, optimal performance
Performance will 30-35% slower then without obfuscation
Performance will 30-35% slower than without obfuscation
```javascript
{
@@ -474,7 +476,7 @@ Performance will 30-35% slower then without obfuscation
### Low obfuscation, High performance
Performance will slightly slower then without obfuscation
Performance will slightly slower than without obfuscation
```javascript
{
@@ -493,7 +495,7 @@ Performance will slightly slower then without obfuscation
```
## License
Copyright (C) 2016 [Timofey Kachalov](http://github.com/sanex3339).
Copyright (C) 2017 [Timofey Kachalov](http://github.com/sanex3339).
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
@@ -513,4 +515,4 @@ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+495 -258
View File
File diff suppressed because it is too large Load Diff
+7 -7
View File
@@ -1,6 +1,6 @@
{
"name": "javascript-obfuscator",
"version": "0.9.0-dev.10",
"version": "0.9.0-beta.2",
"description": "JavaScript obfuscator",
"keywords": [
"obfuscator",
@@ -29,7 +29,7 @@
"lodash": "4.17.4",
"mkdirp": "0.5.1",
"reflect-metadata": "0.1.9",
"source-map-support": "0.4.8",
"source-map-support": "0.4.10",
"string-template": "1.0.0",
"tslib": "1.5.0"
},
@@ -43,15 +43,15 @@
"@types/estree": "0.0.34",
"@types/lodash": "4.14.50",
"@types/mkdirp": "0.3.29",
"@types/mocha": "2.2.37",
"@types/mocha": "2.2.38",
"@types/node": "7.0.0",
"@types/sinon": "1.16.34",
"@types/string-template": "1.0.2",
"awesome-typescript-loader": "3.0.0-beta.18",
"babel-cli": "6.18.0",
"babel-cli": "6.22.1",
"babel-loader": "6.2.10",
"babel-plugin-transform-runtime": "6.15.0",
"babel-preset-es2015": "6.18.0",
"babel-plugin-transform-runtime": "6.22.0",
"babel-preset-es2015": "6.22.0",
"chai": "4.0.0-canary.1",
"coveralls": "2.11.15",
"istanbul": "1.1.0-alpha.1",
@@ -61,7 +61,7 @@
"tslint": "4.3.1",
"tslint-loader": "3.3.0",
"typescript": "2.1.5",
"webpack": "2.2.0-rc.4",
"webpack": "2.2.0",
"webpack-node-externals": "1.5.4"
},
"repository": {
+1
View File
@@ -1,5 +1,6 @@
#!/bin/bash
yarn run test:removeTmpDir &&
yarn run test:compile &&
$(yarn bin)/istanbul cover $(yarn bin)/_mocha -- test-tmp/test/index.spec.js --report lcovonly &&
cat ./coverage/lcov.info | $(yarn bin)/coveralls &&
+1
View File
@@ -1,5 +1,6 @@
#!/bin/bash
yarn run test:removeTmpDir &&
yarn run test:compile &&
node test-tmp/test/dev/dev.js &&
$(yarn bin)/istanbul cover $(yarn bin)/_mocha -- test-tmp/test/index.spec.js &&
+1
View File
@@ -1,5 +1,6 @@
#!/bin/bash
yarn run test:removeTmpDir &&
yarn run test:compile &&
$(yarn bin)/mocha test-tmp/test/index.spec.js &&
yarn run test:removeTmpDir
+81 -51
View File
@@ -6,18 +6,17 @@ import * as ESTree from 'estree';
import { TNodeTransformersFactory } from './types/container/TNodeTransformersFactory';
import { TVisitorDirection } from './types/TVisitorDirection';
import { TVisitorFunction } from './types/TVisitorFunction';
import { ICustomNodeGroup } from './interfaces/custom-nodes/ICustomNodeGroup';
import { IObfuscationEventEmitter } from './interfaces/event-emitters/IObfuscationEventEmitter';
import { IObfuscator } from './interfaces/IObfuscator';
import { IOptions } from './interfaces/options/IOptions';
import { INodeTransformer } from './interfaces/node-transformers/INodeTransformer';
import { IStackTraceAnalyzer } from './interfaces/stack-trace-analyzer/IStackTraceAnalyzer';
import { IStackTraceData } from './interfaces/stack-trace-analyzer/IStackTraceData';
import { IStorage } from './interfaces/storages/IStorage';
import { NodeTransformers } from './enums/container/NodeTransformers';
import { NodeType } from './enums/NodeType';
import { ObfuscationEvents } from './enums/ObfuscationEvents';
import { VisitorDirection } from './enums/VisitorDirection';
@@ -27,40 +26,34 @@ import { NodeUtils } from './node/NodeUtils';
@injectable()
export class Obfuscator implements IObfuscator {
/**
* @type {Map<string, NodeTransformers[]>}
* @type {NodeTransformers[]}
*/
private static readonly controlFlowTransformersMap: Map <string, NodeTransformers[]> = new Map([
[NodeType.BlockStatement, [NodeTransformers.BlockStatementControlFlowTransformer]],
[NodeType.FunctionDeclaration, [NodeTransformers.FunctionControlFlowTransformer]],
[NodeType.FunctionExpression, [NodeTransformers.FunctionControlFlowTransformer]]
]);
private static readonly controlFlowTransformersList: NodeTransformers[] = [
NodeTransformers.BlockStatementControlFlowTransformer,
NodeTransformers.FunctionControlFlowTransformer
];
/**
* @type {Map<string, NodeTransformers[]>}
* @type {NodeTransformers[]}
*/
private static readonly convertingTransformersMap: Map <string, NodeTransformers[]> = new Map([
[NodeType.MemberExpression, [NodeTransformers.MemberExpressionTransformer]],
[NodeType.MethodDefinition, [NodeTransformers.MethodDefinitionTransformer]],
[NodeType.TemplateLiteral, [NodeTransformers.TemplateLiteralTransformer]],
]);
private static readonly convertingTransformersList: NodeTransformers[] = [
NodeTransformers.MemberExpressionTransformer,
NodeTransformers.MethodDefinitionTransformer,
NodeTransformers.TemplateLiteralTransformer
];
/**
* @type {Map<string, NodeTransformers[]>}
* @type {NodeTransformers[]}
*/
private static readonly obfuscatingTransformersMap: Map <string, NodeTransformers[]> = new Map([
[NodeType.ArrowFunctionExpression, [NodeTransformers.FunctionTransformer]],
[NodeType.ClassDeclaration, [NodeTransformers.FunctionDeclarationTransformer]],
[NodeType.CatchClause, [NodeTransformers.CatchClauseTransformer]],
[NodeType.FunctionDeclaration, [
NodeTransformers.FunctionDeclarationTransformer,
NodeTransformers.FunctionTransformer
]],
[NodeType.FunctionExpression, [NodeTransformers.FunctionTransformer]],
[NodeType.ObjectExpression, [NodeTransformers.ObjectExpressionTransformer]],
[NodeType.VariableDeclaration, [NodeTransformers.VariableDeclarationTransformer]],
[NodeType.LabeledStatement, [NodeTransformers.LabeledStatementTransformer]],
[NodeType.Literal, [NodeTransformers.LiteralTransformer]]
]);
private static readonly obfuscatingTransformersList: NodeTransformers[] = [
NodeTransformers.CatchClauseTransformer,
NodeTransformers.FunctionDeclarationTransformer,
NodeTransformers.FunctionTransformer,
NodeTransformers.LabeledStatementTransformer,
NodeTransformers.LiteralTransformer,
NodeTransformers.ObjectExpressionTransformer,
NodeTransformers.VariableDeclarationTransformer
];
/**
* @type {IStorage<ICustomNodeGroup>}
@@ -139,21 +132,17 @@ export class Obfuscator implements IObfuscator {
if (this.options.controlFlowFlattening) {
astTree = this.transformAstTree(
astTree,
VisitorDirection.leave,
this.nodeTransformersFactory(Obfuscator.controlFlowTransformersMap)
Obfuscator.controlFlowTransformersList
);
}
// second pass: nodes obfuscation
astTree = this.transformAstTree(
astTree,
VisitorDirection.enter,
this.nodeTransformersFactory(
new Map([
...Obfuscator.convertingTransformersMap,
...Obfuscator.obfuscatingTransformersMap
])
)
[
...Obfuscator.convertingTransformersList,
...Obfuscator.obfuscatingTransformersList
]
);
this.obfuscationEventEmitter.emit(ObfuscationEvents.AfterObfuscation, astTree, stackTraceData);
@@ -163,26 +152,67 @@ export class Obfuscator implements IObfuscator {
/**
* @param astTree
* @param direction
* @param nodeTransformersConcreteFactory
* @param nodeTransformers
*/
private transformAstTree (
astTree: ESTree.Program,
direction: TVisitorDirection,
nodeTransformersConcreteFactory: (nodeType: string) => INodeTransformer[]
nodeTransformers: NodeTransformers[]
): ESTree.Program {
const visitors: estraverse.Visitor[] = nodeTransformers
.map((nodeTransformer: NodeTransformers): estraverse.Visitor => {
return this.nodeTransformersFactory(nodeTransformer).getVisitor();
});
estraverse.replace(astTree, {
[direction]: (node: ESTree.Node, parentNode: ESTree.Node): ESTree.Node => {
const nodeTransformers: INodeTransformer[] = nodeTransformersConcreteFactory(node.type);
nodeTransformers.forEach((nodeTransformer: INodeTransformer) => {
node = nodeTransformer.transformNode(node, parentNode);
});
return node;
}
enter: this.mergeVisitorsForDirection(
visitors.filter((visitor: estraverse.Visitor) => visitor.enter !== undefined),
VisitorDirection.enter
),
leave: this.mergeVisitorsForDirection(
visitors.filter((visitor: estraverse.Visitor) => visitor.leave !== undefined),
VisitorDirection.leave
)
});
return astTree;
}
/**
* @param visitors
* @param direction
* @return {TVisitorDirection}
*/
private mergeVisitorsForDirection (visitors: estraverse.Visitor[], direction: TVisitorDirection): TVisitorFunction {
if (!visitors.length) {
return (node: ESTree.Node, parentNode: ESTree.Node) => node;
}
return (node: ESTree.Node, parentNode: ESTree.Node) => {
for (const visitor of visitors) {
const visitorFunction: TVisitorFunction | undefined = visitor[direction];
if (!visitorFunction) {
continue;
}
const visitorResult: estraverse.VisitorOption | ESTree.Node | void = visitorFunction(node, parentNode);
if (!visitorResult) {
continue;
}
if (
visitorResult === estraverse.VisitorOption.Break ||
visitorResult === estraverse.VisitorOption.Remove ||
visitorResult === estraverse.VisitorOption.Skip
) {
return visitorResult;
}
node = <ESTree.Node>visitorResult;
}
return node;
};
}
}
@@ -72,31 +72,24 @@ export const nodeTransformersModule: interfaces.ContainerModule = new ContainerM
.whenTargetNamed(NodeTransformers.VariableDeclarationTransformer);
// node transformers factory
bind<INodeTransformer[]>(ServiceIdentifiers.Factory__INodeTransformer)
.toFactory<INodeTransformer[]>((context: interfaces.Context) => {
bind<INodeTransformer>(ServiceIdentifiers.Factory__INodeTransformer)
.toFactory<INodeTransformer>((context: interfaces.Context) => {
const cache: Map <NodeTransformers, INodeTransformer> = new Map();
return (nodeTransformersMap: Map<string, NodeTransformers[]>) => (nodeType: string) => {
const nodeTransformers: NodeTransformers[] = nodeTransformersMap.get(nodeType) || [];
const instancesArray: INodeTransformer[] = [];
return (nodeTransformerName: NodeTransformers) => {
if (cache.has(nodeTransformerName)) {
return <INodeTransformer>cache.get(nodeTransformerName);
}
nodeTransformers.forEach((transformer: NodeTransformers) => {
let nodeTransformer: INodeTransformer;
const nodeTransformer: INodeTransformer = context.container
.getNamed<INodeTransformer>(
ServiceIdentifiers.INodeTransformer,
nodeTransformerName
);
if (cache.has(transformer)) {
nodeTransformer = <INodeTransformer>cache.get(transformer);
} else {
nodeTransformer = context.container.getNamed<INodeTransformer>(
ServiceIdentifiers.INodeTransformer,
transformer
);
cache.set(transformer, nodeTransformer);
}
cache.set(nodeTransformerName, nodeTransformer);
instancesArray.push(nodeTransformer);
});
return instancesArray;
return nodeTransformer;
};
});
});
+1 -2
View File
@@ -4,9 +4,8 @@ import * as ESTree from 'estree';
declare module 'estree' {
interface BaseNode {
obfuscated?: boolean;
obfuscatedNode?: boolean;
parentNode?: ESTree.Node;
skippedByControlFlow?: boolean;
}
interface SimpleLiteral extends ESTree.BaseNode, ESTree.BaseExpression {
+2
View File
@@ -4,6 +4,7 @@ export const NodeType: any = Utils.strEnumify({
ArrayExpression: 'ArrayExpression',
ArrowFunctionExpression: 'ArrowFunctionExpression',
AssignmentExpression: 'AssignmentExpression',
AssignmentPattern: 'AssignmentPattern',
BinaryExpression: 'BinaryExpression',
BlockStatement: 'BlockStatement',
BreakStatement: 'BreakStatement',
@@ -22,6 +23,7 @@ export const NodeType: any = Utils.strEnumify({
MemberExpression: 'MemberExpression',
MethodDefinition: 'MethodDefinition',
ObjectExpression: 'ObjectExpression',
ObjectPattern: 'ObjectPattern',
Program: 'Program',
Property: 'Property',
ReturnStatement: 'ReturnStatement',
@@ -1,6 +1,12 @@
import * as estraverse from 'estraverse';
import * as ESTree from 'estree';
export interface INodeTransformer {
/**
* @returns {estraverse.Visitor}
*/
getVisitor (): estraverse.Visitor;
/**
* @param node
* @param parentNode
+1 -1
View File
@@ -43,7 +43,7 @@ export interface IStorage <T> extends IInitializable {
* @param key
* @param value
*/
set (key: string | number | null, value: T): void;
set (key: string | number, value: T): void;
/**
* @returns string
@@ -1,6 +1,7 @@
import { injectable, inject } from 'inversify';
import { ServiceIdentifiers } from '../container/ServiceIdentifiers';
import * as estraverse from 'estraverse';
import * as ESTree from 'estree';
import { INodeTransformer } from '../interfaces/node-transformers/INodeTransformer';
@@ -29,6 +30,11 @@ export abstract class AbstractNodeTransformer implements INodeTransformer {
this.options = options;
}
/**
* @returns {estraverse.Visitor}
*/
public abstract getVisitor (): estraverse.Visitor;
/**
* @param node
* @param parentNode
@@ -1,6 +1,7 @@
import { injectable, inject } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import * as estraverse from 'estraverse';
import * as ESTree from 'estree';
import { TCustomNodeFactory } from '../../types/container/TCustomNodeFactory';
@@ -49,11 +50,25 @@ export class BlockStatementControlFlowTransformer extends AbstractNodeTransforme
});
}
/**
* @return {estraverse.Visitor}
*/
public getVisitor (): estraverse.Visitor {
return {
leave: (node: ESTree.Node, parentNode: ESTree.Node) => {
if (Node.isBlockStatementNode(node)) {
return this.transformNode(node, parentNode);
}
}
};
}
/**
* @param blockStatementNode
* @param parentNode
* @returns {ESTree.Node}
*/
public transformNode (blockStatementNode: ESTree.BlockStatement): ESTree.Node {
public transformNode (blockStatementNode: ESTree.BlockStatement, parentNode: ESTree.Node): ESTree.Node {
if (
RandomGeneratorUtils.getRandomFloat(0, 1) > this.options.controlFlowFlatteningThreshold ||
BlockStatementControlFlowTransformer.blockStatementHasProhibitedStatements(blockStatementNode)
@@ -112,11 +112,25 @@ export class FunctionControlFlowTransformer extends AbstractNodeTransformer {
return RandomGeneratorUtils.getRandomGenerator().pickone(blockScopesOfNode);
}
/**
* @return {estraverse.Visitor}
*/
public getVisitor (): estraverse.Visitor {
return {
leave: (node: ESTree.Node, parentNode: ESTree.Node) => {
if (Node.isFunctionDeclarationNode(node) || Node.isFunctionExpressionNode(node)) {
return this.transformNode(node, parentNode);
}
}
};
}
/**
* @param functionNode
* @param parentNode
* @returns {ESTree.Node}
*/
public transformNode (functionNode: ESTree.Function): ESTree.Node {
public transformNode (functionNode: ESTree.Function, parentNode: ESTree.Node): ESTree.Node {
if (Node.isArrowFunctionExpressionNode(functionNode)) {
return functionNode;
}
@@ -1,6 +1,7 @@
import { injectable, inject } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import * as estraverse from 'estraverse';
import * as ESTree from 'estree';
import { IOptions } from '../../interfaces/options/IOptions';
@@ -21,6 +22,19 @@ export class MemberExpressionTransformer extends AbstractNodeTransformer {
super(options);
}
/**
* @return {estraverse.Visitor}
*/
public getVisitor (): estraverse.Visitor {
return {
enter: (node: ESTree.Node, parentNode: ESTree.Node) => {
if (Node.isMemberExpressionNode(node)) {
return this.transformNode(node, parentNode);
}
}
};
}
/**
* replaces:
* object.identifier = 1;
@@ -34,9 +48,10 @@ export class MemberExpressionTransformer extends AbstractNodeTransformer {
* Literal node will be obfuscated by LiteralTransformer
*
* @param memberExpressionNode
* @param parentNode
* @returns {ESTree.Node}
*/
public transformNode (memberExpressionNode: ESTree.MemberExpression): ESTree.Node {
public transformNode (memberExpressionNode: ESTree.MemberExpression, parentNode: ESTree.Node): ESTree.Node {
if (Node.isIdentifierNode(memberExpressionNode.property)) {
if (memberExpressionNode.computed) {
return memberExpressionNode;
@@ -1,6 +1,7 @@
import { injectable, inject } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import * as estraverse from 'estraverse';
import * as ESTree from 'estree';
import { IOptions } from '../../interfaces/options/IOptions';
@@ -35,6 +36,19 @@ export class MethodDefinitionTransformer extends AbstractNodeTransformer {
super(options);
}
/**
* @return {estraverse.Visitor}
*/
public getVisitor (): estraverse.Visitor {
return {
enter: (node: ESTree.Node, parentNode: ESTree.Node) => {
if (Node.isMethodDefinitionNode(node)) {
return this.transformNode(node, parentNode);
}
}
};
}
/**
* replaces:
* object.identifier = 1;
@@ -1,6 +1,7 @@
import { injectable, inject } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import * as estraverse from 'estraverse';
import * as ESTree from 'estree';
import { IOptions } from '../../interfaces/options/IOptions';
@@ -32,6 +33,19 @@ export class TemplateLiteralTransformer extends AbstractNodeTransformer {
return node && Node.isLiteralNode(node) && typeof node.value === 'string';
}
/**
* @return {estraverse.Visitor}
*/
public getVisitor (): estraverse.Visitor {
return {
enter: (node: ESTree.Node, parentNode: ESTree.Node) => {
if (Node.isTemplateLiteralNode(node)) {
return this.transformNode(node, parentNode);
}
}
};
}
/**
* @param templateLiteralNode
* @param parentNode
@@ -41,11 +41,25 @@ export class CatchClauseTransformer extends AbstractNodeTransformer {
this.identifierReplacer = <IObfuscationReplacerWithStorage>replacersFactory(NodeObfuscatorsReplacers.IdentifierReplacer);
}
/**
* @return {estraverse.Visitor}
*/
public getVisitor (): estraverse.Visitor {
return {
enter: (node: ESTree.Node, parentNode: ESTree.Node) => {
if (Node.isCatchClauseNode(node)) {
return this.transformNode(node, parentNode);
}
}
};
}
/**
* @param catchClauseNode
* @param parentNode
* @returns {ESTree.Node}
*/
public transformNode (catchClauseNode: ESTree.CatchClause): ESTree.Node {
public transformNode (catchClauseNode: ESTree.CatchClause, parentNode: ESTree.Node): ESTree.Node {
const nodeIdentifier: number = this.nodeIdentifier++;
this.storeCatchClauseParam(catchClauseNode, nodeIdentifier);
@@ -76,7 +90,7 @@ export class CatchClauseTransformer extends AbstractNodeTransformer {
if (node.name !== newNodeName) {
node.name = newNodeName;
node.obfuscated = true;
node.obfuscatedNode = true;
}
}
}
@@ -51,6 +51,19 @@ export class FunctionDeclarationTransformer extends AbstractNodeTransformer {
this.identifierReplacer = <IObfuscationReplacerWithStorage>nodeObfuscatorsReplacersFactory(NodeObfuscatorsReplacers.IdentifierReplacer);
}
/**
* @return {estraverse.Visitor}
*/
public getVisitor (): estraverse.Visitor {
return {
enter: (node: ESTree.Node, parentNode: ESTree.Node) => {
if (Node.isFunctionDeclarationNode(node)) {
return this.transformNode(node, parentNode);
}
}
};
}
/**
* @param functionDeclarationNode
* @param parentNode
@@ -41,11 +41,29 @@ export class FunctionTransformer extends AbstractNodeTransformer {
this.identifierReplacer = <IObfuscationReplacerWithStorage>nodeObfuscatorsReplacersFactory(NodeObfuscatorsReplacers.IdentifierReplacer);
}
/**
* @return {estraverse.Visitor}
*/
public getVisitor (): estraverse.Visitor {
return {
enter: (node: ESTree.Node, parentNode: ESTree.Node) => {
if (
Node.isFunctionDeclarationNode(node) ||
Node.isFunctionExpressionNode(node) ||
Node.isArrowFunctionExpressionNode(node)
) {
return this.transformNode(node, parentNode);
}
}
};
}
/**
* @param functionNode
* @param parentNode
* @returns {ESTree.Node}
*/
public transformNode (functionNode: ESTree.Function): ESTree.Node {
public transformNode (functionNode: ESTree.Function, parentNode: ESTree.Node): ESTree.Node {
const nodeIdentifier: number = this.nodeIdentifier++;
this.storeFunctionParams(functionNode, nodeIdentifier);
@@ -61,9 +79,23 @@ export class FunctionTransformer extends AbstractNodeTransformer {
private storeFunctionParams (functionNode: ESTree.Function, nodeIdentifier: number): void {
functionNode.params
.forEach((paramsNode: ESTree.Node) => {
if (Node.isIdentifierNode(paramsNode)) {
this.identifierReplacer.storeNames(paramsNode.name, nodeIdentifier);
if (Node.isObjectPatternNode(paramsNode)) {
return estraverse.VisitorOption.Skip;
}
estraverse.traverse(paramsNode, {
enter: (node: ESTree.Node): any => {
if (Node.isAssignmentPatternNode(node) && Node.isIdentifierNode(node.left)) {
this.identifierReplacer.storeNames(node.left.name, nodeIdentifier);
return estraverse.VisitorOption.Skip;
}
if (Node.isIdentifierNode(node)) {
this.identifierReplacer.storeNames(node.name, nodeIdentifier);
}
}
});
});
}
@@ -79,7 +111,7 @@ export class FunctionTransformer extends AbstractNodeTransformer {
if (node.name !== newNodeName) {
node.name = newNodeName;
node.obfuscated = true;
node.obfuscatedNode = true;
}
}
}
@@ -49,11 +49,25 @@ export class LabeledStatementTransformer extends AbstractNodeTransformer {
this.identifierReplacer = <IObfuscationReplacerWithStorage>nodeObfuscatorsReplacersFactory(NodeObfuscatorsReplacers.IdentifierReplacer);
}
/**
* @return {estraverse.Visitor}
*/
public getVisitor (): estraverse.Visitor {
return {
enter: (node: ESTree.Node, parentNode: ESTree.Node) => {
if (Node.isLabeledStatementNode(node)) {
return this.transformNode(node, parentNode);
}
}
};
}
/**
* @param labeledStatementNode
* @param parentNode
* @returns {ESTree.Node}
*/
public transformNode (labeledStatementNode: ESTree.LabeledStatement): ESTree.Node {
public transformNode (labeledStatementNode: ESTree.LabeledStatement, parentNode: ESTree.Node): ESTree.Node {
const nodeIdentifier: number = this.nodeIdentifier++;
this.storeLabeledStatementName(labeledStatementNode, nodeIdentifier);
@@ -2,6 +2,7 @@ import { injectable, inject } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import * as escodegen from 'escodegen';
import * as estraverse from 'estraverse';
import * as ESTree from 'estree';
import { IOptions } from '../../interfaces/options/IOptions';
@@ -32,6 +33,19 @@ export class LiteralTransformer extends AbstractNodeTransformer {
this.replacersFactory = replacersFactory;
}
/**
* @return {estraverse.Visitor}
*/
public getVisitor (): estraverse.Visitor {
return {
enter: (node: ESTree.Node, parentNode: ESTree.Node) => {
if (Node.isLiteralNode(node)) {
return this.transformNode(node, parentNode);
}
}
};
}
/**
* @param literalNode
* @param parentNode
@@ -2,6 +2,7 @@ import { injectable, inject } from 'inversify';
import { ServiceIdentifiers } from '../../container/ServiceIdentifiers';
import * as escodegen from 'escodegen';
import * as estraverse from 'estraverse';
import * as ESTree from 'estree';
import { IOptions } from '../../interfaces/options/IOptions';
@@ -64,11 +65,25 @@ export class ObjectExpressionTransformer extends AbstractNodeTransformer {
};
}
/**
* @return {estraverse.Visitor}
*/
public getVisitor (): estraverse.Visitor {
return {
enter: (node: ESTree.Node, parentNode: ESTree.Node) => {
if (Node.isObjectExpressionNode(node)) {
return this.transformNode(node, parentNode);
}
}
};
}
/**
* @param objectExpressionNode
* @param parentNode
* @returns {ESTree.Node}
*/
public transformNode (objectExpressionNode: ESTree.ObjectExpression): ESTree.Node {
public transformNode (objectExpressionNode: ESTree.ObjectExpression, parentNode: ESTree.Node): ESTree.Node {
objectExpressionNode.properties
.forEach((property: ESTree.Property) => {
if (property.shorthand) {
@@ -52,6 +52,19 @@ export class VariableDeclarationTransformer extends AbstractNodeTransformer {
this.identifierReplacer = <IObfuscationReplacerWithStorage>replacersFactory(NodeObfuscatorsReplacers.IdentifierReplacer);
}
/**
* @return {estraverse.Visitor}
*/
public getVisitor (): estraverse.Visitor {
return {
enter: (node: ESTree.Node, parentNode: ESTree.Node) => {
if (Node.isVariableDeclarationNode(node)) {
return this.transformNode(node, parentNode);
}
}
};
}
/**
* @param variableDeclarationNode
* @param parentNode
@@ -83,9 +96,13 @@ export class VariableDeclarationTransformer extends AbstractNodeTransformer {
private storeVariableNames (variableDeclarationNode: ESTree.VariableDeclaration, nodeIdentifier: number): void {
variableDeclarationNode.declarations
.forEach((declarationNode: ESTree.VariableDeclarator) => {
if (Node.isIdentifierNode(declarationNode.id)) {
this.identifierReplacer.storeNames(declarationNode.id.name, nodeIdentifier);
if (Node.isObjectPatternNode(declarationNode.id)) {
return estraverse.VisitorOption.Skip;
}
NodeUtils.typedTraverse(declarationNode.id, NodeType.Identifier, {
enter: (node: ESTree.Identifier) => this.identifierReplacer.storeNames(node.name, nodeIdentifier)
});
});
}
@@ -111,7 +128,7 @@ export class VariableDeclarationTransformer extends AbstractNodeTransformer {
estraverse.replace(scopeNode, {
enter: (node: ESTree.Node, parentNode: ESTree.Node): any => {
if (!node.obfuscated && Node.isReplaceableIdentifierNode(node, parentNode)) {
if (!node.obfuscatedNode && Node.isReplaceableIdentifierNode(node, parentNode)) {
const newNodeName: string = this.identifierReplacer.replace(node.name, nodeIdentifier);
if (node.name !== newNodeName) {
@@ -102,10 +102,10 @@ export class StringLiteralReplacer extends AbstractReplacer {
return <string>this.stringLiteralHexadecimalIndexCache.get(value);
}
const indexOfValue: number = this.stringArrayStorage.getLength();
const hexadecimalIndex: string = `${Utils.hexadecimalPrefix}${Utils.decToHex(indexOfValue)}`;
const stringArrayStorageLength: number = this.stringArrayStorage.getLength();
const hexadecimalIndex: string = `${Utils.hexadecimalPrefix}${Utils.decToHex(stringArrayStorageLength)}`;
this.stringArrayStorage.set(null, value);
this.stringArrayStorage.set(stringArrayStorageLength, value);
this.stringLiteralHexadecimalIndexCache.set(value, hexadecimalIndex);
return hexadecimalIndex;
+41
View File
@@ -13,6 +13,14 @@ export class Node {
return node.type === NodeType.ArrowFunctionExpression;
}
/**
* @param node
* @returns {boolean}
*/
public static isAssignmentPatternNode (node: ESTree.Node): node is ESTree.AssignmentPattern {
return node.type === NodeType.AssignmentPattern;
}
/**
* @param node
* @returns {boolean}
@@ -37,6 +45,14 @@ export class Node {
return node.type === NodeType.CallExpression;
}
/**
* @param node
* @returns {boolean}
*/
public static isCatchClauseNode (node: ESTree.Node): node is ESTree.CatchClause {
return node.type === NodeType.CatchClause;
}
/**
* @param node
* @returns {boolean}
@@ -122,6 +138,22 @@ export class Node {
return node.type === NodeType.MemberExpression;
}
/**
* @param node
* @returns {boolean}
*/
public static isMethodDefinitionNode (node: ESTree.Node): node is ESTree.MethodDefinition {
return node.type === NodeType.MethodDefinition;
}
/**
* @param node
* @returns {boolean}
*/
public static isObjectPatternNode (node: ESTree.Node): node is ESTree.ObjectPattern {
return node.type === NodeType.ObjectPattern;
}
/**
* @param node
* @returns {boolean}
@@ -168,6 +200,15 @@ export class Node {
return !parentNodeIsPropertyNode && !parentNodeIsMemberExpressionNode && !Node.isLabelIdentifierNode(node, parentNode);
}
/**
*
* @param node
* @returns {boolean}
*/
public static isTemplateLiteralNode (node: ESTree.Node): node is ESTree.TemplateLiteral {
return node.type === NodeType.TemplateLiteral;
}
/**
*
* @param node
+1 -1
View File
@@ -177,7 +177,7 @@ export class NodeUtils {
}
node.parentNode = value;
node.obfuscated = false;
node.obfuscatedNode = false;
}
});
+27 -27
View File
@@ -15,7 +15,7 @@ export class Nodes {
type: NodeType.Program,
body,
sourceType: 'script',
obfuscated: false
obfuscatedNode: false
};
}
@@ -35,7 +35,7 @@ export class Nodes {
operator,
left,
right,
obfuscated: false
obfuscatedNode: false
};
}
@@ -55,7 +55,7 @@ export class Nodes {
operator,
left,
right,
obfuscated: false
obfuscatedNode: false
};
}
@@ -67,7 +67,7 @@ export class Nodes {
return {
type: NodeType.BlockStatement,
body,
obfuscated: false
obfuscatedNode: false
};
}
@@ -78,7 +78,7 @@ export class Nodes {
public static getBreakStatement (label?: ESTree.Identifier): ESTree.BreakStatement {
const breakStatementNode: ESTree.BreakStatement = {
type: NodeType.BreakStatement,
obfuscated: false
obfuscatedNode: false
};
if (label) {
@@ -97,7 +97,7 @@ export class Nodes {
type: NodeType.CatchClause,
param: Nodes.getIdentifierNode('err'),
body: Nodes.getBlockStatementNode(body),
obfuscated: false
obfuscatedNode: false
};
}
@@ -114,7 +114,7 @@ export class Nodes {
type: NodeType.CallExpression,
callee,
arguments: args,
obfuscated: false
obfuscatedNode: false
};
}
@@ -125,7 +125,7 @@ export class Nodes {
public static getContinueStatement (label?: ESTree.Identifier): ESTree.ContinueStatement {
const continueStatementNode: ESTree.ContinueStatement = {
type: NodeType.ContinueStatement,
obfuscated: false
obfuscatedNode: false
};
if (label) {
@@ -143,7 +143,7 @@ export class Nodes {
return {
type: NodeType.ExpressionStatement,
expression,
obfuscated: false
obfuscatedNode: false
};
}
@@ -164,7 +164,7 @@ export class Nodes {
params,
body,
generator: false,
obfuscated: false
obfuscatedNode: false
};
}
@@ -182,7 +182,7 @@ export class Nodes {
params,
body,
generator: false,
obfuscated: false
obfuscatedNode: false
};
}
@@ -196,7 +196,7 @@ export class Nodes {
type: NodeType.IfStatement,
test,
consequent,
obfuscated: false
obfuscatedNode: false
};
}
@@ -208,7 +208,7 @@ export class Nodes {
return {
type: NodeType.Identifier,
name,
obfuscated: false
obfuscatedNode: false
};
}
@@ -222,7 +222,7 @@ export class Nodes {
type: NodeType.LabeledStatement,
label,
body,
obfuscated: false
obfuscatedNode: false
};
}
@@ -239,7 +239,7 @@ export class Nodes {
content: `'${value}'`,
precedence: escodegen.Precedence.Primary
},
obfuscated: false
obfuscatedNode: false
};
}
@@ -259,7 +259,7 @@ export class Nodes {
operator,
left,
right,
obfuscated: false
obfuscatedNode: false
};
}
@@ -279,7 +279,7 @@ export class Nodes {
computed,
object,
property,
obfuscated: false
obfuscatedNode: false
};
}
@@ -291,7 +291,7 @@ export class Nodes {
return {
type: NodeType.ObjectExpression,
properties,
obfuscated: false
obfuscatedNode: false
};
}
@@ -311,7 +311,7 @@ export class Nodes {
method: false,
shorthand: false,
computed,
obfuscated: false
obfuscatedNode: false
};
}
@@ -331,7 +331,7 @@ export class Nodes {
operator,
argument,
prefix,
obfuscated: false
obfuscatedNode: false
};
}
@@ -343,7 +343,7 @@ export class Nodes {
return {
type: NodeType.ReturnStatement,
argument,
obfuscated: false
obfuscatedNode: false
};
}
@@ -360,7 +360,7 @@ export class Nodes {
type: NodeType.SwitchStatement,
discriminant,
cases,
obfuscated: false
obfuscatedNode: false
};
}
@@ -374,7 +374,7 @@ export class Nodes {
type: NodeType.SwitchCase,
test,
consequent,
obfuscated: false
obfuscatedNode: false
};
}
@@ -389,7 +389,7 @@ export class Nodes {
operator,
argument: argumentExpr,
prefix: false,
obfuscated: false
obfuscatedNode: false
};
}
@@ -406,7 +406,7 @@ export class Nodes {
type: NodeType.VariableDeclaration,
declarations,
kind,
obfuscated: false
obfuscatedNode: false
};
}
@@ -420,7 +420,7 @@ export class Nodes {
type: NodeType.VariableDeclarator,
id,
init,
obfuscated: false
obfuscatedNode: false
};
}
@@ -434,7 +434,7 @@ export class Nodes {
type: NodeType.WhileStatement,
test,
body,
obfuscated: false
obfuscatedNode: false
};
}
}
+22 -9
View File
@@ -8,6 +8,12 @@ import { RandomGeneratorUtils } from '../utils/RandomGeneratorUtils';
@injectable()
export abstract class ArrayStorage <T> implements IStorage <T> {
/**
* @type {T[]}
*/
@initializable()
protected storage: T[];
/**
* @type {string}
*/
@@ -15,10 +21,9 @@ export abstract class ArrayStorage <T> implements IStorage <T> {
protected storageId: string;
/**
* @type {T[]}
* @type {number}
*/
@initializable()
protected storage: T[];
private storageLength: number = 0;
/**
* @param key
@@ -36,17 +41,19 @@ export abstract class ArrayStorage <T> implements IStorage <T> {
/**
* @param value
* @returns {string | number}
* @returns {number | null}
*/
public getKeyOf (value: T): string | number {
return this.storage.indexOf(value);
public getKeyOf (value: T): number | null {
const key: number = this.storage.indexOf(value);
return key >= 0 ? key : null;
}
/**
* @returns {number}
*/
public getLength (): number {
return this.storage.length;
return this.storageLength;
}
/**
@@ -87,7 +94,13 @@ export abstract class ArrayStorage <T> implements IStorage <T> {
* @param key
* @param value
*/
public set (key: string | null, value: T): void {
this.storage.push(value);
public set (key: number, value: T): void {
if (key === this.storageLength) {
this.storage.push(value);
} else {
this.storage.splice(key, 0, value);
}
this.storageLength++;
}
}
+7 -2
View File
@@ -5,7 +5,6 @@ import { IStorage } from '../interfaces/storages/IStorage';
import { initializable } from '../decorators/Initializable';
import { RandomGeneratorUtils } from '../utils/RandomGeneratorUtils';
import { Utils } from '../utils/Utils';
@injectable()
export abstract class MapStorage <T> implements IStorage <T> {
@@ -40,7 +39,13 @@ export abstract class MapStorage <T> implements IStorage <T> {
* @returns {string | number | null}
*/
public getKeyOf (value: T): string | number | null {
return Utils.mapGetFirstKeyOf <string | number, T> (this.storage, value);
for (const [key, storageValue] of this.storage) {
if (value === storageValue) {
return key;
}
}
return null;
}
/**
+4
View File
@@ -0,0 +1,4 @@
import * as estraverse from 'estraverse';
import * as ESTree from 'estree';
export type TVisitorFunction = (node: ESTree.Node, parentNode: ESTree.Node | null) => estraverse.VisitorOption | ESTree.Node | void;
+1 -1
View File
@@ -2,4 +2,4 @@ import { INodeTransformer } from '../../interfaces/node-transformers/INodeTransf
import { NodeTransformers } from '../../enums/container/NodeTransformers';
export type TNodeTransformersFactory = (nodeTransformersMap: Map<string, NodeTransformers[]>) => (nodeType: string) => INodeTransformer[];
export type TNodeTransformersFactory = (nodeTransformerName: NodeTransformers) => INodeTransformer;
-16
View File
@@ -1,4 +1,3 @@
import * as _ from 'lodash';
import { JSFuck } from '../enums/JSFuck';
import { RandomGeneratorUtils } from './RandomGeneratorUtils';
@@ -92,21 +91,6 @@ export class Utils {
return number % 1 === 0;
}
/**
* @param map
* @param value
* @returns {T | null}
*/
public static mapGetFirstKeyOf <T, U> (map: Map <T, U>, value: U): T | null {
for (const [key, storageValue] of map) {
if (_.isEqual(value, storageValue)) {
return key;
}
}
return null;
}
/**
* @param obj
* @returns {T}
@@ -58,8 +58,6 @@ describe('BinaryExpressionControlFlowReplacer', () => {
assert.match(obfuscatedCode, controlFlowStorageCallRegExp1);
assert.match(obfuscatedCode, controlFlowStorageCallRegExp2);
assert.isOk(firstMatch);
assert.isOk(secondMatch);
if (firstMatch === secondMatch) {
equalsValue++;
@@ -67,6 +65,8 @@ describe('BinaryExpressionControlFlowReplacer', () => {
}
assert.closeTo(equalsValue / samplesCount, expectedValue, delta);
console.log(equalsValue / samplesCount);
});
});
});
@@ -58,8 +58,6 @@ describe('CallExpressionControlFlowReplacer', () => {
assert.match(obfuscatedCode, controlFlowStorageCallRegExp1);
assert.match(obfuscatedCode, controlFlowStorageCallRegExp2);
assert.isOk(firstMatch);
assert.isOk(secondMatch);
if (firstMatch === secondMatch) {
equalsValue++;
@@ -67,6 +65,8 @@ describe('CallExpressionControlFlowReplacer', () => {
}
assert.closeTo(equalsValue / samplesCount, expectedValue, delta);
console.log(equalsValue / samplesCount);
});
});
@@ -58,8 +58,6 @@ describe('LogicalExpressionControlFlowReplacer', () => {
assert.match(obfuscatedCode, controlFlowStorageCallRegExp1);
assert.match(obfuscatedCode, controlFlowStorageCallRegExp2);
assert.isOk(firstMatch);
assert.isOk(secondMatch);
if (firstMatch === secondMatch) {
equalsValue++;
@@ -67,6 +65,8 @@ describe('LogicalExpressionControlFlowReplacer', () => {
}
assert.closeTo(equalsValue / samplesCount, expectedValue, delta);
console.log(equalsValue / samplesCount);
});
});
@@ -52,4 +52,124 @@ describe('FunctionTransformer', () => {
assert.match(obfuscatedCode, functionBodyMatch);
});
});
describe('assignment pattern as parameter', () => {
describe('literal as right value', () => {
const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
readFileAsString(__dirname + '/fixtures/assignment-pattern-as-parameter-1.js'),
{
...NO_CUSTOM_NODES_PRESET
}
);
const obfuscatedCode: string = obfuscationResult.getObfuscatedCode();
it('should transform function parameter assignment pattern identifier', () => {
const functionParameterMatch: RegExp = /function *\(_0x[a-f0-9]{4,6} *= *0x1\) *\{/;
const functionBodyMatch: RegExp = /return *_0x[a-f0-9]{4,6};/;
assert.match(obfuscatedCode, functionParameterMatch);
assert.match(obfuscatedCode, functionBodyMatch);
});
});
describe('identifier as right value', () => {
const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
readFileAsString(__dirname + '/fixtures/assignment-pattern-as-parameter-2.js'),
{
...NO_CUSTOM_NODES_PRESET
}
);
const obfuscatedCode: string = obfuscationResult.getObfuscatedCode();
const variableDeclarationMatch: RegExp = /var *(_0x[a-f0-9]{4,6}) *= *0x1;/;
const functionParameterMatch: RegExp = /function *\((_0x[a-f0-9]{4,6}) *= *(_0x[a-f0-9]{4,6})\) *\{/;
const functionBodyMatch: RegExp = /return *(_0x[a-f0-9]{4,6});/;
const variableDeclarationIdentifierName: string = obfuscatedCode.match(variableDeclarationMatch)![1];
const functionParameterIdentifierName: string = obfuscatedCode.match(functionParameterMatch)![1];
const functionDefaultParameterIdentifierName: string = obfuscatedCode.match(functionParameterMatch)![2];
const functionBodyIdentifierName: string = obfuscatedCode.match(functionBodyMatch)![1];
it('should transform function parameter assignment pattern identifier', () => {
assert.match(obfuscatedCode, variableDeclarationMatch);
assert.match(obfuscatedCode, functionParameterMatch);
assert.match(obfuscatedCode, functionBodyMatch);
});
it('should keep same names for identifier in variable declaration and default value identifier of function parameter', () => {
assert.equal(variableDeclarationIdentifierName, functionDefaultParameterIdentifierName);
});
it('should keep same names for identifiers in function params and function body', () => {
assert.equal(functionParameterIdentifierName, functionBodyIdentifierName);
});
});
describe('identifier as right value', () => {
const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
readFileAsString(__dirname + '/fixtures/assignment-pattern-as-parameter-3.js'),
{
...NO_CUSTOM_NODES_PRESET
}
);
const obfuscatedCode: string = obfuscationResult.getObfuscatedCode();
const variableDeclarationMatch: RegExp = /var *(_0x[a-f0-9]{4,6}) *= *0x1;/;
const functionParameterMatch: RegExp = /function *\((_0x[a-f0-9]{4,6}), *(_0x[a-f0-9]{4,6}) *= *(_0x[a-f0-9]{4,6})\) *\{/;
const functionBodyMatch: RegExp = /return *(_0x[a-f0-9]{4,6}) *\+ *(_0x[a-f0-9]{4,6});/;
const variableDeclarationIdentifierName: string = obfuscatedCode.match(variableDeclarationMatch)![1];
const functionParameterIdentifierName: string = obfuscatedCode.match(functionParameterMatch)![1];
const functionDefaultParameterIdentifierName1: string = obfuscatedCode.match(functionParameterMatch)![2];
const functionDefaultParameterIdentifierName2: string = obfuscatedCode.match(functionParameterMatch)![3];
const functionBodyIdentifierName1: string = obfuscatedCode.match(functionBodyMatch)![1];
const functionBodyIdentifierName2: string = obfuscatedCode.match(functionBodyMatch)![2];
it('should transform function parameter assignment pattern identifier', () => {
assert.match(obfuscatedCode, variableDeclarationMatch);
assert.match(obfuscatedCode, functionParameterMatch);
assert.match(obfuscatedCode, functionBodyMatch);
});
it('shouldn\'t keep same names variable declaration identifier and function parameters identifiers', () => {
assert.notEqual(variableDeclarationIdentifierName, functionParameterIdentifierName);
assert.notEqual(variableDeclarationIdentifierName, functionDefaultParameterIdentifierName1);
assert.notEqual(variableDeclarationIdentifierName, functionDefaultParameterIdentifierName2);
});
it('should keep same names for identifier in first function parameter and default value identifier of second function parameter', () => {
assert.equal(functionParameterIdentifierName, functionDefaultParameterIdentifierName2);
});
it('should keep same names for identifiers in function params and function body', () => {
assert.equal(functionParameterIdentifierName, functionBodyIdentifierName1);
assert.equal(functionDefaultParameterIdentifierName1, functionBodyIdentifierName2);
});
});
});
describe('array pattern as parameter', () => {
const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
readFileAsString(__dirname + '/fixtures/array-pattern-as-parameter.js'),
{
...NO_CUSTOM_NODES_PRESET
}
);
const obfuscatedCode: string = obfuscationResult.getObfuscatedCode();
const functionParameterMatch: RegExp = /function *\(\[(_0x[a-f0-9]{4,6}), *(_0x[a-f0-9]{4,6})\]\) *\{/;
const functionBodyMatch: RegExp = /return *(_0x[a-f0-9]{4,6}) *\+ *(_0x[a-f0-9]{4,6});/;
const arrayPatternIdentifierName1: string = obfuscatedCode.match(functionParameterMatch)![1];
const arrayPatternIdentifierName2: string = obfuscatedCode.match(functionParameterMatch)![2];
const functionBodyIdentifierName1: string = obfuscatedCode.match(functionBodyMatch)![1];
const functionBodyIdentifierName2: string = obfuscatedCode.match(functionBodyMatch)![2];
it('should keep same names for identifiers in function parameter array pattern and function body', () => {
assert.equal(arrayPatternIdentifierName1, functionBodyIdentifierName1);
assert.equal(arrayPatternIdentifierName2, functionBodyIdentifierName2);
});
});
});
@@ -0,0 +1,5 @@
(function () {
var test = function ([foo, bar]) {
return foo + bar;
}
})();
@@ -0,0 +1,5 @@
(function () {
var test = function (bar = 1) {
return bar;
}
})();
@@ -0,0 +1,6 @@
(function () {
var foo = 1;
var test = function (bar = foo) {
return bar;
}
})();
@@ -0,0 +1,6 @@
(function () {
var foo = 1;
var test = function (foo, bar = foo) {
return foo + bar;
}
})();
@@ -200,11 +200,39 @@ describe('VariableDeclarationTransformer', () => {
const obfuscatedCode: string = obfuscationResult.getObfuscatedCode();
it('shouldn\'t transform object pattern variable declarator', () => {
const objectPatternVariableDeclarator: RegExp = /var *\{ *bar *\} *= *\{ *'\\x62\\x61\\x72' *: *'\\x66\\x6f\\x6f' *\};/;
const objectPatternVariableDeclaratorMatch: RegExp = /var *\{ *bar *\} *= *\{ *'\\x62\\x61\\x72' *: *'\\x66\\x6f\\x6f' *\};/;
const variableUsageMatch: RegExp = /console\['\\x6c\\x6f\\x67'\]\(bar\);/;
assert.match(obfuscatedCode, objectPatternVariableDeclarator);
assert.match(obfuscatedCode, objectPatternVariableDeclaratorMatch);
assert.match(obfuscatedCode, variableUsageMatch);
});
});
describe('array pattern as variable declarator', () => {
const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(
readFileAsString(__dirname + '/fixtures/array-pattern.js'),
{
...NO_CUSTOM_NODES_PRESET
}
);
const obfuscatedCode: string = obfuscationResult.getObfuscatedCode();
const objectPatternVariableDeclaratorMatch: RegExp = /var *\[ *(_0x([a-f0-9]){4,6}), *(_0x([a-f0-9]){4,6}) *\] *= *\[0x1, *0x2\];/;
const variableUsageMatch: RegExp = /console\['\\x6c\\x6f\\x67'\]\((_0x([a-f0-9]){4,6}), *(_0x([a-f0-9]){4,6})\);/;
const objectPatternIdentifierName1: string = obfuscatedCode.match(objectPatternVariableDeclaratorMatch)![1];
const objectPatternIdentifierName2: string = obfuscatedCode.match(objectPatternVariableDeclaratorMatch)![2];
const identifierName1: string = obfuscatedCode.match(variableUsageMatch)![1];
const identifierName2: string = obfuscatedCode.match(variableUsageMatch)![2];
it('should transform array pattern variable declarator', () => {
assert.match(obfuscatedCode, objectPatternVariableDeclaratorMatch);
assert.match(obfuscatedCode, variableUsageMatch);
});
it('should keep same identifier names same for identifiers in variable declaration and after variable declaration', () => {
assert.equal(objectPatternIdentifierName1, identifierName1);
assert.equal(objectPatternIdentifierName2, identifierName2);
});
});
});
@@ -0,0 +1,5 @@
function foo () {
var [bar, baz] = [1, 2];
console.log(bar, baz);
}
@@ -1,4 +1,5 @@
(function () {
var { bar } = { bar: 'foo' };
console.log(bar);
})();
+2
View File
@@ -13,6 +13,8 @@ import './unit-tests/obfuscation-result/ObfuscationResult.spec';
import './unit-tests/options/options-normalizer/OptionsNormalizer.spec';
import './unit-tests/source-map-corrector/SourceMapCorrector.spec';
import './unit-tests/stack-trace-analyzer/stack-trace-analyzer/StackTraceAnalyzer.spec';
import './unit-tests/storages/ArrayStorage.spec';
import './unit-tests/storages/MapStorage.spec';
import './unit-tests/utils/crypt-utils/CryptUtils.spec';
import './unit-tests/utils/random-generator-utils/RandomGeneratorUtils.spec';
import './unit-tests/utils/utils/Utils.spec';
@@ -0,0 +1,126 @@
import { assert } from 'chai';
import { IStorage } from '../../../src/interfaces/storages/IStorage';
import { ArrayStorage } from '../../../src/storages/ArrayStorage';
class ConcreteStorage extends ArrayStorage <string> {
constructor () {
super();
}
}
describe('ArrayStorage', () => {
describe('initialize (...args: any[]): void', () => {
it('should throws an error when storage isn\'t initialized', () => {
const storage: IStorage <string> = new ConcreteStorage();
assert.throws(() => storage.set(0, 'foo'), Error);
});
});
describe('getStorage (): T[]', () => {
it('should returns storage', () => {
const storage: IStorage <string> = new ConcreteStorage();
storage.initialize();
assert.instanceOf(storage.getStorage(), Array);
});
});
describe('get (key: number): T', () => {
it('should returns value from storage by key', () => {
const storage: IStorage <string> = new ConcreteStorage();
storage.initialize();
storage.set(0, 'foo');
assert.equal(storage.get(0), 'foo');
});
it('should throw an error if value isn\'t exist', () => {
const storage: IStorage <string> = new ConcreteStorage();
storage.initialize();
assert.throws(() => storage.get(0), Error);
});
});
describe('getLength (): number', () => {
it('should returns length of storage', () => {
const storage: IStorage <string> = new ConcreteStorage();
storage.initialize();
storage.set(0, 'foo');
assert.equal(storage.getLength(), 1);
});
});
describe('getKeyOf (value: T): number | null', () => {
it('should returns key of string value', () => {
const storage: IStorage <string> = new ConcreteStorage();
storage.initialize();
storage.set(0, 'foo');
assert.equal(storage.getKeyOf('foo'), 0);
});
it('should returns key of object if objects in `set` and `get` are two linked objects', () => {
const storage: IStorage <Object> = new ConcreteStorage();
const object: Object = {
foo: 'bar'
};
storage.initialize();
storage.set(0, object);
assert.equal(storage.getKeyOf(object), 0);
});
it('should return `null` if objects in `set` and `get` are two equal objects', () => {
const storage: IStorage <Object> = new ConcreteStorage();
storage.initialize();
storage.set(0, {
foo: 'bar'
});
assert.equal(storage.getKeyOf({
foo: 'bar'
}), null);
});
});
describe('set (key: number, value: T): void', () => {
it('should set value to the storage', () => {
const storage: IStorage <string> = new ConcreteStorage();
storage.initialize();
storage.set(0, 'foo');
assert.equal(storage.get(0), 'foo');
assert.equal(storage.getLength(), 1);
});
});
describe('mergeWith (storage: this, mergeId: boolean = false): void', () => {
it('should merge two storages', () => {
const storage1: IStorage <string> = new ConcreteStorage();
const storage2: IStorage <string> = new ConcreteStorage();
storage1.initialize();
storage1.set(0, 'foo');
storage2.initialize();
storage2.set(1, 'bar');
storage1.mergeWith(storage2, false);
assert.deepEqual(storage1.getStorage(), ['foo', 'bar']);
});
});
});
+126
View File
@@ -0,0 +1,126 @@
import { assert } from 'chai';
import { IStorage } from '../../../src/interfaces/storages/IStorage';
import { MapStorage } from '../../../src/storages/MapStorage';
class ConcreteStorage extends MapStorage <string> {
constructor () {
super();
}
}
describe('MapStorage', () => {
describe('initialize (...args: any[]): void', () => {
it('should throws an error when storage isn\'t initialized', () => {
const storage: IStorage <string> = new ConcreteStorage();
assert.throws(() => storage.set('foo', 'bar'), Error);
});
});
describe('getStorage (): Map <string | number, T>', () => {
it('should returns storage', () => {
const storage: IStorage <string> = new ConcreteStorage();
storage.initialize();
assert.instanceOf(storage.getStorage(), Map);
});
});
describe('get (key: string | number): T', () => {
it('should returns value from storage by key', () => {
const storage: IStorage <string> = new ConcreteStorage();
storage.initialize();
storage.set('foo', 'bar');
assert.equal(storage.get('foo'), 'bar');
});
it('should throw an error if value isn\'t exist', () => {
const storage: IStorage <string> = new ConcreteStorage();
storage.initialize();
assert.throws(() => storage.get('foo'), Error);
});
});
describe('getLength (): number', () => {
it('should returns length of storage', () => {
const storage: IStorage <string> = new ConcreteStorage();
storage.initialize();
storage.set('foo', 'bar');
assert.equal(storage.getLength(), 1);
});
});
describe('getKeyOf (value: T): string | number | null', () => {
it('should returns key of string value', () => {
const storage: IStorage <string> = new ConcreteStorage();
storage.initialize();
storage.set('foo', 'bar');
assert.equal(storage.getKeyOf('bar'), 'foo');
});
it('should returns key of object if objects in `set` and `get` are two linked objects', () => {
const storage: IStorage <Object> = new ConcreteStorage();
const object: Object = {
bar: 'baz'
};
storage.initialize();
storage.set('foo', object);
assert.equal(storage.getKeyOf(object), 'foo');
});
it('should return `null` if objects in `set` and `get` are two equal objects', () => {
const storage: IStorage <Object> = new ConcreteStorage();
storage.initialize();
storage.set('foo', {
bar: 'baz'
});
assert.equal(storage.getKeyOf({
bar: 'baz'
}), null);
});
});
describe('set (key: string | number, value: T): void', () => {
it('should set value to the storage', () => {
const storage: IStorage <string> = new ConcreteStorage();
storage.initialize();
storage.set('foo', 'bar');
assert.equal(storage.get('foo'), 'bar');
assert.equal(storage.getLength(), 1);
});
});
describe('mergeWith (storage: this, mergeId: boolean = false): void', () => {
it('should merge two storages', () => {
const storage1: IStorage <string> = new ConcreteStorage();
const storage2: IStorage <string> = new ConcreteStorage();
storage1.initialize();
storage1.set('foo', 'bar');
storage2.initialize();
storage2.set('baz', 'quux');
storage1.mergeWith(storage2, false);
assert.deepEqual(Array.from(storage1.getStorage()), [['foo', 'bar'], ['baz', 'quux']]);
});
});
});
-28
View File
@@ -53,34 +53,6 @@ describe('Utils', () => {
});
});
describe('mapGetFirstKeyOf(map: Map <any, any>, value: any): any', () => {
it('should returns key of map item', () => {
const map: Map <any, any> = new Map();
map.set('number1', 1);
map.set('number2', 2);
map.set('number3', 2);
map.set('string1', 'foo');
map.set('string2', 'bar');
map.set('object1', {item: 'value'});
map.set('object2', {item: 'value'});
map.set({key: 'object'}, [1, 2, 3]);
assert.deepEqual(Utils.mapGetFirstKeyOf(map, 1), 'number1');
assert.deepEqual(Utils.mapGetFirstKeyOf(map, 2), 'number2');
assert.deepEqual(Utils.mapGetFirstKeyOf(map, 'foo'), 'string1');
assert.deepEqual(Utils.mapGetFirstKeyOf(map, 'bar'), 'string2');
assert.deepEqual(Utils.mapGetFirstKeyOf(map, {item: 'value'}), 'object1');
assert.deepEqual(Utils.mapGetFirstKeyOf(map, [1, 2, 3]), {key: 'object'});
assert.deepEqual(Utils.mapGetFirstKeyOf(map, 3), null);
});
});
describe('stringRotate (string: string, times: number): string', () => {
let string: string;
+1 -1
View File
@@ -6,7 +6,7 @@ const webpack = require('webpack');
const CheckerPlugin = require('awesome-typescript-loader').CheckerPlugin;
function getLicenseText () {
return "/*\nCopyright (C) 2016 Timofey Kachalov <sanex3339@yandex.ru>\n\n" +
return "/*\nCopyright (C) 2017 Timofey Kachalov <sanex3339@yandex.ru>\n\n" +
fs.readFileSync('./LICENSE.BSD', 'utf8') + "\n*/";
}