js-confuser 1.5.9 → 1.7.0
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/.github/workflows/node.js.yml +2 -2
- package/CHANGELOG.md +55 -0
- package/README.md +346 -165
- package/dist/constants.js +6 -2
- package/dist/index.js +9 -21
- package/dist/obfuscator.js +19 -31
- package/dist/options.js +5 -5
- package/dist/order.js +1 -3
- package/dist/presets.js +6 -7
- package/dist/probability.js +2 -4
- package/dist/templates/bufferToString.js +13 -0
- package/dist/templates/crash.js +3 -3
- package/dist/templates/es5.js +18 -0
- package/dist/templates/functionLength.js +16 -0
- package/dist/transforms/calculator.js +77 -21
- package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +980 -367
- package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +4 -1
- package/dist/transforms/controlFlowFlattening/switchCaseObfuscation.js +25 -26
- package/dist/transforms/deadCode.js +33 -25
- package/dist/transforms/dispatcher.js +8 -4
- package/dist/transforms/es5/antiDestructuring.js +2 -0
- package/dist/transforms/es5/es5.js +31 -34
- package/dist/transforms/extraction/duplicateLiteralsRemoval.js +92 -58
- package/dist/transforms/finalizer.js +82 -0
- package/dist/transforms/flatten.js +229 -148
- package/dist/transforms/identifier/globalAnalysis.js +88 -0
- package/dist/transforms/identifier/globalConcealing.js +10 -83
- package/dist/transforms/identifier/movedDeclarations.js +35 -88
- package/dist/transforms/identifier/renameVariables.js +124 -59
- package/dist/transforms/identifier/variableAnalysis.js +58 -62
- package/dist/transforms/lock/lock.js +0 -37
- package/dist/transforms/minify.js +60 -57
- package/dist/transforms/opaquePredicates.js +1 -1
- package/dist/transforms/preparation/preparation.js +2 -2
- package/dist/transforms/preparation.js +231 -0
- package/dist/transforms/renameLabels.js +1 -1
- package/dist/transforms/rgf.js +139 -247
- package/dist/transforms/stack.js +128 -26
- package/dist/transforms/string/encoding.js +150 -179
- package/dist/transforms/string/stringCompression.js +14 -15
- package/dist/transforms/string/stringConcealing.js +25 -8
- package/dist/transforms/string/stringEncoding.js +13 -24
- package/dist/transforms/transform.js +12 -19
- package/dist/traverse.js +24 -10
- package/dist/util/gen.js +17 -1
- package/dist/util/identifiers.js +37 -3
- package/dist/util/insert.js +35 -4
- package/dist/util/random.js +15 -0
- package/docs/ControlFlowFlattening.md +595 -0
- package/{Countermeasures.md → docs/Countermeasures.md} +1 -15
- package/{Integrity.md → docs/Integrity.md} +2 -2
- package/docs/RGF.md +419 -0
- package/package.json +5 -5
- package/src/constants.ts +3 -0
- package/src/index.ts +2 -2
- package/src/obfuscator.ts +19 -31
- package/src/options.ts +14 -103
- package/src/order.ts +1 -5
- package/src/presets.ts +6 -7
- package/src/probability.ts +2 -3
- package/src/templates/bufferToString.ts +68 -0
- package/src/templates/crash.ts +15 -19
- package/src/templates/es5.ts +131 -0
- package/src/templates/functionLength.ts +14 -0
- package/src/transforms/calculator.ts +122 -59
- package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +1583 -571
- package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +4 -1
- package/src/transforms/deadCode.ts +383 -26
- package/src/transforms/dispatcher.ts +9 -4
- package/src/transforms/es5/antiDestructuring.ts +2 -0
- package/src/transforms/es5/es5.ts +32 -77
- package/src/transforms/extraction/duplicateLiteralsRemoval.ts +133 -129
- package/src/transforms/{hexadecimalNumbers.ts → finalizer.ts} +29 -13
- package/src/transforms/flatten.ts +357 -300
- package/src/transforms/identifier/globalAnalysis.ts +85 -0
- package/src/transforms/identifier/globalConcealing.ts +14 -103
- package/src/transforms/identifier/movedDeclarations.ts +49 -102
- package/src/transforms/identifier/renameVariables.ts +149 -78
- package/src/transforms/identifier/variableAnalysis.ts +66 -73
- package/src/transforms/lock/lock.ts +1 -42
- package/src/transforms/minify.ts +91 -75
- package/src/transforms/opaquePredicates.ts +2 -2
- package/src/transforms/preparation.ts +238 -0
- package/src/transforms/renameLabels.ts +2 -2
- package/src/transforms/rgf.ts +213 -405
- package/src/transforms/stack.ts +156 -36
- package/src/transforms/string/encoding.ts +115 -212
- package/src/transforms/string/stringCompression.ts +27 -18
- package/src/transforms/string/stringConcealing.ts +39 -9
- package/src/transforms/string/stringEncoding.ts +18 -18
- package/src/transforms/transform.ts +21 -23
- package/src/traverse.ts +23 -4
- package/src/types.ts +2 -1
- package/src/util/gen.ts +28 -3
- package/src/util/identifiers.ts +43 -2
- package/src/util/insert.ts +38 -3
- package/src/util/random.ts +13 -0
- package/test/code/Cash.test.ts +1 -1
- package/test/code/Dynamic.test.ts +12 -10
- package/test/code/ES6.src.js +146 -0
- package/test/code/ES6.test.ts +28 -2
- package/test/index.test.ts +2 -1
- package/test/probability.test.ts +44 -0
- package/test/templates/template.test.ts +1 -1
- package/test/transforms/antiTooling.test.ts +22 -0
- package/test/transforms/calculator.test.ts +40 -0
- package/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts +702 -160
- package/test/transforms/controlFlowFlattening/expressionObfuscation.test.ts +173 -0
- package/test/transforms/deadCode.test.ts +66 -15
- package/test/transforms/dispatcher.test.ts +20 -1
- package/test/transforms/es5/antiDestructuring.test.ts +16 -0
- package/test/transforms/flatten.test.ts +399 -86
- package/test/transforms/identifier/movedDeclarations.test.ts +63 -8
- package/test/transforms/identifier/renameVariables.test.ts +119 -0
- package/test/transforms/lock/antiDebug.test.ts +2 -2
- package/test/transforms/lock/lock.test.ts +1 -48
- package/test/transforms/minify.test.ts +104 -0
- package/test/transforms/preparation.test.ts +157 -0
- package/test/transforms/rgf.test.ts +261 -381
- package/test/transforms/stack.test.ts +143 -21
- package/test/transforms/string/stringCompression.test.ts +39 -0
- package/test/transforms/string/stringConcealing.test.ts +82 -0
- package/test/transforms/string/stringEncoding.test.ts +53 -2
- package/test/transforms/transform.test.ts +66 -0
- package/test/traverse.test.ts +139 -0
- package/test/util/identifiers.test.ts +113 -1
- package/test/util/insert.test.ts +57 -3
- package/src/transforms/controlFlowFlattening/choiceFlowObfuscation.ts +0 -87
- package/src/transforms/controlFlowFlattening/controlFlowObfuscation.ts +0 -203
- package/src/transforms/controlFlowFlattening/switchCaseObfuscation.ts +0 -130
- package/src/transforms/eval.ts +0 -89
- package/src/transforms/hideInitializingCode.ts +0 -432
- package/src/transforms/identifier/nameRecycling.ts +0 -280
- package/src/transforms/label.ts +0 -64
- package/src/transforms/preparation/nameConflicts.ts +0 -102
- package/src/transforms/preparation/preparation.ts +0 -176
- package/test/transforms/controlFlowFlattening/controlFlowObfuscation.test.ts +0 -101
- package/test/transforms/controlFlowFlattening/switchCaseObfuscation.test.ts +0 -120
- package/test/transforms/eval.test.ts +0 -131
- package/test/transforms/hideInitializingCode.test.ts +0 -336
- package/test/transforms/identifier/nameRecycling.test.ts +0 -205
- package/test/transforms/preparation/nameConflicts.test.ts +0 -52
- package/test/transforms/preparation/preparation.test.ts +0 -62
|
@@ -1,17 +1,14 @@
|
|
|
1
1
|
import { ok } from "assert";
|
|
2
|
-
import { reservedIdentifiers } from "../constants";
|
|
2
|
+
import { noRenameVariablePrefix, reservedIdentifiers } from "../constants";
|
|
3
3
|
import { ObfuscateOrder } from "../order";
|
|
4
|
-
import
|
|
4
|
+
import { walk } from "../traverse";
|
|
5
5
|
import {
|
|
6
|
-
FunctionDeclaration,
|
|
7
6
|
Identifier,
|
|
8
7
|
ReturnStatement,
|
|
9
8
|
VariableDeclaration,
|
|
10
9
|
VariableDeclarator,
|
|
11
10
|
CallExpression,
|
|
12
11
|
MemberExpression,
|
|
13
|
-
ThisExpression,
|
|
14
|
-
ArrayExpression,
|
|
15
12
|
ExpressionStatement,
|
|
16
13
|
AssignmentExpression,
|
|
17
14
|
Node,
|
|
@@ -20,78 +17,94 @@ import {
|
|
|
20
17
|
FunctionExpression,
|
|
21
18
|
ObjectExpression,
|
|
22
19
|
Property,
|
|
23
|
-
SpreadElement,
|
|
24
20
|
Literal,
|
|
25
|
-
IfStatement,
|
|
26
|
-
ThrowStatement,
|
|
27
|
-
NewExpression,
|
|
28
21
|
AwaitExpression,
|
|
22
|
+
FunctionDeclaration,
|
|
23
|
+
SpreadElement,
|
|
29
24
|
UnaryExpression,
|
|
25
|
+
RestElement,
|
|
30
26
|
} from "../util/gen";
|
|
31
27
|
import { getIdentifierInfo } from "../util/identifiers";
|
|
32
28
|
import {
|
|
33
29
|
getBlockBody,
|
|
34
|
-
getVarContext,
|
|
35
|
-
isFunction,
|
|
36
30
|
prepend,
|
|
37
31
|
clone,
|
|
32
|
+
getDefiningContext,
|
|
33
|
+
computeFunctionLength,
|
|
38
34
|
} from "../util/insert";
|
|
39
35
|
import { shuffle } from "../util/random";
|
|
40
36
|
import Transform from "./transform";
|
|
37
|
+
import { FunctionLengthTemplate } from "../templates/functionLength";
|
|
41
38
|
|
|
42
39
|
/**
|
|
43
|
-
*
|
|
40
|
+
* Flatten takes functions and isolates them from their original scope, and brings it to the top level of the program.
|
|
41
|
+
*
|
|
42
|
+
* An additional `flatObject` parameter is passed in, giving access to the original scoped variables.
|
|
44
43
|
*
|
|
45
|
-
*
|
|
44
|
+
* The `flatObject` uses `get` and `set` properties to allow easy an AST transformation:
|
|
46
45
|
*
|
|
47
46
|
* ```js
|
|
48
|
-
*
|
|
49
|
-
*
|
|
47
|
+
* // Input
|
|
48
|
+
* function myFunction(myParam){
|
|
49
|
+
* modified = true;
|
|
50
|
+
* if(reference) {
|
|
51
|
+
*
|
|
52
|
+
* }
|
|
53
|
+
* ...
|
|
54
|
+
* console.log(myParam);
|
|
55
|
+
* }
|
|
56
|
+
*
|
|
57
|
+
* // Output
|
|
58
|
+
* function myFunction_flat([myParam], flatObject){
|
|
59
|
+
* flatObject["set_modified"] = true;
|
|
60
|
+
* if(flatObject["get_reference"]) {
|
|
61
|
+
*
|
|
62
|
+
* }
|
|
63
|
+
* ...
|
|
64
|
+
* console.log(myParam)
|
|
65
|
+
* }
|
|
66
|
+
*
|
|
67
|
+
* function myFunction(){
|
|
68
|
+
* var flatObject = {
|
|
69
|
+
* set set_modified(v) { modified = v }
|
|
70
|
+
* get get_reference() { return reference }
|
|
71
|
+
* }
|
|
72
|
+
* return myFunction_flat([...arguments], flatObject)
|
|
50
73
|
* }
|
|
51
74
|
* ```
|
|
52
75
|
*
|
|
53
76
|
* Flatten is used to make functions eligible for the RGF transformation.
|
|
77
|
+
*
|
|
78
|
+
* - `myFunction_flat` is now eligible because it does not rely on outside scoped variables
|
|
54
79
|
*/
|
|
55
80
|
export default class Flatten extends Transform {
|
|
81
|
+
isDebug = false;
|
|
82
|
+
|
|
56
83
|
definedNames: Map<Node, Set<string>>;
|
|
84
|
+
|
|
85
|
+
// Array of FunctionDeclaration nodes
|
|
57
86
|
flattenedFns: Node[];
|
|
58
87
|
gen: ReturnType<Transform["getGenerator"]>;
|
|
59
88
|
|
|
89
|
+
functionLengthName: string;
|
|
90
|
+
|
|
60
91
|
constructor(o) {
|
|
61
92
|
super(o, ObfuscateOrder.Flatten);
|
|
62
93
|
|
|
63
94
|
this.definedNames = new Map();
|
|
64
95
|
this.flattenedFns = [];
|
|
65
|
-
this.gen = this.getGenerator();
|
|
96
|
+
this.gen = this.getGenerator("mangled");
|
|
97
|
+
|
|
98
|
+
if (this.isDebug) {
|
|
99
|
+
console.warn("Flatten debug mode");
|
|
100
|
+
}
|
|
66
101
|
}
|
|
67
102
|
|
|
68
103
|
apply(tree) {
|
|
69
|
-
traverse(tree, (o, p) => {
|
|
70
|
-
if (
|
|
71
|
-
o.type == "Identifier" &&
|
|
72
|
-
!reservedIdentifiers.has(o.name) &&
|
|
73
|
-
!this.options.globalVariables.has(o.name)
|
|
74
|
-
) {
|
|
75
|
-
var info = getIdentifierInfo(o, p);
|
|
76
|
-
if (info.spec.isReferenced) {
|
|
77
|
-
if (info.spec.isDefined) {
|
|
78
|
-
var c = getVarContext(o, p);
|
|
79
|
-
if (c) {
|
|
80
|
-
if (!this.definedNames.has(c)) {
|
|
81
|
-
this.definedNames.set(c, new Set([o.name]));
|
|
82
|
-
} else {
|
|
83
|
-
this.definedNames.get(c).add(o.name);
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
|
|
91
104
|
super.apply(tree);
|
|
92
105
|
|
|
93
106
|
if (this.flattenedFns.length) {
|
|
94
|
-
prepend(tree,
|
|
107
|
+
prepend(tree, ...this.flattenedFns);
|
|
95
108
|
}
|
|
96
109
|
}
|
|
97
110
|
|
|
@@ -100,6 +113,7 @@ export default class Flatten extends Transform {
|
|
|
100
113
|
(object.type == "FunctionDeclaration" ||
|
|
101
114
|
object.type === "FunctionExpression") &&
|
|
102
115
|
object.body.type == "BlockStatement" &&
|
|
116
|
+
!object.$requiresEval &&
|
|
103
117
|
!object.generator &&
|
|
104
118
|
!object.params.find((x) => x.type !== "Identifier")
|
|
105
119
|
);
|
|
@@ -120,7 +134,7 @@ export default class Flatten extends Transform {
|
|
|
120
134
|
if (
|
|
121
135
|
parents[0].type === "Property" &&
|
|
122
136
|
parents[0].value === object &&
|
|
123
|
-
parents[0].kind !== "init"
|
|
137
|
+
(parents[0].kind !== "init" || parents[0].method)
|
|
124
138
|
) {
|
|
125
139
|
return;
|
|
126
140
|
}
|
|
@@ -140,36 +154,37 @@ export default class Flatten extends Transform {
|
|
|
140
154
|
parents[0].id?.name;
|
|
141
155
|
|
|
142
156
|
if (parents[0]?.type === "Property" && parents[0]?.key) {
|
|
143
|
-
currentFnName =
|
|
144
|
-
currentFnName ||
|
|
145
|
-
String(parents[0]?.key?.name || parents[0]?.key?.value);
|
|
157
|
+
currentFnName = currentFnName || String(parents[0]?.key?.name);
|
|
146
158
|
}
|
|
147
159
|
|
|
148
160
|
if (!currentFnName) currentFnName = "unnamed";
|
|
149
161
|
|
|
150
|
-
var
|
|
151
|
-
var references = new Set<string>();
|
|
152
|
-
var modified = new Set<string>();
|
|
162
|
+
var definedMap = new Map<Node, Set<string>>();
|
|
153
163
|
|
|
154
164
|
var illegal = new Set<string>();
|
|
155
165
|
var isIllegal = false;
|
|
156
166
|
|
|
157
|
-
var
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
set.forEach((name) => definedAbove.add(name));
|
|
163
|
-
}
|
|
164
|
-
});
|
|
167
|
+
var identifierNodes: [
|
|
168
|
+
Node,
|
|
169
|
+
Node[],
|
|
170
|
+
ReturnType<typeof getIdentifierInfo>
|
|
171
|
+
][] = [];
|
|
165
172
|
|
|
166
173
|
walk(object, parents, (o, p) => {
|
|
167
|
-
if (
|
|
168
|
-
|
|
174
|
+
if (
|
|
175
|
+
(o.type === "Identifier" && o.name === "arguments") ||
|
|
176
|
+
(o.type === "UnaryExpression" && o.operator === "delete") ||
|
|
177
|
+
o.type == "ThisExpression" ||
|
|
178
|
+
o.type == "Super" ||
|
|
179
|
+
o.type == "MetaProperty"
|
|
180
|
+
) {
|
|
181
|
+
isIllegal = true;
|
|
182
|
+
return "EXIT";
|
|
169
183
|
}
|
|
170
184
|
|
|
171
185
|
if (
|
|
172
186
|
o.type == "Identifier" &&
|
|
187
|
+
o !== object.id &&
|
|
173
188
|
!this.options.globalVariables.has(o.name) &&
|
|
174
189
|
!reservedIdentifiers.has(o.name)
|
|
175
190
|
) {
|
|
@@ -178,45 +193,36 @@ export default class Flatten extends Transform {
|
|
|
178
193
|
return;
|
|
179
194
|
}
|
|
180
195
|
|
|
181
|
-
if (
|
|
196
|
+
if (
|
|
197
|
+
info.spec.isExported ||
|
|
198
|
+
o.name.startsWith(noRenameVariablePrefix)
|
|
199
|
+
) {
|
|
182
200
|
illegal.add(o.name);
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
} else if (info.spec.isModified) {
|
|
186
|
-
modified.add(o.name);
|
|
187
|
-
} else {
|
|
188
|
-
references.add(o.name);
|
|
201
|
+
|
|
202
|
+
return;
|
|
189
203
|
}
|
|
190
|
-
}
|
|
191
204
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
return "EXIT";
|
|
195
|
-
}
|
|
205
|
+
if (info.spec.isDefined) {
|
|
206
|
+
var definingContext = getDefiningContext(o, p);
|
|
196
207
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
208
|
+
if (!definedMap.has(definingContext)) {
|
|
209
|
+
definedMap.set(definingContext, new Set([o.name]));
|
|
210
|
+
} else {
|
|
211
|
+
definedMap.get(definingContext).add(o.name);
|
|
212
|
+
}
|
|
213
|
+
return;
|
|
201
214
|
}
|
|
202
|
-
}
|
|
203
215
|
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
}
|
|
216
|
+
var isDefined = p.find(
|
|
217
|
+
(x) => definedMap.has(x) && definedMap.get(x).has(o.name)
|
|
218
|
+
);
|
|
208
219
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
if (o.type == "MetaProperty") {
|
|
215
|
-
isIllegal = true;
|
|
216
|
-
return "EXIT";
|
|
220
|
+
if (!isDefined) {
|
|
221
|
+
identifierNodes.push([o, p, info]);
|
|
222
|
+
}
|
|
217
223
|
}
|
|
218
224
|
|
|
219
|
-
if (o.type == "
|
|
225
|
+
if (o.type == "TryStatement") {
|
|
220
226
|
isIllegal = true;
|
|
221
227
|
return "EXIT";
|
|
222
228
|
}
|
|
@@ -229,257 +235,308 @@ export default class Flatten extends Transform {
|
|
|
229
235
|
return;
|
|
230
236
|
}
|
|
231
237
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
modified.delete(name);
|
|
235
|
-
});
|
|
238
|
+
var newFnName = this.getPlaceholder() + "_flat_" + currentFnName;
|
|
239
|
+
var flatObjectName = this.getPlaceholder() + "_flat_object";
|
|
236
240
|
|
|
237
|
-
|
|
241
|
+
const getFlatObjectMember = (propertyName: string) => {
|
|
242
|
+
return MemberExpression(
|
|
243
|
+
Identifier(flatObjectName),
|
|
244
|
+
Literal(propertyName),
|
|
245
|
+
true
|
|
246
|
+
);
|
|
247
|
+
};
|
|
238
248
|
|
|
239
|
-
var
|
|
249
|
+
var getterPropNames: { [identifierName: string]: string } =
|
|
250
|
+
Object.create(null);
|
|
251
|
+
var setterPropNames: { [identifierName: string]: string } =
|
|
252
|
+
Object.create(null);
|
|
253
|
+
var typeofPropNames: { [identifierName: string]: string } =
|
|
254
|
+
Object.create(null);
|
|
255
|
+
var callPropNames: { [identifierName: string]: string } =
|
|
256
|
+
Object.create(null);
|
|
240
257
|
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
258
|
+
for (var [o, p, info] of identifierNodes) {
|
|
259
|
+
var identifierName: string = o.name;
|
|
260
|
+
if (
|
|
261
|
+
p.find(
|
|
262
|
+
(x) => definedMap.has(x) && definedMap.get(x).has(identifierName)
|
|
263
|
+
)
|
|
264
|
+
)
|
|
265
|
+
continue;
|
|
244
266
|
|
|
245
|
-
|
|
267
|
+
ok(!info.spec.isDefined);
|
|
246
268
|
|
|
247
|
-
|
|
248
|
-
var resultName = this.getPlaceholder();
|
|
249
|
-
var propName = this.gen.generate();
|
|
269
|
+
var type = info.spec.isModified ? "setter" : "getter";
|
|
250
270
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
)
|
|
274
|
-
|
|
271
|
+
switch (type) {
|
|
272
|
+
case "setter":
|
|
273
|
+
var setterPropName = setterPropNames[identifierName];
|
|
274
|
+
if (typeof setterPropName === "undefined") {
|
|
275
|
+
// No getter function made yet, make it (Try to re-use getter name if available)
|
|
276
|
+
setterPropName =
|
|
277
|
+
getterPropNames[identifierName] ||
|
|
278
|
+
(this.isDebug ? "set_" + identifierName : this.gen.generate());
|
|
279
|
+
setterPropNames[identifierName] = setterPropName;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
// If an update expression, ensure a getter function is also available. Ex: a++
|
|
283
|
+
if (p[0].type === "UpdateExpression") {
|
|
284
|
+
getterPropNames[identifierName] = setterPropName;
|
|
285
|
+
} else {
|
|
286
|
+
// If assignment on member expression, ensure a getter function is also available: Ex. myObject.property = ...
|
|
287
|
+
var assignmentIndex = p.findIndex(
|
|
288
|
+
(x) => x.type === "AssignmentExpression"
|
|
289
|
+
);
|
|
290
|
+
if (
|
|
291
|
+
assignmentIndex !== -1 &&
|
|
292
|
+
p[assignmentIndex].left.type !== "Identifier"
|
|
293
|
+
) {
|
|
294
|
+
getterPropNames[identifierName] = setterPropName;
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
// calls flatObject.set_identifier_value(newValue)
|
|
299
|
+
this.replace(o, getFlatObjectMember(setterPropName));
|
|
300
|
+
break;
|
|
301
|
+
|
|
302
|
+
case "getter":
|
|
303
|
+
var getterPropName = getterPropNames[identifierName];
|
|
304
|
+
if (typeof getterPropName === "undefined") {
|
|
305
|
+
// No getter function made yet, make it (Try to re-use setter name if available)
|
|
306
|
+
getterPropName =
|
|
307
|
+
setterPropNames[identifierName] ||
|
|
308
|
+
(this.isDebug ? "get_" + identifierName : this.gen.generate());
|
|
309
|
+
getterPropNames[identifierName] = getterPropName;
|
|
310
|
+
}
|
|
275
311
|
|
|
312
|
+
// Typeof expression check
|
|
276
313
|
if (
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
o.argument.name == "undefined"
|
|
281
|
-
)
|
|
314
|
+
p[0].type === "UnaryExpression" &&
|
|
315
|
+
p[0].operator === "typeof" &&
|
|
316
|
+
p[0].argument === o
|
|
282
317
|
) {
|
|
283
|
-
|
|
284
|
-
|
|
318
|
+
var typeofPropName = typeofPropNames[identifierName];
|
|
319
|
+
if (typeof typeofPropName === "undefined") {
|
|
320
|
+
// No typeof getter function made yet, make it (Don't re-use getter/setter names)
|
|
321
|
+
typeofPropName = this.isDebug
|
|
322
|
+
? "get_typeof_" + identifierName
|
|
323
|
+
: this.gen.generate();
|
|
324
|
+
typeofPropNames[identifierName] = typeofPropName;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
// Replace the entire unary expression not just the identifier node
|
|
328
|
+
// calls flatObject.get_typeof_identifier()
|
|
329
|
+
this.replace(p[0], getFlatObjectMember(typeofPropName));
|
|
330
|
+
break;
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
// Bound call-expression check
|
|
334
|
+
if (p[0].type === "CallExpression" && p[0].callee === o) {
|
|
335
|
+
var callPropName = callPropNames[identifierName];
|
|
336
|
+
if (typeof callPropName === "undefined") {
|
|
337
|
+
callPropName = this.isDebug
|
|
338
|
+
? "call_" + identifierName
|
|
339
|
+
: this.gen.generate();
|
|
340
|
+
callPropNames[identifierName] = callPropName;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
// Replace the entire call expression not just the identifier node
|
|
344
|
+
// calls flatObject.call_identifier(...arguments)
|
|
345
|
+
this.replace(
|
|
346
|
+
p[0],
|
|
347
|
+
CallExpression(
|
|
348
|
+
getFlatObjectMember(callPropName),
|
|
349
|
+
p[0].arguments
|
|
350
|
+
)
|
|
285
351
|
);
|
|
352
|
+
break;
|
|
286
353
|
}
|
|
287
354
|
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
false
|
|
294
|
-
),
|
|
295
|
-
returnObject
|
|
296
|
-
);
|
|
297
|
-
}
|
|
298
|
-
};
|
|
299
|
-
});
|
|
355
|
+
// calls flatObject.get_identifier_value()
|
|
356
|
+
this.replace(o, getFlatObjectMember(getterPropName));
|
|
357
|
+
break;
|
|
358
|
+
}
|
|
359
|
+
}
|
|
300
360
|
|
|
301
|
-
|
|
361
|
+
// Create the getter and setter functions
|
|
362
|
+
var flatObjectProperties: Node[] = [];
|
|
302
363
|
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
ArrayPattern(clone(object.params)),
|
|
307
|
-
Identifier(resultName),
|
|
308
|
-
],
|
|
309
|
-
newBody
|
|
310
|
-
);
|
|
364
|
+
// Getter functions
|
|
365
|
+
for (var identifierName in getterPropNames) {
|
|
366
|
+
var getterPropName = getterPropNames[identifierName];
|
|
311
367
|
|
|
312
|
-
|
|
313
|
-
|
|
368
|
+
flatObjectProperties.push(
|
|
369
|
+
Property(
|
|
370
|
+
Literal(getterPropName),
|
|
371
|
+
FunctionExpression(
|
|
372
|
+
[],
|
|
373
|
+
[ReturnStatement(Identifier(identifierName))]
|
|
374
|
+
),
|
|
375
|
+
true,
|
|
376
|
+
"get"
|
|
377
|
+
)
|
|
378
|
+
);
|
|
379
|
+
}
|
|
314
380
|
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
381
|
+
// Get typeof functions
|
|
382
|
+
for (var identifierName in typeofPropNames) {
|
|
383
|
+
var typeofPropName = typeofPropNames[identifierName];
|
|
384
|
+
|
|
385
|
+
flatObjectProperties.push(
|
|
386
|
+
Property(
|
|
387
|
+
Literal(typeofPropName),
|
|
388
|
+
FunctionExpression(
|
|
389
|
+
[],
|
|
390
|
+
[
|
|
391
|
+
ReturnStatement(
|
|
392
|
+
UnaryExpression("typeof", Identifier(identifierName))
|
|
393
|
+
),
|
|
394
|
+
]
|
|
395
|
+
),
|
|
396
|
+
true,
|
|
397
|
+
"get"
|
|
398
|
+
)
|
|
399
|
+
);
|
|
400
|
+
}
|
|
321
401
|
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
402
|
+
// Call functions
|
|
403
|
+
for (var identifierName in callPropNames) {
|
|
404
|
+
var callPropName = callPropNames[identifierName];
|
|
405
|
+
var argumentsName = this.getPlaceholder();
|
|
406
|
+
flatObjectProperties.push(
|
|
407
|
+
Property(
|
|
408
|
+
Literal(callPropName),
|
|
409
|
+
FunctionExpression(
|
|
410
|
+
[RestElement(Identifier(argumentsName))],
|
|
411
|
+
[
|
|
412
|
+
ReturnStatement(
|
|
413
|
+
CallExpression(Identifier(identifierName), [
|
|
414
|
+
SpreadElement(Identifier(argumentsName)),
|
|
415
|
+
])
|
|
416
|
+
),
|
|
417
|
+
]
|
|
418
|
+
),
|
|
419
|
+
true
|
|
420
|
+
)
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
// Setter functions
|
|
425
|
+
for (var identifierName in setterPropNames) {
|
|
426
|
+
var setterPropName = setterPropNames[identifierName];
|
|
427
|
+
var newValueParameterName = this.getPlaceholder();
|
|
428
|
+
|
|
429
|
+
flatObjectProperties.push(
|
|
430
|
+
Property(
|
|
431
|
+
Literal(setterPropName),
|
|
432
|
+
FunctionExpression(
|
|
433
|
+
[Identifier(newValueParameterName)],
|
|
434
|
+
[
|
|
435
|
+
ExpressionStatement(
|
|
436
|
+
AssignmentExpression(
|
|
437
|
+
"=",
|
|
438
|
+
Identifier(identifierName),
|
|
439
|
+
Identifier(newValueParameterName)
|
|
440
|
+
)
|
|
441
|
+
),
|
|
442
|
+
]
|
|
443
|
+
),
|
|
444
|
+
true,
|
|
445
|
+
"set"
|
|
446
|
+
)
|
|
447
|
+
);
|
|
448
|
+
}
|
|
325
449
|
|
|
326
|
-
|
|
327
|
-
|
|
450
|
+
if (!this.isDebug) {
|
|
451
|
+
shuffle(flatObjectProperties);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
var newBody = getBlockBody(object.body);
|
|
455
|
+
|
|
456
|
+
// Remove 'use strict' directive
|
|
457
|
+
if (newBody.length > 0 && newBody[0].directive) {
|
|
458
|
+
newBody.shift();
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
var newFunctionDeclaration = FunctionDeclaration(
|
|
462
|
+
newFnName,
|
|
463
|
+
[ArrayPattern(clone(object.params)), Identifier(flatObjectName)],
|
|
464
|
+
newBody
|
|
328
465
|
);
|
|
329
466
|
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
Literal(outputName),
|
|
335
|
-
true
|
|
336
|
-
);
|
|
467
|
+
newFunctionDeclaration.async = !!object.async;
|
|
468
|
+
newFunctionDeclaration.generator = false;
|
|
469
|
+
|
|
470
|
+
this.flattenedFns.push(newFunctionDeclaration);
|
|
337
471
|
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
Identifier(
|
|
472
|
+
var argumentsName = this.getPlaceholder();
|
|
473
|
+
|
|
474
|
+
// newFn.call([...arguments], flatObject)
|
|
475
|
+
var callExpression = CallExpression(Identifier(newFnName), [
|
|
476
|
+
Identifier(argumentsName),
|
|
477
|
+
Identifier(flatObjectName),
|
|
343
478
|
]);
|
|
344
479
|
|
|
345
480
|
var newObjectBody: Node[] = [
|
|
346
|
-
// var
|
|
481
|
+
// var flatObject = { get(), set() };
|
|
347
482
|
VariableDeclaration([
|
|
348
|
-
VariableDeclarator(
|
|
483
|
+
VariableDeclarator(
|
|
484
|
+
flatObjectName,
|
|
485
|
+
ObjectExpression(flatObjectProperties)
|
|
486
|
+
),
|
|
349
487
|
]),
|
|
350
488
|
|
|
351
|
-
|
|
352
|
-
|
|
489
|
+
ReturnStatement(
|
|
490
|
+
newFunctionDeclaration.async
|
|
353
491
|
? AwaitExpression(callExpression)
|
|
354
492
|
: callExpression
|
|
355
493
|
),
|
|
356
494
|
];
|
|
357
495
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
// realVar
|
|
361
|
-
outputReversed.forEach((outputName) => {
|
|
362
|
-
newObjectBody.push(
|
|
363
|
-
ExpressionStatement(
|
|
364
|
-
AssignmentExpression(
|
|
365
|
-
"=",
|
|
366
|
-
Identifier(outputName),
|
|
367
|
-
getOutputMemberExpression(newOutputNames[outputName])
|
|
368
|
-
)
|
|
369
|
-
)
|
|
370
|
-
);
|
|
371
|
-
});
|
|
496
|
+
object.body = BlockStatement(newObjectBody);
|
|
372
497
|
|
|
373
|
-
//
|
|
374
|
-
var
|
|
375
|
-
var decoyNodes = [
|
|
376
|
-
// if (result.random) throw result.prop.random
|
|
377
|
-
IfStatement(
|
|
378
|
-
MemberExpression(
|
|
379
|
-
Identifier(resultName),
|
|
380
|
-
Literal(this.gen.generate()),
|
|
381
|
-
true
|
|
382
|
-
),
|
|
383
|
-
[
|
|
384
|
-
ThrowStatement(
|
|
385
|
-
NewExpression(Identifier("Error"), [
|
|
386
|
-
getOutputMemberExpression(this.gen.generate()),
|
|
387
|
-
])
|
|
388
|
-
),
|
|
389
|
-
]
|
|
390
|
-
),
|
|
391
|
-
// if (result.random) return true;
|
|
392
|
-
IfStatement(
|
|
393
|
-
MemberExpression(
|
|
394
|
-
Identifier(resultName),
|
|
395
|
-
Literal(this.gen.generate()),
|
|
396
|
-
true
|
|
397
|
-
),
|
|
398
|
-
[ReturnStatement(Literal(true))]
|
|
399
|
-
),
|
|
400
|
-
// if (result.random) return result;
|
|
401
|
-
IfStatement(
|
|
402
|
-
MemberExpression(
|
|
403
|
-
Identifier(resultName),
|
|
404
|
-
Literal(this.gen.generate()),
|
|
405
|
-
true
|
|
406
|
-
),
|
|
407
|
-
[ReturnStatement(Identifier(resultName))]
|
|
408
|
-
),
|
|
409
|
-
// if (result.random) return result.random;
|
|
410
|
-
IfStatement(
|
|
411
|
-
MemberExpression(Identifier(resultName), Literal(decoyKey), true),
|
|
412
|
-
[
|
|
413
|
-
ReturnStatement(
|
|
414
|
-
MemberExpression(Identifier(resultName), Literal(decoyKey), true)
|
|
415
|
-
),
|
|
416
|
-
]
|
|
417
|
-
),
|
|
418
|
-
// if(result.random1) return result.random2;
|
|
419
|
-
IfStatement(
|
|
420
|
-
MemberExpression(
|
|
421
|
-
Identifier(resultName),
|
|
422
|
-
Literal(this.gen.generate()),
|
|
423
|
-
true
|
|
424
|
-
),
|
|
425
|
-
[
|
|
426
|
-
ReturnStatement(
|
|
427
|
-
MemberExpression(
|
|
428
|
-
Identifier(resultName),
|
|
429
|
-
Literal(this.gen.generate()),
|
|
430
|
-
true
|
|
431
|
-
)
|
|
432
|
-
),
|
|
433
|
-
]
|
|
434
|
-
),
|
|
435
|
-
// if(result.random) return flatFn;
|
|
436
|
-
IfStatement(
|
|
437
|
-
MemberExpression(
|
|
438
|
-
Identifier(resultName),
|
|
439
|
-
Literal(this.gen.generate()),
|
|
440
|
-
true
|
|
441
|
-
),
|
|
442
|
-
[ReturnStatement(Identifier(newName))]
|
|
443
|
-
),
|
|
444
|
-
// if(result.random) flatFn = undefined;
|
|
445
|
-
IfStatement(
|
|
446
|
-
MemberExpression(
|
|
447
|
-
Identifier(resultName),
|
|
448
|
-
Literal(this.gen.generate()),
|
|
449
|
-
true
|
|
450
|
-
),
|
|
451
|
-
[
|
|
452
|
-
ExpressionStatement(
|
|
453
|
-
AssignmentExpression(
|
|
454
|
-
"=",
|
|
455
|
-
Identifier(newName),
|
|
456
|
-
Identifier("undefined")
|
|
457
|
-
)
|
|
458
|
-
),
|
|
459
|
-
]
|
|
460
|
-
),
|
|
461
|
-
// if(!result) return;
|
|
462
|
-
IfStatement(UnaryExpression("!", Identifier(resultName)), [
|
|
463
|
-
ReturnStatement(),
|
|
464
|
-
]),
|
|
465
|
-
].filter(() => Math.random() > 0.25);
|
|
466
|
-
|
|
467
|
-
// if (result.output) return result.output.returnValue;
|
|
468
|
-
// this is the real return statement, it is always added
|
|
469
|
-
decoyNodes.push(
|
|
470
|
-
IfStatement(
|
|
471
|
-
MemberExpression(Identifier(resultName), Literal(propName), true),
|
|
472
|
-
[ReturnStatement(getOutputMemberExpression(returnOutputName))]
|
|
473
|
-
)
|
|
474
|
-
);
|
|
498
|
+
// Preserve function.length property
|
|
499
|
+
var originalFunctionLength = computeFunctionLength(object.params);
|
|
475
500
|
|
|
476
|
-
|
|
501
|
+
object.params = [SpreadElement(Identifier(argumentsName))];
|
|
477
502
|
|
|
478
|
-
|
|
503
|
+
if (originalFunctionLength !== 0) {
|
|
504
|
+
if (!this.functionLengthName) {
|
|
505
|
+
this.functionLengthName = this.getPlaceholder();
|
|
479
506
|
|
|
480
|
-
|
|
507
|
+
prepend(
|
|
508
|
+
parents[parents.length - 1] || object,
|
|
509
|
+
FunctionLengthTemplate.single({ name: this.functionLengthName })
|
|
510
|
+
);
|
|
511
|
+
}
|
|
481
512
|
|
|
482
|
-
|
|
513
|
+
if (object.type === "FunctionDeclaration") {
|
|
514
|
+
var body = parents[0];
|
|
515
|
+
if (Array.isArray(body)) {
|
|
516
|
+
var index = body.indexOf(object);
|
|
517
|
+
|
|
518
|
+
body.splice(
|
|
519
|
+
index + 1,
|
|
520
|
+
0,
|
|
521
|
+
ExpressionStatement(
|
|
522
|
+
CallExpression(Identifier(this.functionLengthName), [
|
|
523
|
+
Identifier(object.id.name),
|
|
524
|
+
Literal(originalFunctionLength),
|
|
525
|
+
])
|
|
526
|
+
)
|
|
527
|
+
);
|
|
528
|
+
}
|
|
529
|
+
} else {
|
|
530
|
+
ok(object.type === "FunctionExpression");
|
|
531
|
+
this.replace(
|
|
532
|
+
object,
|
|
533
|
+
CallExpression(Identifier(this.functionLengthName), [
|
|
534
|
+
{ ...object },
|
|
535
|
+
Literal(originalFunctionLength),
|
|
536
|
+
])
|
|
537
|
+
);
|
|
538
|
+
}
|
|
539
|
+
}
|
|
483
540
|
};
|
|
484
541
|
}
|
|
485
542
|
}
|