mirror of
https://github.com/javascript-obfuscator/javascript-obfuscator
synced 2026-08-09 12:42:29 +00:00
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:
@@ -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
|
||||
|
||||
@@ -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/
|
||||
[](https://travis-ci.org/javascript-obfuscator/javascript-obfuscator)
|
||||
[](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.
|
||||
|
||||
Vendored
+495
-258
File diff suppressed because it is too large
Load Diff
+7
-7
@@ -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,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,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,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
@@ -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;
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
Vendored
+1
-2
@@ -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 {
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
+16
-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 { 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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -177,7 +177,7 @@ export class NodeUtils {
|
||||
}
|
||||
|
||||
node.parentNode = value;
|
||||
node.obfuscated = false;
|
||||
node.obfuscatedNode = false;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
+27
-27
@@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Vendored
+4
@@ -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
@@ -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;
|
||||
|
||||
@@ -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}
|
||||
|
||||
+2
-2
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+2
-2
@@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
+2
-2
@@ -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);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
+120
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
(function () {
|
||||
var test = function ([foo, bar]) {
|
||||
return foo + bar;
|
||||
}
|
||||
})();
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
(function () {
|
||||
var test = function (bar = 1) {
|
||||
return bar;
|
||||
}
|
||||
})();
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
(function () {
|
||||
var foo = 1;
|
||||
var test = function (bar = foo) {
|
||||
return bar;
|
||||
}
|
||||
})();
|
||||
+6
@@ -0,0 +1,6 @@
|
||||
(function () {
|
||||
var foo = 1;
|
||||
var test = function (foo, bar = foo) {
|
||||
return foo + bar;
|
||||
}
|
||||
})();
|
||||
+30
-2
@@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
function foo () {
|
||||
var [bar, baz] = [1, 2];
|
||||
|
||||
console.log(bar, baz);
|
||||
}
|
||||
+1
@@ -1,4 +1,5 @@
|
||||
(function () {
|
||||
var { bar } = { bar: 'foo' };
|
||||
|
||||
console.log(bar);
|
||||
})();
|
||||
|
||||
@@ -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']);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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']]);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -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
@@ -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*/";
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user