js-confuser 1.7.0 → 1.7.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/README.md +0 -2
- package/dist/transforms/dispatcher.js +6 -0
- package/dist/transforms/extraction/duplicateLiteralsRemoval.js +6 -1
- package/dist/transforms/extraction/objectExtraction.js +6 -1
- package/dist/transforms/rgf.js +9 -1
- package/dist/util/identifiers.js +3 -3
- package/docs/ControlFlowFlattening.md +1 -1
- package/docs/ES5.md +197 -0
- package/package.json +2 -2
- package/src/transforms/dispatcher.ts +10 -0
- package/src/transforms/extraction/duplicateLiteralsRemoval.ts +5 -1
- package/src/transforms/extraction/objectExtraction.ts +4 -0
- package/src/transforms/rgf.ts +9 -0
- package/src/util/identifiers.ts +6 -3
- package/test/transforms/dispatcher.test.ts +27 -0
- package/test/transforms/extraction/duplicateLiteralsRemoval.test.ts +21 -8
- package/test/transforms/extraction/objectExtraction.test.ts +35 -15
- package/test/transforms/identifier/globalConcealing.test.ts +23 -2
- package/test/transforms/lock/integrity.test.ts +24 -0
- package/test/util/identifiers.test.ts +21 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
# `1.7.1`
|
|
2
|
+
Updates
|
|
3
|
+
|
|
4
|
+
- Fixed [#107](https://github.com/MichaelXF/js-confuser/issues/107)
|
|
5
|
+
- - RGF and Integrity clash issue fixed
|
|
6
|
+
|
|
7
|
+
- Fixed [#106](https://github.com/MichaelXF/js-confuser/issues/106)
|
|
8
|
+
- - Object Extraction to properly handle `const` objects
|
|
9
|
+
|
|
10
|
+
- Fixed [#105](https://github.com/MichaelXF/js-confuser/issues/105)
|
|
11
|
+
- - Duplicate Literals Removal updated to not cause this error
|
|
12
|
+
|
|
13
|
+
- Fixed [#103](https://github.com/MichaelXF/js-confuser/issues/103)
|
|
14
|
+
- - Dispatcher will no longer apply to these types of functions to prevent this error
|
|
15
|
+
|
|
16
|
+
- Added documentation page for [ES5](https://github.com/MichaelXF/js-confuser/blob/master/docs/ES5.md)
|
|
17
|
+
|
|
18
|
+
- Rollup Plugin created: https://github.com/ayecue/rollup-js-confuser (Thanks @ayecue !)
|
|
19
|
+
|
|
1
20
|
# `1.7.0`
|
|
2
21
|
Updates
|
|
3
22
|
|
package/README.md
CHANGED
|
@@ -737,7 +737,6 @@ function iVQoGQD(...iVQoGQD){
|
|
|
737
737
|
stringSplitting: 0.75,
|
|
738
738
|
|
|
739
739
|
// Use at own risk
|
|
740
|
-
eval: false,
|
|
741
740
|
rgf: false
|
|
742
741
|
}
|
|
743
742
|
```
|
|
@@ -828,7 +827,6 @@ These features are experimental or a security concern.
|
|
|
828
827
|
```js
|
|
829
828
|
{
|
|
830
829
|
target: "node",
|
|
831
|
-
eval: true, // (security concern)
|
|
832
830
|
rgf: true, // (security concern)
|
|
833
831
|
|
|
834
832
|
// set to false for web-related scripts
|
|
@@ -123,6 +123,12 @@ class Dispatcher extends _transform.default {
|
|
|
123
123
|
illegalFnNames.add(name);
|
|
124
124
|
return "EXIT";
|
|
125
125
|
}
|
|
126
|
+
} // Avoid functions with function expressions as they have a different scope
|
|
127
|
+
|
|
128
|
+
|
|
129
|
+
if ((oo.type === "FunctionExpression" || oo.type === "ArrowFunctionExpression") && pp.find(x => x == o.params)) {
|
|
130
|
+
illegalFnNames.add(name);
|
|
131
|
+
return "EXIT";
|
|
126
132
|
}
|
|
127
133
|
});
|
|
128
134
|
functionDeclarations[name] = [o, p];
|
|
@@ -25,6 +25,8 @@ var _random = require("../../util/random");
|
|
|
25
25
|
|
|
26
26
|
var _traverse = require("../../traverse");
|
|
27
27
|
|
|
28
|
+
var _identifiers = require("../../util/identifiers");
|
|
29
|
+
|
|
28
30
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
29
31
|
|
|
30
32
|
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
@@ -163,7 +165,10 @@ class DuplicateLiteralsRemoval extends _transform.default {
|
|
|
163
165
|
|
|
164
166
|
transform(object, parents) {
|
|
165
167
|
return () => {
|
|
166
|
-
|
|
168
|
+
if (object.type === "Identifier") {
|
|
169
|
+
var info = (0, _identifiers.getIdentifierInfo)(object, parents);
|
|
170
|
+
if (info.isLabel || info.spec.isDefined) return;
|
|
171
|
+
}
|
|
167
172
|
|
|
168
173
|
if (object.regex) {
|
|
169
174
|
return;
|
|
@@ -236,7 +236,12 @@ class ObjectExtraction extends _transform.default {
|
|
|
236
236
|
var v = property.value;
|
|
237
237
|
variableDeclarators.push((0, _gen.VariableDeclarator)(nn, this.addComment(v, "".concat(name, ".").concat(keyName))));
|
|
238
238
|
});
|
|
239
|
-
declaration.declarations.splice(declaration.declarations.indexOf(declarator), 1, ...variableDeclarators);
|
|
239
|
+
declaration.declarations.splice(declaration.declarations.indexOf(declarator), 1, ...variableDeclarators);
|
|
240
|
+
|
|
241
|
+
if (declaration.kind === "const") {
|
|
242
|
+
declaration.kind = "var";
|
|
243
|
+
} // update all identifiers that pointed to the old object
|
|
244
|
+
|
|
240
245
|
|
|
241
246
|
objectDefChanges[name] && objectDefChanges[name].forEach(change => {
|
|
242
247
|
if (!change.key) {
|
package/dist/transforms/rgf.js
CHANGED
|
@@ -23,6 +23,8 @@ var _identifiers = require("../util/identifiers");
|
|
|
23
23
|
|
|
24
24
|
var _insert = require("../util/insert");
|
|
25
25
|
|
|
26
|
+
var _integrity = _interopRequireDefault(require("./lock/integrity"));
|
|
27
|
+
|
|
26
28
|
var _transform = _interopRequireDefault(require("./transform"));
|
|
27
29
|
|
|
28
30
|
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
@@ -170,7 +172,13 @@ class RGF extends _transform.default {
|
|
|
170
172
|
});
|
|
171
173
|
|
|
172
174
|
if (obfuscator.options.lock) {
|
|
173
|
-
delete obfuscator.options.lock.countermeasures;
|
|
175
|
+
delete obfuscator.options.lock.countermeasures; // Integrity will not recursively apply to RGF'd functions. This is intended.
|
|
176
|
+
|
|
177
|
+
var lockTransform = obfuscator.transforms["Lock"];
|
|
178
|
+
|
|
179
|
+
if (lockTransform) {
|
|
180
|
+
lockTransform.before = lockTransform.before.filter(beforeTransform => !(beforeTransform instanceof _integrity.default));
|
|
181
|
+
}
|
|
174
182
|
}
|
|
175
183
|
|
|
176
184
|
var transforms = obfuscator.array.filter(x => x.priority > this.priority);
|
package/dist/util/identifiers.js
CHANGED
|
@@ -86,10 +86,11 @@ function getIdentifierInfo(object, parents) {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
var varIndex = parents.findIndex(x => x.type == "VariableDeclarator");
|
|
89
|
-
var isVariableDeclaration = varIndex != -1 && parents[varIndex].id == (parents[varIndex - 1] || object) && parents.find(x => x.type == "VariableDeclaration") && objectPatternCheck(object, parents);
|
|
89
|
+
var isVariableDeclaration = varIndex != -1 && parents[varIndex].id == (parents[varIndex - 1] || object) && parents.find(x => x.type == "VariableDeclaration") && objectPatternCheck(object, parents);
|
|
90
|
+
var functionIndex = parents.findIndex(x => (0, _insert.isFunction)(x)); // Assignment pattern check!
|
|
90
91
|
|
|
91
92
|
if (isVariableDeclaration) {
|
|
92
|
-
var slicedParents = parents.slice(0,
|
|
93
|
+
var slicedParents = parents.slice(0, functionIndex != -1 ? Math.min(varIndex, functionIndex) : varIndex);
|
|
93
94
|
var i = 0;
|
|
94
95
|
|
|
95
96
|
for (var parent of slicedParents) {
|
|
@@ -106,7 +107,6 @@ function getIdentifierInfo(object, parents) {
|
|
|
106
107
|
|
|
107
108
|
var forIndex = parents.findIndex(x => x.type == "ForStatement");
|
|
108
109
|
var isForInitializer = forIndex != -1 && parents[forIndex].init == (parents[forIndex - 1] || object);
|
|
109
|
-
var functionIndex = parents.findIndex(x => (0, _insert.isFunction)(x));
|
|
110
110
|
var isFunctionDeclaration = functionIndex != -1 && parents[functionIndex].type == "FunctionDeclaration" && parents[functionIndex].id == object;
|
|
111
111
|
var isNamedFunctionExpression = functionIndex != -1 && parents[functionIndex].type === "FunctionExpression" && parents[functionIndex].id === object;
|
|
112
112
|
var isAFunctionParameter = isFunctionParameter(object, parents);
|
|
@@ -137,7 +137,7 @@ while (mJMdMhJ + A1Nyvv + xDwpOk6 != 83) {
|
|
|
137
137
|
}
|
|
138
138
|
```
|
|
139
139
|
|
|
140
|
-
As seen in the example, your code will
|
|
140
|
+
As seen in the example, your code will be wrapped in a large, complicated switch statement. The makes the behavior of your program very hard to understand and is resistent to deobfuscators. This comes with a large performance reduction.
|
|
141
141
|
|
|
142
142
|
## Flattening Control Structures
|
|
143
143
|
|
package/docs/ES5.md
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
## `ES5`
|
|
2
|
+
|
|
3
|
+
The ES5 option converts most ES6+ features into ES5 compatible code.
|
|
4
|
+
|
|
5
|
+
Option name: `es5`
|
|
6
|
+
|
|
7
|
+
Option values: `true/false`
|
|
8
|
+
|
|
9
|
+
Note: Does not cover all cases such as Promises or Generator functions. Use [Babel](https://babel.dev/).
|
|
10
|
+
|
|
11
|
+
The ES5 option is intended to undo any ES6 feature the obfuscator adds to your code. If you input ES5 code, and enable the `es5` option, you can be guaranteed to have ES5 compatible output.
|
|
12
|
+
|
|
13
|
+
## Example
|
|
14
|
+
|
|
15
|
+
```js
|
|
16
|
+
// Input
|
|
17
|
+
function print(...messages){
|
|
18
|
+
console.log(...messages); // The spread operator (...)
|
|
19
|
+
// was introduced in ES6!
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
print("Hello", "World"); // "Hello World"
|
|
23
|
+
|
|
24
|
+
// Output
|
|
25
|
+
var __p_2580918143;
|
|
26
|
+
function print() {
|
|
27
|
+
var __p_7607361496;
|
|
28
|
+
var messages, __p_2591841272 = (__p_7607361496 = Array.prototype.slice.call(arguments), messages = __p_7607361496.slice(0));
|
|
29
|
+
(__p_2580918143 = console).log.apply(__p_2580918143, [].concat(Array.prototype.slice.call(messages)));
|
|
30
|
+
}
|
|
31
|
+
print('Hello', 'World'); // "Hello World"
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## Polyfill Array Methods
|
|
35
|
+
|
|
36
|
+
When the ES5 option is enabled, array method polyfills will be injected to the top of your script.
|
|
37
|
+
|
|
38
|
+
```js
|
|
39
|
+
if (!Array.prototype.forEach) {
|
|
40
|
+
Array.prototype.forEach = function forEach(callback, thisArg) {
|
|
41
|
+
if (typeof callback !== 'function') {
|
|
42
|
+
throw new TypeError(callback + ' is not a function');
|
|
43
|
+
}
|
|
44
|
+
var array = this;
|
|
45
|
+
thisArg = thisArg || this;
|
|
46
|
+
for (var i = 0, l = array.length; i !== l; ++i) {
|
|
47
|
+
callback.call(thisArg, array[i], i, array);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## Destructuring
|
|
54
|
+
|
|
55
|
+
The ES5 option supports transpiling the destructuring patterns.
|
|
56
|
+
|
|
57
|
+
```js
|
|
58
|
+
// Input
|
|
59
|
+
var {userName, email} = { userName: "John", email: "email@exampe.com" };
|
|
60
|
+
|
|
61
|
+
// Output
|
|
62
|
+
var __p_7467473759;
|
|
63
|
+
var userName, email, __p_4755992742 = (__p_7467473759 = {
|
|
64
|
+
userName: 'John',
|
|
65
|
+
email: 'email@exampe.com'
|
|
66
|
+
}, userName = __p_7467473759.userName, email = __p_7467473759.email);
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Spread Operator
|
|
70
|
+
|
|
71
|
+
The ES5 option supports transpiling the spread operator.
|
|
72
|
+
|
|
73
|
+
```js
|
|
74
|
+
// Input
|
|
75
|
+
array.push(...objects);
|
|
76
|
+
|
|
77
|
+
// Output
|
|
78
|
+
var __p_6344935930;
|
|
79
|
+
(__p_6344935930 = array).push.apply(__p_6344935930, [].concat(Array.prototype.slice.call(objects)));
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Template String
|
|
83
|
+
|
|
84
|
+
The ES5 option supports transpiling template strings.
|
|
85
|
+
|
|
86
|
+
```js
|
|
87
|
+
// Input
|
|
88
|
+
var myString = `Hello ${userName}`;
|
|
89
|
+
|
|
90
|
+
// Output
|
|
91
|
+
var myString = 'Hello ' + (userName + '');
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Object getters/setters
|
|
95
|
+
|
|
96
|
+
The ES5 option supports transpiling getter and setter methods.
|
|
97
|
+
|
|
98
|
+
```js
|
|
99
|
+
// Input
|
|
100
|
+
var _name;
|
|
101
|
+
var myObject = {
|
|
102
|
+
get name(){
|
|
103
|
+
return _name;
|
|
104
|
+
},
|
|
105
|
+
set name(newName){
|
|
106
|
+
_name = newName;
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// Output
|
|
111
|
+
function __p_6886881506(base, computedProps, getters, setters) {
|
|
112
|
+
for (var i = 0; i < computedProps.length; i++) {
|
|
113
|
+
base[computedProps[i][0]] = computedProps[i][1];
|
|
114
|
+
}
|
|
115
|
+
var keys = Object.create(null);
|
|
116
|
+
Object.keys(getters).forEach(function (key) {
|
|
117
|
+
return keys[key] = 1;
|
|
118
|
+
});
|
|
119
|
+
Object.keys(setters).forEach(function (key) {
|
|
120
|
+
return keys[key] = 1;
|
|
121
|
+
});
|
|
122
|
+
Object.keys(keys).forEach(function (key) {
|
|
123
|
+
Object.defineProperty(base, key, {
|
|
124
|
+
set: setters[key],
|
|
125
|
+
get: getters[key],
|
|
126
|
+
configurable: true
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
return base;
|
|
130
|
+
}
|
|
131
|
+
var _name;
|
|
132
|
+
var myObject = __p_6886881506({}, [], {
|
|
133
|
+
'name': function () {
|
|
134
|
+
return _name;
|
|
135
|
+
}
|
|
136
|
+
}, {
|
|
137
|
+
'name': function (newName) {
|
|
138
|
+
_name = newName;
|
|
139
|
+
}
|
|
140
|
+
});
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Arrow Functions
|
|
144
|
+
|
|
145
|
+
The ES5 option converts arrow functions into regular functions.
|
|
146
|
+
|
|
147
|
+
```js
|
|
148
|
+
// Input
|
|
149
|
+
var print = message => console.log(message);
|
|
150
|
+
|
|
151
|
+
// Output
|
|
152
|
+
var print = function (message) {
|
|
153
|
+
return console.log(message);
|
|
154
|
+
};
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## Const/Let
|
|
158
|
+
|
|
159
|
+
The ES5 option converts `const` and `let` to a regular `var` keyword.
|
|
160
|
+
|
|
161
|
+
```js
|
|
162
|
+
// Input
|
|
163
|
+
let myVar1 = true;
|
|
164
|
+
const myVar2 = "String";
|
|
165
|
+
|
|
166
|
+
// Output
|
|
167
|
+
var myVar1 = true;
|
|
168
|
+
var myVar2 = 'String';
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Classes
|
|
172
|
+
|
|
173
|
+
The ES5 option partially supports transpiling classes.
|
|
174
|
+
|
|
175
|
+
## Reserved Identifiers
|
|
176
|
+
|
|
177
|
+
The ES5 option will change any illegal uses of reserved identifiers.
|
|
178
|
+
|
|
179
|
+
```js
|
|
180
|
+
// Input
|
|
181
|
+
var myObject = {true: 1};
|
|
182
|
+
myObject.for = true;
|
|
183
|
+
|
|
184
|
+
// Output
|
|
185
|
+
var myObject = {"true": 1};
|
|
186
|
+
myObject["for"] = true;
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Features not supported
|
|
190
|
+
|
|
191
|
+
- Promises
|
|
192
|
+
- Async / Await
|
|
193
|
+
- Generator functions
|
|
194
|
+
- Nullish coalescing
|
|
195
|
+
- Optional chaining
|
|
196
|
+
|
|
197
|
+
Use [Babel](https://babel.dev/) to transpile these features. JS-Confuser will only support features the obfuscator may potentially add to your code.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "js-confuser",
|
|
3
|
-
"version": "1.7.
|
|
3
|
+
"version": "1.7.1",
|
|
4
4
|
"description": "JavaScript Obfuscation Tool.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "index.d.ts",
|
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
"author": "MichaelXF",
|
|
23
23
|
"license": "MIT",
|
|
24
24
|
"dependencies": {
|
|
25
|
-
"acorn": "^8.
|
|
25
|
+
"acorn": "^8.10.0",
|
|
26
26
|
"escodegen": "^2.0.0"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
@@ -157,6 +157,16 @@ export default class Dispatcher extends Transform {
|
|
|
157
157
|
return "EXIT";
|
|
158
158
|
}
|
|
159
159
|
}
|
|
160
|
+
|
|
161
|
+
// Avoid functions with function expressions as they have a different scope
|
|
162
|
+
if (
|
|
163
|
+
(oo.type === "FunctionExpression" ||
|
|
164
|
+
oo.type === "ArrowFunctionExpression") &&
|
|
165
|
+
pp.find((x) => x == o.params)
|
|
166
|
+
) {
|
|
167
|
+
illegalFnNames.add(name);
|
|
168
|
+
return "EXIT";
|
|
169
|
+
}
|
|
160
170
|
});
|
|
161
171
|
|
|
162
172
|
functionDeclarations[name] = [o, p];
|
|
@@ -24,6 +24,7 @@ import { ComputeProbabilityMap } from "../../probability";
|
|
|
24
24
|
import { ok } from "assert";
|
|
25
25
|
import { chance, choice, getRandomInteger } from "../../util/random";
|
|
26
26
|
import { getBlock } from "../../traverse";
|
|
27
|
+
import { getIdentifierInfo } from "../../util/identifiers";
|
|
27
28
|
|
|
28
29
|
/**
|
|
29
30
|
* [Duplicate Literals Removal](https://docs.jscrambler.com/code-integrity/documentation/transformations/duplicate-literals-removal) replaces duplicate literals with a variable name.
|
|
@@ -221,7 +222,10 @@ export default class DuplicateLiteralsRemoval extends Transform {
|
|
|
221
222
|
|
|
222
223
|
transform(object: Node, parents: Node[]) {
|
|
223
224
|
return () => {
|
|
224
|
-
|
|
225
|
+
if (object.type === "Identifier") {
|
|
226
|
+
var info = getIdentifierInfo(object, parents);
|
|
227
|
+
if (info.isLabel || info.spec.isDefined) return;
|
|
228
|
+
}
|
|
225
229
|
if (object.regex) {
|
|
226
230
|
return;
|
|
227
231
|
}
|
|
@@ -316,6 +316,10 @@ export default class ObjectExtraction extends Transform {
|
|
|
316
316
|
...variableDeclarators
|
|
317
317
|
);
|
|
318
318
|
|
|
319
|
+
if (declaration.kind === "const") {
|
|
320
|
+
declaration.kind = "var";
|
|
321
|
+
}
|
|
322
|
+
|
|
319
323
|
// update all identifiers that pointed to the old object
|
|
320
324
|
objectDefChanges[name] &&
|
|
321
325
|
objectDefChanges[name].forEach((change) => {
|
package/src/transforms/rgf.ts
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
} from "../util/gen";
|
|
21
21
|
import { getIdentifierInfo } from "../util/identifiers";
|
|
22
22
|
import { prepend, getDefiningContext } from "../util/insert";
|
|
23
|
+
import Integrity from "./lock/integrity";
|
|
23
24
|
import Transform from "./transform";
|
|
24
25
|
|
|
25
26
|
/**
|
|
@@ -200,6 +201,14 @@ export default class RGF extends Transform {
|
|
|
200
201
|
|
|
201
202
|
if (obfuscator.options.lock) {
|
|
202
203
|
delete obfuscator.options.lock.countermeasures;
|
|
204
|
+
|
|
205
|
+
// Integrity will not recursively apply to RGF'd functions. This is intended.
|
|
206
|
+
var lockTransform = obfuscator.transforms["Lock"];
|
|
207
|
+
if (lockTransform) {
|
|
208
|
+
lockTransform.before = lockTransform.before.filter(
|
|
209
|
+
(beforeTransform) => !(beforeTransform instanceof Integrity)
|
|
210
|
+
);
|
|
211
|
+
}
|
|
203
212
|
}
|
|
204
213
|
|
|
205
214
|
var transforms = obfuscator.array.filter(
|
package/src/util/identifiers.ts
CHANGED
|
@@ -94,9 +94,14 @@ export function getIdentifierInfo(object: Node, parents: Node[]) {
|
|
|
94
94
|
parents.find((x) => x.type == "VariableDeclaration") &&
|
|
95
95
|
objectPatternCheck(object, parents);
|
|
96
96
|
|
|
97
|
+
var functionIndex = parents.findIndex((x) => isFunction(x));
|
|
98
|
+
|
|
97
99
|
// Assignment pattern check!
|
|
98
100
|
if (isVariableDeclaration) {
|
|
99
|
-
var slicedParents = parents.slice(
|
|
101
|
+
var slicedParents = parents.slice(
|
|
102
|
+
0,
|
|
103
|
+
functionIndex != -1 ? Math.min(varIndex, functionIndex) : varIndex
|
|
104
|
+
);
|
|
100
105
|
var i = 0;
|
|
101
106
|
for (var parent of slicedParents) {
|
|
102
107
|
var childNode = slicedParents[i - 1] || object;
|
|
@@ -113,8 +118,6 @@ export function getIdentifierInfo(object: Node, parents: Node[]) {
|
|
|
113
118
|
forIndex != -1 &&
|
|
114
119
|
parents[forIndex].init == (parents[forIndex - 1] || object);
|
|
115
120
|
|
|
116
|
-
var functionIndex = parents.findIndex((x) => isFunction(x));
|
|
117
|
-
|
|
118
121
|
var isFunctionDeclaration =
|
|
119
122
|
functionIndex != -1 &&
|
|
120
123
|
parents[functionIndex].type == "FunctionDeclaration" &&
|
|
@@ -373,3 +373,30 @@ test("Variant #16: Don't change functions that use 'eval'", async () => {
|
|
|
373
373
|
|
|
374
374
|
expect(TEST_OUTPUT).toStrictEqual(2);
|
|
375
375
|
});
|
|
376
|
+
|
|
377
|
+
// https://github.com/MichaelXF/js-confuser/issues/103
|
|
378
|
+
test("Variant #17: Don't break default parameter, function expression", async () => {
|
|
379
|
+
var output = await JsConfuser(
|
|
380
|
+
`
|
|
381
|
+
var X = "Correct Value";
|
|
382
|
+
|
|
383
|
+
function printX(
|
|
384
|
+
getX = function () {
|
|
385
|
+
return X;
|
|
386
|
+
}
|
|
387
|
+
) {
|
|
388
|
+
var X = "Incorrect Value";
|
|
389
|
+
|
|
390
|
+
TEST_OUTPUT = getX();
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
printX();
|
|
394
|
+
`,
|
|
395
|
+
{ target: "node", dispatcher: true }
|
|
396
|
+
);
|
|
397
|
+
|
|
398
|
+
var TEST_OUTPUT;
|
|
399
|
+
eval(output);
|
|
400
|
+
|
|
401
|
+
expect(TEST_OUTPUT).toStrictEqual("Correct Value");
|
|
402
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import JsConfuser from "../../../src/index";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
test("Variant #1: Remove duplicate literals", async () => {
|
|
4
4
|
var code = `
|
|
5
5
|
|
|
6
6
|
var TEST_ARRAY = [5,5];
|
|
@@ -15,7 +15,7 @@ it("should remove duplicate literals", async () => {
|
|
|
15
15
|
expect(output).toContain("5");
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
test("Variant #2: Remove duplicate literals and execute correctly", async () => {
|
|
19
19
|
var code = `
|
|
20
20
|
|
|
21
21
|
TEST_ARRAY = [5,5];
|
|
@@ -36,7 +36,7 @@ it("should remove duplicate literals and execute correctly", async () => {
|
|
|
36
36
|
expect(TEST_ARRAY).toEqual([5, 5]);
|
|
37
37
|
});
|
|
38
38
|
|
|
39
|
-
|
|
39
|
+
test("Variant #3: Remove 'undefined' and 'null' values", async () => {
|
|
40
40
|
var code = `
|
|
41
41
|
|
|
42
42
|
TEST_ARRAY = [undefined,undefined,null,null];
|
|
@@ -60,7 +60,7 @@ it("should remove 'undefined' and 'null' values", async () => {
|
|
|
60
60
|
expect(TEST_ARRAY).toEqual([undefined, undefined, null, null]);
|
|
61
61
|
});
|
|
62
62
|
|
|
63
|
-
|
|
63
|
+
test("Variant #4: Do not remove empty strings", async () => {
|
|
64
64
|
var code = `
|
|
65
65
|
|
|
66
66
|
TEST_ARRAY = ['','','',''];
|
|
@@ -80,7 +80,7 @@ it("should not remove empty strings", async () => {
|
|
|
80
80
|
expect(TEST_ARRAY).toEqual(["", "", "", ""]);
|
|
81
81
|
});
|
|
82
82
|
|
|
83
|
-
|
|
83
|
+
test("Variant #5: Work with NaN values", async () => {
|
|
84
84
|
var code = `
|
|
85
85
|
|
|
86
86
|
TEST_ARRAY = [NaN];
|
|
@@ -98,7 +98,7 @@ it("should work with NaN values", async () => {
|
|
|
98
98
|
expect(TEST_ARRAY[0] === TEST_ARRAY[0]).toStrictEqual(false);
|
|
99
99
|
});
|
|
100
100
|
|
|
101
|
-
|
|
101
|
+
test("Variant #6: Work on property keys", async () => {
|
|
102
102
|
var code = `
|
|
103
103
|
var myObject = {
|
|
104
104
|
myKey: 100
|
|
@@ -124,7 +124,7 @@ it("should work on property keys", async () => {
|
|
|
124
124
|
expect(TEST_VAR).toStrictEqual(100);
|
|
125
125
|
});
|
|
126
126
|
|
|
127
|
-
|
|
127
|
+
test("Variant #7: Work on class keys", async () => {
|
|
128
128
|
var code = `
|
|
129
129
|
class MyClass {
|
|
130
130
|
myMethod(){
|
|
@@ -150,7 +150,7 @@ it("should work on class keys", async () => {
|
|
|
150
150
|
expect(TEST_VAR).toStrictEqual(100);
|
|
151
151
|
});
|
|
152
152
|
|
|
153
|
-
|
|
153
|
+
test("Variant #8: Do not encode constructor key", async () => {
|
|
154
154
|
var code = `
|
|
155
155
|
class MyClass {
|
|
156
156
|
constructor(){
|
|
@@ -177,3 +177,16 @@ it("should not encode constructor key", async () => {
|
|
|
177
177
|
|
|
178
178
|
expect(TEST_VAR).toStrictEqual(100);
|
|
179
179
|
});
|
|
180
|
+
|
|
181
|
+
// https://github.com/MichaelXF/js-confuser/issues/105
|
|
182
|
+
test("Variant #9: Undefined as variable name", async () => {
|
|
183
|
+
var output = await JsConfuser(
|
|
184
|
+
`
|
|
185
|
+
var undefined = 0;
|
|
186
|
+
var undefined = 1;
|
|
187
|
+
`,
|
|
188
|
+
{ target: "node", duplicateLiteralsRemoval: true }
|
|
189
|
+
);
|
|
190
|
+
|
|
191
|
+
eval(output);
|
|
192
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import JsConfuser from "../../../src/index";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
test("Variant #1: Extract properties", async () => {
|
|
4
4
|
var code = `
|
|
5
5
|
var TEST_OBJECT = {
|
|
6
6
|
TEST_1: "Hello World",
|
|
@@ -34,7 +34,7 @@ it("should extract properties", async () => {
|
|
|
34
34
|
eval(output);
|
|
35
35
|
});
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
test("Variant #2: Extract function properties correctly", async () => {
|
|
38
38
|
var code = `
|
|
39
39
|
var TEST_OBJECT = {
|
|
40
40
|
isBoolean: x=>typeof x === "boolean",
|
|
@@ -68,7 +68,7 @@ it("should extract function properties correctly", async () => {
|
|
|
68
68
|
eval(output);
|
|
69
69
|
});
|
|
70
70
|
|
|
71
|
-
|
|
71
|
+
test("Variant #3: Not extract properties on with dynamically added keys", async () => {
|
|
72
72
|
var code = `
|
|
73
73
|
var TEST_OBJECT = {
|
|
74
74
|
first_key: 1
|
|
@@ -100,7 +100,7 @@ it("should not extract properties on with dynamically added keys", async () => {
|
|
|
100
100
|
eval(output);
|
|
101
101
|
});
|
|
102
102
|
|
|
103
|
-
|
|
103
|
+
test("Variant #4: Not extract properties on with dynamically added keys even when in nested contexts", async () => {
|
|
104
104
|
var code = `
|
|
105
105
|
var TEST_OBJECT = {
|
|
106
106
|
first_key: 1
|
|
@@ -135,7 +135,7 @@ it("should not extract properties on with dynamically added keys even when in ne
|
|
|
135
135
|
eval(output);
|
|
136
136
|
});
|
|
137
137
|
|
|
138
|
-
|
|
138
|
+
test("Variant #5: Not extract properties on objects with computed properties", async () => {
|
|
139
139
|
var code = `
|
|
140
140
|
|
|
141
141
|
var key = "111"
|
|
@@ -166,7 +166,7 @@ it("should not extract properties on objects with computed properties", async ()
|
|
|
166
166
|
eval(output);
|
|
167
167
|
});
|
|
168
168
|
|
|
169
|
-
|
|
169
|
+
test("Variant #6: Not extract properties on objects with computed properties (string)", async () => {
|
|
170
170
|
var code = `
|
|
171
171
|
|
|
172
172
|
var v = "key";
|
|
@@ -197,7 +197,7 @@ it("should not extract properties on objects with computed properties (string)",
|
|
|
197
197
|
eval(output);
|
|
198
198
|
});
|
|
199
199
|
|
|
200
|
-
|
|
200
|
+
test("Variant #7: Not extract properties on objects when the object is referenced independently", async () => {
|
|
201
201
|
var code = `
|
|
202
202
|
|
|
203
203
|
var TEST_OBJECT = {
|
|
@@ -229,7 +229,7 @@ it("should not extract properties on objects when the object is referenced indep
|
|
|
229
229
|
eval(output);
|
|
230
230
|
});
|
|
231
231
|
|
|
232
|
-
|
|
232
|
+
test("Variant #8: Not extract properties on objects when the variable gets redefined", async () => {
|
|
233
233
|
var code = `
|
|
234
234
|
|
|
235
235
|
var TEST_OBJECT = {
|
|
@@ -260,7 +260,7 @@ it("should not extract properties on objects when the variable gets redefined",
|
|
|
260
260
|
eval(output);
|
|
261
261
|
});
|
|
262
262
|
|
|
263
|
-
|
|
263
|
+
test("Variant #9: Not extract properties on objects when the variable gets reassigned", async () => {
|
|
264
264
|
var code = `
|
|
265
265
|
|
|
266
266
|
var TEST_OBJECT = {
|
|
@@ -292,7 +292,7 @@ it("should not extract properties on objects when the variable gets reassigned",
|
|
|
292
292
|
eval(output);
|
|
293
293
|
});
|
|
294
294
|
|
|
295
|
-
|
|
295
|
+
test("Variant #10: Not extract properties on objects with methods referencing 'this'", async () => {
|
|
296
296
|
var code = `
|
|
297
297
|
|
|
298
298
|
var TEST_OBJECT = {
|
|
@@ -325,7 +325,7 @@ it("should not extract properties on objects with methods referencing 'this'", a
|
|
|
325
325
|
eval(output);
|
|
326
326
|
});
|
|
327
327
|
|
|
328
|
-
|
|
328
|
+
test("Variant #11: Not extract properties on objects when properties are dynamically deleted", async () => {
|
|
329
329
|
var code = `
|
|
330
330
|
|
|
331
331
|
var TEST_OBJECT = {
|
|
@@ -356,7 +356,7 @@ it("should not extract properties on objects when properties are dynamically del
|
|
|
356
356
|
eval(output);
|
|
357
357
|
});
|
|
358
358
|
|
|
359
|
-
|
|
359
|
+
test("Variant #12: Not extract properties on objects with computed accessors", async () => {
|
|
360
360
|
var code = `
|
|
361
361
|
|
|
362
362
|
var TEST_OBJECT = {
|
|
@@ -388,7 +388,7 @@ it("should not extract properties on objects with computed accessors", async ()
|
|
|
388
388
|
eval(output);
|
|
389
389
|
});
|
|
390
390
|
|
|
391
|
-
|
|
391
|
+
test("Variant #13: Properly use custom callback to exclude certain names from being changed", async () => {
|
|
392
392
|
var code = `
|
|
393
393
|
|
|
394
394
|
var TEST_OBJECT = {
|
|
@@ -424,7 +424,7 @@ it("should properly use custom callback to exclude certain names from being chan
|
|
|
424
424
|
eval(output);
|
|
425
425
|
});
|
|
426
426
|
|
|
427
|
-
|
|
427
|
+
test("Variant #14: Not apply to objects with non-init properties (method, set, get)", async () => {
|
|
428
428
|
var code = `
|
|
429
429
|
|
|
430
430
|
var realValue = 0;
|
|
@@ -448,7 +448,7 @@ it("should not apply to objects with non-init properties (method, set, get)", as
|
|
|
448
448
|
});
|
|
449
449
|
|
|
450
450
|
// https://github.com/MichaelXF/js-confuser/issues/78
|
|
451
|
-
|
|
451
|
+
test("Variant #15: Handle objects with spread elements", async () => {
|
|
452
452
|
var output = await JsConfuser(
|
|
453
453
|
`
|
|
454
454
|
var x = { firstName: "John", lastName: "Doe" }
|
|
@@ -467,3 +467,23 @@ it("should handle objects with spread elements", async () => {
|
|
|
467
467
|
|
|
468
468
|
expect(TEST_OUTPUT).toStrictEqual({ firstName: "John", lastName: "Doe" });
|
|
469
469
|
});
|
|
470
|
+
|
|
471
|
+
// https://github.com/MichaelXF/js-confuser/issues/106
|
|
472
|
+
test("Variant #16: Handle const declarations", async () => {
|
|
473
|
+
var output = await JsConfuser(
|
|
474
|
+
`
|
|
475
|
+
const obj = {prop: 0};
|
|
476
|
+
obj.prop = 1;
|
|
477
|
+
TEST_OUTPUT = obj.prop;
|
|
478
|
+
`,
|
|
479
|
+
{
|
|
480
|
+
target: "node",
|
|
481
|
+
objectExtraction: true,
|
|
482
|
+
}
|
|
483
|
+
);
|
|
484
|
+
|
|
485
|
+
var TEST_OUTPUT;
|
|
486
|
+
eval(output);
|
|
487
|
+
|
|
488
|
+
expect(TEST_OUTPUT).toStrictEqual(1);
|
|
489
|
+
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import JsConfuser from "../../../src/index";
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
test("Variant #1: Hide global names (such as Math)", async () => {
|
|
4
4
|
var code = `
|
|
5
5
|
var TEST_RESULT = Math.floor(10.1);
|
|
6
6
|
`;
|
|
@@ -16,7 +16,7 @@ it("should hide global names (such as Math)", async () => {
|
|
|
16
16
|
expect(output).toContain("window");
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
test("Variant #2: Do not hide modified identifiers", async () => {
|
|
20
20
|
var code = `
|
|
21
21
|
var Math = 50;
|
|
22
22
|
|
|
@@ -30,3 +30,24 @@ it("should not rename global variables", async () => {
|
|
|
30
30
|
|
|
31
31
|
expect(output).toContain("log'](Math)");
|
|
32
32
|
});
|
|
33
|
+
|
|
34
|
+
test("Variant #3: Properly hide in default parameter, function expression", async () => {
|
|
35
|
+
var output = await JsConfuser(
|
|
36
|
+
`
|
|
37
|
+
function myFunction( myParameter = function(){
|
|
38
|
+
var myVariable = true;
|
|
39
|
+
return myVariable;
|
|
40
|
+
} ) {
|
|
41
|
+
return myParameter();
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
TEST_OUTPUT = myFunction(); // true
|
|
45
|
+
`,
|
|
46
|
+
{ target: "node", globalConcealing: true }
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
var TEST_OUTPUT;
|
|
50
|
+
eval(output);
|
|
51
|
+
|
|
52
|
+
expect(TEST_OUTPUT).toStrictEqual(true);
|
|
53
|
+
});
|
|
@@ -135,3 +135,27 @@ it("should work on High Preset", async () => {
|
|
|
135
135
|
|
|
136
136
|
expect(TEST_OUTPUT).toStrictEqual("Hello World");
|
|
137
137
|
});
|
|
138
|
+
|
|
139
|
+
it("should work with RGF enabled", async () => {
|
|
140
|
+
var output = await JsConfuser(
|
|
141
|
+
`
|
|
142
|
+
function getTestOutput(){
|
|
143
|
+
return "Hello World";
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
TEST_OUTPUT = getTestOutput();
|
|
147
|
+
`,
|
|
148
|
+
{
|
|
149
|
+
target: "node",
|
|
150
|
+
rgf: true,
|
|
151
|
+
lock: {
|
|
152
|
+
integrity: true,
|
|
153
|
+
},
|
|
154
|
+
}
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
var TEST_OUTPUT;
|
|
158
|
+
eval(output);
|
|
159
|
+
|
|
160
|
+
expect(TEST_OUTPUT).toStrictEqual("Hello World");
|
|
161
|
+
});
|
|
@@ -153,6 +153,27 @@ describe("getIdentifierInfo", () => {
|
|
|
153
153
|
expect(nonModifiedInfo.spec.isModified).toStrictEqual(false);
|
|
154
154
|
expect(nonModifiedInfo.spec.isReferenced).toStrictEqual(false);
|
|
155
155
|
});
|
|
156
|
+
|
|
157
|
+
test("Variant #7: Default parameter, function expression", async () => {
|
|
158
|
+
var tree = parseSync(`
|
|
159
|
+
function myFunction( myParameter = function() {
|
|
160
|
+
var myNestedDeclaration = true;
|
|
161
|
+
} ){
|
|
162
|
+
|
|
163
|
+
}
|
|
164
|
+
`);
|
|
165
|
+
|
|
166
|
+
var myNestedDeclaration = findIdentifier(tree, "myNestedDeclaration");
|
|
167
|
+
var myNestedDeclarationInfo = getIdentifierInfo(
|
|
168
|
+
myNestedDeclaration[0],
|
|
169
|
+
myNestedDeclaration[1]
|
|
170
|
+
);
|
|
171
|
+
|
|
172
|
+
expect(myNestedDeclarationInfo.isVariableDeclaration).toStrictEqual(true);
|
|
173
|
+
expect(myNestedDeclarationInfo.spec.isDefined).toStrictEqual(true);
|
|
174
|
+
expect(myNestedDeclarationInfo.spec.isReferenced).toStrictEqual(true);
|
|
175
|
+
expect(myNestedDeclarationInfo.spec.isModified).toStrictEqual(false);
|
|
176
|
+
});
|
|
156
177
|
});
|
|
157
178
|
|
|
158
179
|
describe("validateChain", () => {
|