javascript-obfuscator
Advanced tools
Change Log | ||
=== | ||
v0.7.2 | ||
--- | ||
* runtime error fix [#7](https://github.com/sanex3339/webpack-obfuscator/issues/7) | ||
* shorthand object expression fix [#16](https://github.com/sanex3339/javascript-obfuscator/issues/16) | ||
v0.7.1 | ||
@@ -5,0 +11,0 @@ --- |
{ | ||
"name": "javascript-obfuscator", | ||
"version": "0.7.1", | ||
"version": "0.7.2", | ||
"description": "JavaScript obfuscator", | ||
@@ -25,6 +25,6 @@ "keywords": [ | ||
"chance": "^1.0.4", | ||
"class-validator": "^0.5.0", | ||
"class-validator": "^0.6.1", | ||
"commander": "^2.9.0", | ||
"escodegen": "^1.8.1", | ||
"esprima": "^2.7.2", | ||
"esprima": "^3.0.0", | ||
"estraverse": "^4.2.0", | ||
@@ -36,29 +36,29 @@ "format-unicorn": "^1.1.0", | ||
"devDependencies": { | ||
"@types/chai": "^3.4.31", | ||
"@types/chai": "^3.4.32", | ||
"@types/chance": "^0.7.28", | ||
"@types/commander": "^2.3.29", | ||
"@types/escodegen": "^0.0.3", | ||
"@types/esprima": "^2.1.30", | ||
"@types/estraverse": "^0.0.3", | ||
"@types/format-unicorn": "^0.0.28", | ||
"@types/joi": "^9.0.30", | ||
"@types/escodegen": "0.0.3", | ||
"@types/esprima": "^2.1.31", | ||
"@types/estraverse": "0.0.3", | ||
"@types/format-unicorn": "^0.0.29", | ||
"@types/joi": "^9.0.31", | ||
"@types/mkdirp": "^0.3.28", | ||
"@types/mocha": "^2.2.30", | ||
"@types/mocha": "^2.2.31", | ||
"@types/node": "^4.0.30", | ||
"@types/sinon": "^1.16.28", | ||
"babel-cli": "^6.11.4", | ||
"@types/sinon": "^1.16.29", | ||
"babel-cli": "^6.14.0", | ||
"babel-loader": "^6.2.5", | ||
"babel-preset-es2015": "^6.13.2", | ||
"babel-preset-es2015": "^6.14.0", | ||
"chai": "^3.5.0", | ||
"chai-members-deep": "^1.1.0", | ||
"coveralls": "^2.11.12", | ||
"coveralls": "^2.11.14", | ||
"istanbul": "1.1.0-alpha.1", | ||
"mocha": "^3.0.2", | ||
"sinon": "^2.0.0-pre.2", | ||
"optimize-js-plugin": "0.0.4", | ||
"sinon": "^2.0.0-pre.3", | ||
"ts-loader": "^0.8.2", | ||
"ts-node": "^1.3.0", | ||
"tslint": "^3.14.0", | ||
"tslint": "^3.15.1", | ||
"typescript": "^2.0.0", | ||
"webpack": "^2.1.0-beta.21", | ||
"webpack-node-externals": "^1.3.3" | ||
"webpack": "^2.1.0-beta.25", | ||
"webpack-node-externals": "^1.4.3" | ||
}, | ||
@@ -88,2 +88,2 @@ "repository": { | ||
"license": "BSD-2-Clause" | ||
} | ||
} |
export interface INode { | ||
type: string; | ||
parentNode?: INode; | ||
obfuscated?: boolean; | ||
} |
@@ -35,3 +35,3 @@ import * as estraverse from 'estraverse'; | ||
estraverse.traverse(catchClauseNode.param, { | ||
leave: (node: INode): any => this.storeIdentifiersNames(node, this.catchClauseParam) | ||
enter: (node: INode): any => this.storeIdentifiersNames(node, this.catchClauseParam) | ||
}); | ||
@@ -45,3 +45,3 @@ } | ||
estraverse.replace(catchClauseNode, { | ||
leave: (node: INode, parentNode: INode): any => { | ||
enter: (node: INode, parentNode: INode): any => { | ||
this.replaceIdentifiersWithRandomNames(node, parentNode, this.catchClauseParam); | ||
@@ -48,0 +48,0 @@ } |
@@ -44,3 +44,3 @@ import * as estraverse from 'estraverse'; | ||
estraverse.traverse(functionDeclarationNode.id, { | ||
leave: (node: INode): any => this.storeIdentifiersNames(node, this.functionName) | ||
enter: (node: INode): any => this.storeIdentifiersNames(node, this.functionName) | ||
}); | ||
@@ -47,0 +47,0 @@ } |
@@ -7,2 +7,3 @@ import * as estraverse from 'estraverse'; | ||
import { NodeObfuscator } from './NodeObfuscator'; | ||
import { Nodes } from "../Nodes"; | ||
@@ -38,3 +39,3 @@ /** | ||
estraverse.traverse(paramsNode, { | ||
leave: (node: INode): any => this.storeIdentifiersNames(node, this.functionParams) | ||
enter: (node: INode): any => this.storeIdentifiersNames(node, this.functionParams) | ||
}); | ||
@@ -49,4 +50,16 @@ }); | ||
let replaceVisitor: estraverse.Visitor = { | ||
leave: (node: INode, parentNode: INode): any => { | ||
enter: (node: INode, parentNode: INode): any => { | ||
let newNodeName: string = ''; | ||
if (Nodes.isIdentifierNode(node)) { | ||
newNodeName = node.name; | ||
} | ||
this.replaceIdentifiersWithRandomNames(node, parentNode, this.functionParams); | ||
if (Nodes.isIdentifierNode(node)) { | ||
if (node.name !== newNodeName) { | ||
node.obfuscated = true; | ||
} | ||
} | ||
} | ||
@@ -53,0 +66,0 @@ }; |
@@ -20,3 +20,3 @@ import * as escodegen from 'escodegen'; | ||
estraverse.replace(memberExpressionNode.property, { | ||
leave: (node: INode, parentNode: INode): any => { | ||
enter: (node: INode, parentNode: INode): any => { | ||
if (Nodes.isLiteralNode(node)) { | ||
@@ -23,0 +23,0 @@ this.obfuscateLiteralProperty(node); |
@@ -33,2 +33,6 @@ import * as escodegen from 'escodegen'; | ||
.forEach((property: IPropertyNode) => { | ||
if (property.shorthand) { | ||
property.shorthand = false; | ||
} | ||
estraverse.replace(property.key, { | ||
@@ -35,0 +39,0 @@ leave: (node: INode, parentNode: INode): any => { |
@@ -11,3 +11,2 @@ import * as estraverse from 'estraverse'; | ||
import { NodeUtils } from "../NodeUtils"; | ||
import { Utils } from '../Utils'; | ||
@@ -62,26 +61,7 @@ /** | ||
variableDeclarationNode | ||
) : variableParentNode, | ||
isNodeAfterVariableDeclaratorFlag: boolean = false; | ||
) : variableParentNode; | ||
estraverse.replace(scopeNode, { | ||
enter: (node: INode, parentNode: INode): any => { | ||
const functionNodes: string[] = [ | ||
NodeType.ArrowFunctionExpression, | ||
NodeType.FunctionDeclaration, | ||
NodeType.FunctionExpression | ||
]; | ||
if (Utils.arrayContains(functionNodes, node.type)) { | ||
estraverse.replace(node, { | ||
enter: (node: INode, parentNode: INode): any => { | ||
this.replaceIdentifiersWithRandomNames(node, parentNode, this.variableNames); | ||
} | ||
}); | ||
} | ||
if (node === variableDeclarationNode) { | ||
isNodeAfterVariableDeclaratorFlag = true; | ||
} | ||
if (isNodeAfterVariableDeclaratorFlag) { | ||
if (!node.obfuscated) { | ||
this.replaceIdentifiersWithRandomNames(node, parentNode, this.variableNames); | ||
@@ -88,0 +68,0 @@ } |
@@ -15,2 +15,3 @@ import { IBlockStatementNode } from "./interfaces/nodes/IBlockStatementNode"; | ||
import { NodeType } from "./enums/NodeType"; | ||
import { ICallExpressionNode } from "./interfaces/nodes/ICallExpressionNode"; | ||
@@ -26,3 +27,4 @@ export class Nodes { | ||
'body': bodyNode, | ||
'sourceType': 'script' | ||
'sourceType': 'script', | ||
'obfuscated': false | ||
}; | ||
@@ -43,2 +45,10 @@ } | ||
*/ | ||
public static isCallExpressionNode (node: INode): node is ICallExpressionNode { | ||
return node.type === NodeType.CallExpression; | ||
} | ||
/** | ||
* @param node | ||
* @returns {boolean} | ||
*/ | ||
public static isIdentifierNode (node: INode): node is IIdentifierNode { | ||
@@ -45,0 +55,0 @@ return node.type === NodeType.Identifier; |
@@ -155,2 +155,3 @@ import * as escodegen from 'escodegen'; | ||
node['parentNode'] = value; | ||
node['obfuscated'] = false; | ||
} | ||
@@ -157,0 +158,0 @@ }); |
@@ -134,3 +134,3 @@ import * as estraverse from 'estraverse'; | ||
estraverse.replace(node, { | ||
leave: (node: INode, parentNode: INode): any => { | ||
enter: (node: INode, parentNode: INode): any => { | ||
this.initializeNodeObfuscators(node, parentNode); | ||
@@ -137,0 +137,0 @@ } |
@@ -59,2 +59,7 @@ 'use strict'; | ||
var sA = 'shorthand1'; | ||
var sB = 'shorthand2'; | ||
console.log({sA, sB}); | ||
try { | ||
@@ -61,0 +66,0 @@ } catch (error) { |
@@ -27,2 +27,20 @@ import { IObfuscationResult } from "../../../src/interfaces/IObfuscationResult"; | ||
}); | ||
it('should correct convert shorthand ES6 object expression to non-shorthand object expression', () => { | ||
let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( | ||
` | ||
(function () { | ||
let a = 0; | ||
let b = 0; | ||
var test = {a, b}; | ||
})(); | ||
`, | ||
Object.assign({}, NO_CUSTOM_NODES_PRESET) | ||
); | ||
assert.match( | ||
obfuscationResult.getObfuscatedCode(), | ||
/var *_0x[a-z0-9]{4,6} *= *\{'\\x61': *_0x[a-z0-9]{4,6}\, *'\\x62': *_0x[a-z0-9]{4,6}\};/ | ||
); | ||
}); | ||
}); |
@@ -21,4 +21,4 @@ import { IObfuscationResult } from "../../../src/interfaces/IObfuscationResult"; | ||
assert.match(obfuscationResult.getObfuscatedCode(), /var *_0x([a-z0-9]){6} *= *'\\x61\\x62\\x63';/); | ||
assert.match(obfuscationResult.getObfuscatedCode(), /console\['\\x6c\\x6f\\x67'\]\(_0x([a-z0-9]){6}\);/); | ||
assert.match(obfuscationResult.getObfuscatedCode(), /var *_0x([a-z0-9]){4,6} *= *'\\x61\\x62\\x63';/); | ||
assert.match(obfuscationResult.getObfuscatedCode(), /console\['\\x6c\\x6f\\x67'\]\(_0x([a-z0-9]){4,6}\);/); | ||
}); | ||
@@ -39,5 +39,63 @@ | ||
assert.match(obfuscationResult.getObfuscatedCode(), /console\['\\x6c\\x6f\\x67'\]\(_0x([a-z0-9]){6}\);/); | ||
assert.match(obfuscationResult.getObfuscatedCode(), /console\['\\x6c\\x6f\\x67'\]\(_0x([a-z0-9]){4,6}\);/); | ||
}); | ||
describe(`variable calls before variable declaration when function param has the same name as variables name`, () => { | ||
let obfuscationResult: IObfuscationResult, | ||
functionParamIdentifierName: string|null, | ||
innerFunctionParamIdentifierName: string|null, | ||
constructorIdentifierName: string|null, | ||
objectIdentifierName: string|null, | ||
variableDeclarationIdentifierName: string|null; | ||
beforeEach(() => { | ||
obfuscationResult = JavaScriptObfuscator.obfuscate( | ||
` | ||
(function () { | ||
function foo (t, e) { | ||
return function () { | ||
function baz (t) { | ||
console.log(t); | ||
} | ||
return {t: t}; | ||
var t; | ||
}(); | ||
} | ||
})(); | ||
`, | ||
Object.assign({}, NO_CUSTOM_NODES_PRESET) | ||
); | ||
}); | ||
it('should correct obfuscate variables inside function body', () => { | ||
const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); | ||
const functionParamIdentifierMatch: RegExpMatchArray|null = obfuscatedCode | ||
.match(/function *_0x[a-z0-9]{5,6} *\((_0x[a-z0-9]{5,6})\,(_0x[a-z0-9]{5,6})\) *\{/); | ||
const innerFunctionParamIdentifierMatch: RegExpMatchArray|null = obfuscatedCode | ||
.match(/function _0x[a-z0-9]{5,6} *\((_0x[a-z0-9]{5,6})\) *\{/); | ||
const constructorIdentifierMatch: RegExpMatchArray|null = obfuscatedCode | ||
.match(/console\['\\x6c\\x6f\\x67'\]\((_0x[a-z0-9]{5,6})\)/); | ||
const objectIdentifierMatch: RegExpMatchArray|null = obfuscatedCode | ||
.match(/return\{'\\x74':(_0x[a-z0-9]{5,6})\}/); | ||
const variableDeclarationIdentifierMatch: RegExpMatchArray|null = obfuscatedCode | ||
.match(/var *(_0x[a-z0-9]{5,6});/); | ||
functionParamIdentifierName = (<RegExpMatchArray>functionParamIdentifierMatch)[1]; | ||
innerFunctionParamIdentifierName = (<RegExpMatchArray>innerFunctionParamIdentifierMatch)[1]; | ||
constructorIdentifierName = (<RegExpMatchArray>constructorIdentifierMatch)[1]; | ||
objectIdentifierName = (<RegExpMatchArray>objectIdentifierMatch)[1]; | ||
variableDeclarationIdentifierName = (<RegExpMatchArray>variableDeclarationIdentifierMatch)[1]; | ||
assert.notEqual(functionParamIdentifierName, constructorIdentifierName); | ||
assert.notEqual(functionParamIdentifierName, innerFunctionParamIdentifierName); | ||
assert.equal(functionParamIdentifierName, objectIdentifierName); | ||
assert.equal(functionParamIdentifierName, variableDeclarationIdentifierName); | ||
assert.equal(innerFunctionParamIdentifierName, constructorIdentifierName); | ||
assert.equal(variableDeclarationIdentifierName, objectIdentifierName); | ||
}); | ||
}); | ||
it('should not obfuscate variable call (`identifier` node) outside of block scope of node in which this variable was declared with `let` kind', () => { | ||
@@ -83,9 +141,9 @@ let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( | ||
it('should obfuscate variable call (`identifier` node) before variable declaration if this call is inside function body', () => { | ||
assert.match(obfuscationResult.getObfuscatedCode(), /console\['\\x6c\\x6f\\x67'\]\(_0x([a-z0-9]){6}\['\\x69\\x74\\x65\\x6d'\]\);/); | ||
assert.match(obfuscationResult.getObfuscatedCode(), /console\['\\x6c\\x6f\\x67'\]\(_0x([a-z0-9]){4,6}\['\\x69\\x74\\x65\\x6d'\]\);/); | ||
}); | ||
it('should not obfuscate variable call (`identifier` node) before variable declaration', () => { | ||
assert.match(obfuscationResult.getObfuscatedCode(), /console\['\\x6c\\x6f\\x67'\]\(abc\);/); | ||
assert.match(obfuscationResult.getObfuscatedCode(), /console\['\\x6c\\x6f\\x67'\]\(_0x([a-z0-9]){5,6}\);/); | ||
}); | ||
}); | ||
}); |
@@ -26,2 +26,3 @@ import { BabelPolyfill } from './polyfills/BabelPolyfill'; | ||
import './functional-tests/JavaScriptObfuscatorInternal.spec'; | ||
import './functional-tests/node-obfuscators/FunctionObfuscator.spec'; | ||
import './functional-tests/node-obfuscators/LiteralObfuscator.spec'; | ||
@@ -28,0 +29,0 @@ import './functional-tests/node-obfuscators/MemberExpressionObfuscator.spec'; |
@@ -31,3 +31,4 @@ import * as escodegen from 'escodegen'; | ||
body: bodyNodes, | ||
sourceType: 'script' | ||
sourceType: 'script', | ||
obfuscated: false | ||
}; | ||
@@ -43,3 +44,4 @@ } | ||
type: NodeType.BlockStatement, | ||
body: bodyNodes | ||
body: bodyNodes, | ||
obfuscated: false | ||
}; | ||
@@ -56,3 +58,4 @@ } | ||
param: NodeMocks.getIdentifierNode('err'), | ||
body: NodeMocks.getBlockStatementNode(bodyNodes) | ||
body: NodeMocks.getBlockStatementNode(bodyNodes), | ||
obfuscated: false | ||
}; | ||
@@ -73,3 +76,4 @@ } | ||
callee: callee, | ||
arguments: args | ||
arguments: args, | ||
obfuscated: false | ||
}; | ||
@@ -87,3 +91,4 @@ } | ||
type: NodeType.ExpressionStatement, | ||
expression: expression | ||
expression: expression, | ||
obfuscated: false | ||
}; | ||
@@ -109,3 +114,4 @@ } | ||
generator: false, | ||
expression: false | ||
expression: false, | ||
obfuscated: false | ||
}; | ||
@@ -124,6 +130,8 @@ } | ||
value: true, | ||
raw: 'true' | ||
raw: 'true', | ||
obfuscated: false | ||
}, | ||
consequent: blockStatementNode, | ||
alternate: null | ||
alternate: null, | ||
obfuscated: false | ||
}; | ||
@@ -140,2 +148,3 @@ } | ||
name: identifierName, | ||
obfuscated: false | ||
}; | ||
@@ -156,3 +165,4 @@ } | ||
precedence: escodegen.Precedence.Primary | ||
} | ||
}, | ||
obfuscated: false | ||
}; | ||
@@ -174,3 +184,4 @@ } | ||
object: object, | ||
property: property | ||
property: property, | ||
obfuscated: false | ||
}; | ||
@@ -191,3 +202,4 @@ } | ||
declarations: declarations, | ||
kind: kind | ||
kind: kind, | ||
obfuscated: false | ||
}; | ||
@@ -205,5 +217,6 @@ } | ||
id: id, | ||
init: init | ||
init: init, | ||
obfuscated: false | ||
}; | ||
} | ||
} |
@@ -17,4 +17,2 @@ import * as chai from 'chai'; | ||
chai.use(require('chai-members-deep')); | ||
const assert: any = chai.assert; | ||
@@ -106,3 +104,3 @@ | ||
it('should convert code to `INode` structure', () => { | ||
assert.deepEqualIdent(NodeUtils.convertCodeToStructure(code), variableDeclarationNode); | ||
assert.deepEqual(NodeUtils.convertCodeToStructure(code), variableDeclarationNode); | ||
}); | ||
@@ -109,0 +107,0 @@ }); |
'use strict'; | ||
let fs = require("fs"), | ||
var fs = require("fs"), | ||
nodeExternals = require('webpack-node-externals'), | ||
@@ -8,7 +8,4 @@ webpack = require('webpack'); | ||
function getLicenseText () { | ||
return `/* | ||
Copyright (C) 2016 Timofey Kachalov <sanex3339@yandex.ru> | ||
${fs.readFileSync('./LICENSE.BSD', 'utf8')} | ||
*/`; | ||
return "/*\nCopyright (C) 2016 Timofey Kachalov <sanex3339@yandex.ru>\n\n" + | ||
fs.readFileSync('./LICENSE.BSD', 'utf8') + "\n*/"; | ||
} | ||
@@ -29,4 +26,3 @@ | ||
resolve: { | ||
extensions: ['', '.ts'], | ||
modulesDirectories: ['./src', './node_modules'] | ||
extensions: ['.ts'] | ||
}, | ||
@@ -36,7 +32,7 @@ plugins: [ | ||
{ | ||
banner: `${getLicenseText()}\n\nrequire("source-map-support").install();\n`, | ||
banner: getLicenseText() + '\n\nrequire("source-map-support").install();\n', | ||
raw: true, | ||
entryOnly: false | ||
} | ||
) | ||
), | ||
], | ||
@@ -49,2 +45,2 @@ output: { | ||
} | ||
}; | ||
}; |
Sorry, the diff of this file is too big to display
359983
1.63%147
0.68%7757
1.25%