js-confuser 1.6.0 → 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/CHANGELOG.md +23 -0
- package/README.md +215 -170
- package/dist/constants.js +6 -2
- package/dist/obfuscator.js +0 -6
- package/dist/options.js +4 -4
- package/dist/presets.js +6 -7
- package/dist/templates/crash.js +2 -2
- package/dist/templates/functionLength.js +16 -0
- package/dist/transforms/dispatcher.js +4 -1
- package/dist/transforms/extraction/duplicateLiteralsRemoval.js +89 -58
- package/dist/transforms/flatten.js +224 -147
- package/dist/transforms/identifier/movedDeclarations.js +38 -85
- package/dist/transforms/identifier/renameVariables.js +94 -41
- package/dist/transforms/lock/lock.js +0 -37
- package/dist/transforms/minify.js +2 -2
- package/dist/transforms/rgf.js +139 -246
- package/dist/transforms/stack.js +42 -1
- package/dist/transforms/transform.js +1 -1
- package/dist/util/gen.js +2 -1
- package/dist/util/identifiers.js +37 -3
- package/dist/util/insert.js +24 -3
- 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 +1 -1
- package/src/constants.ts +3 -0
- package/src/obfuscator.ts +0 -4
- package/src/options.ts +9 -86
- package/src/presets.ts +6 -7
- package/src/templates/crash.ts +10 -10
- package/src/templates/functionLength.ts +14 -0
- package/src/transforms/dispatcher.ts +5 -1
- package/src/transforms/extraction/duplicateLiteralsRemoval.ts +130 -129
- package/src/transforms/flatten.ts +357 -290
- package/src/transforms/identifier/movedDeclarations.ts +50 -96
- package/src/transforms/identifier/renameVariables.ts +120 -56
- package/src/transforms/lock/lock.ts +1 -42
- package/src/transforms/minify.ts +11 -2
- package/src/transforms/rgf.ts +214 -404
- package/src/transforms/stack.ts +62 -0
- package/src/transforms/transform.ts +6 -2
- package/src/util/gen.ts +7 -2
- package/src/util/identifiers.ts +43 -2
- package/src/util/insert.ts +26 -2
- package/test/code/ES6.src.js +24 -0
- package/test/transforms/flatten.test.ts +352 -88
- package/test/transforms/identifier/movedDeclarations.test.ts +37 -9
- package/test/transforms/identifier/renameVariables.test.ts +37 -0
- package/test/transforms/lock/lock.test.ts +1 -48
- package/test/transforms/minify.test.ts +19 -0
- package/test/transforms/rgf.test.ts +262 -353
- package/test/transforms/stack.test.ts +52 -0
- package/test/util/identifiers.test.ts +113 -1
- package/test/util/insert.test.ts +57 -3
- package/src/transforms/eval.ts +0 -89
- package/src/transforms/identifier/nameRecycling.ts +0 -280
- package/test/transforms/eval.test.ts +0 -131
- package/test/transforms/identifier/nameRecycling.test.ts +0 -205
|
@@ -1,7 +1,7 @@
|
|
|
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
6
|
Identifier,
|
|
7
7
|
ReturnStatement,
|
|
@@ -9,7 +9,6 @@ import {
|
|
|
9
9
|
VariableDeclarator,
|
|
10
10
|
CallExpression,
|
|
11
11
|
MemberExpression,
|
|
12
|
-
ArrayExpression,
|
|
13
12
|
ExpressionStatement,
|
|
14
13
|
AssignmentExpression,
|
|
15
14
|
Node,
|
|
@@ -19,70 +18,93 @@ import {
|
|
|
19
18
|
ObjectExpression,
|
|
20
19
|
Property,
|
|
21
20
|
Literal,
|
|
22
|
-
IfStatement,
|
|
23
|
-
ThrowStatement,
|
|
24
|
-
NewExpression,
|
|
25
21
|
AwaitExpression,
|
|
22
|
+
FunctionDeclaration,
|
|
23
|
+
SpreadElement,
|
|
26
24
|
UnaryExpression,
|
|
25
|
+
RestElement,
|
|
27
26
|
} from "../util/gen";
|
|
28
27
|
import { getIdentifierInfo } from "../util/identifiers";
|
|
29
|
-
import {
|
|
30
|
-
|
|
28
|
+
import {
|
|
29
|
+
getBlockBody,
|
|
30
|
+
prepend,
|
|
31
|
+
clone,
|
|
32
|
+
getDefiningContext,
|
|
33
|
+
computeFunctionLength,
|
|
34
|
+
} from "../util/insert";
|
|
35
|
+
import { shuffle } from "../util/random";
|
|
31
36
|
import Transform from "./transform";
|
|
37
|
+
import { FunctionLengthTemplate } from "../templates/functionLength";
|
|
32
38
|
|
|
33
39
|
/**
|
|
34
|
-
*
|
|
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.
|
|
35
43
|
*
|
|
36
|
-
*
|
|
44
|
+
* The `flatObject` uses `get` and `set` properties to allow easy an AST transformation:
|
|
37
45
|
*
|
|
38
46
|
* ```js
|
|
39
|
-
*
|
|
40
|
-
*
|
|
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)
|
|
41
73
|
* }
|
|
42
74
|
* ```
|
|
43
75
|
*
|
|
44
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
|
|
45
79
|
*/
|
|
46
80
|
export default class Flatten extends Transform {
|
|
81
|
+
isDebug = false;
|
|
82
|
+
|
|
47
83
|
definedNames: Map<Node, Set<string>>;
|
|
84
|
+
|
|
85
|
+
// Array of FunctionDeclaration nodes
|
|
48
86
|
flattenedFns: Node[];
|
|
49
87
|
gen: ReturnType<Transform["getGenerator"]>;
|
|
50
88
|
|
|
89
|
+
functionLengthName: string;
|
|
90
|
+
|
|
51
91
|
constructor(o) {
|
|
52
92
|
super(o, ObfuscateOrder.Flatten);
|
|
53
93
|
|
|
54
94
|
this.definedNames = new Map();
|
|
55
95
|
this.flattenedFns = [];
|
|
56
|
-
this.gen = this.getGenerator();
|
|
96
|
+
this.gen = this.getGenerator("mangled");
|
|
97
|
+
|
|
98
|
+
if (this.isDebug) {
|
|
99
|
+
console.warn("Flatten debug mode");
|
|
100
|
+
}
|
|
57
101
|
}
|
|
58
102
|
|
|
59
103
|
apply(tree) {
|
|
60
|
-
traverse(tree, (o, p) => {
|
|
61
|
-
if (
|
|
62
|
-
o.type == "Identifier" &&
|
|
63
|
-
!reservedIdentifiers.has(o.name) &&
|
|
64
|
-
!this.options.globalVariables.has(o.name)
|
|
65
|
-
) {
|
|
66
|
-
var info = getIdentifierInfo(o, p);
|
|
67
|
-
if (info.spec.isReferenced) {
|
|
68
|
-
if (info.spec.isDefined) {
|
|
69
|
-
var c = getVarContext(o, p);
|
|
70
|
-
if (c) {
|
|
71
|
-
if (!this.definedNames.has(c)) {
|
|
72
|
-
this.definedNames.set(c, new Set([o.name]));
|
|
73
|
-
} else {
|
|
74
|
-
this.definedNames.get(c).add(o.name);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
});
|
|
81
|
-
|
|
82
104
|
super.apply(tree);
|
|
83
105
|
|
|
84
106
|
if (this.flattenedFns.length) {
|
|
85
|
-
prepend(tree,
|
|
107
|
+
prepend(tree, ...this.flattenedFns);
|
|
86
108
|
}
|
|
87
109
|
}
|
|
88
110
|
|
|
@@ -91,6 +113,7 @@ export default class Flatten extends Transform {
|
|
|
91
113
|
(object.type == "FunctionDeclaration" ||
|
|
92
114
|
object.type === "FunctionExpression") &&
|
|
93
115
|
object.body.type == "BlockStatement" &&
|
|
116
|
+
!object.$requiresEval &&
|
|
94
117
|
!object.generator &&
|
|
95
118
|
!object.params.find((x) => x.type !== "Identifier")
|
|
96
119
|
);
|
|
@@ -111,7 +134,7 @@ export default class Flatten extends Transform {
|
|
|
111
134
|
if (
|
|
112
135
|
parents[0].type === "Property" &&
|
|
113
136
|
parents[0].value === object &&
|
|
114
|
-
parents[0].kind !== "init"
|
|
137
|
+
(parents[0].kind !== "init" || parents[0].method)
|
|
115
138
|
) {
|
|
116
139
|
return;
|
|
117
140
|
}
|
|
@@ -131,36 +154,37 @@ export default class Flatten extends Transform {
|
|
|
131
154
|
parents[0].id?.name;
|
|
132
155
|
|
|
133
156
|
if (parents[0]?.type === "Property" && parents[0]?.key) {
|
|
134
|
-
currentFnName =
|
|
135
|
-
currentFnName ||
|
|
136
|
-
String(parents[0]?.key?.name || parents[0]?.key?.value);
|
|
157
|
+
currentFnName = currentFnName || String(parents[0]?.key?.name);
|
|
137
158
|
}
|
|
138
159
|
|
|
139
160
|
if (!currentFnName) currentFnName = "unnamed";
|
|
140
161
|
|
|
141
|
-
var
|
|
142
|
-
var references = new Set<string>();
|
|
143
|
-
var modified = new Set<string>();
|
|
162
|
+
var definedMap = new Map<Node, Set<string>>();
|
|
144
163
|
|
|
145
164
|
var illegal = new Set<string>();
|
|
146
165
|
var isIllegal = false;
|
|
147
166
|
|
|
148
|
-
var
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
set.forEach((name) => definedAbove.add(name));
|
|
154
|
-
}
|
|
155
|
-
});
|
|
167
|
+
var identifierNodes: [
|
|
168
|
+
Node,
|
|
169
|
+
Node[],
|
|
170
|
+
ReturnType<typeof getIdentifierInfo>
|
|
171
|
+
][] = [];
|
|
156
172
|
|
|
157
173
|
walk(object, parents, (o, p) => {
|
|
158
|
-
if (
|
|
159
|
-
|
|
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";
|
|
160
183
|
}
|
|
161
184
|
|
|
162
185
|
if (
|
|
163
186
|
o.type == "Identifier" &&
|
|
187
|
+
o !== object.id &&
|
|
164
188
|
!this.options.globalVariables.has(o.name) &&
|
|
165
189
|
!reservedIdentifiers.has(o.name)
|
|
166
190
|
) {
|
|
@@ -169,45 +193,36 @@ export default class Flatten extends Transform {
|
|
|
169
193
|
return;
|
|
170
194
|
}
|
|
171
195
|
|
|
172
|
-
if (
|
|
196
|
+
if (
|
|
197
|
+
info.spec.isExported ||
|
|
198
|
+
o.name.startsWith(noRenameVariablePrefix)
|
|
199
|
+
) {
|
|
173
200
|
illegal.add(o.name);
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
} else if (info.spec.isModified) {
|
|
177
|
-
modified.add(o.name);
|
|
178
|
-
} else {
|
|
179
|
-
references.add(o.name);
|
|
201
|
+
|
|
202
|
+
return;
|
|
180
203
|
}
|
|
181
|
-
}
|
|
182
204
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
return "EXIT";
|
|
186
|
-
}
|
|
205
|
+
if (info.spec.isDefined) {
|
|
206
|
+
var definingContext = getDefiningContext(o, p);
|
|
187
207
|
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
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;
|
|
192
214
|
}
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
if (o.type == "ThisExpression") {
|
|
196
|
-
isIllegal = true;
|
|
197
|
-
return "EXIT";
|
|
198
|
-
}
|
|
199
215
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
}
|
|
216
|
+
var isDefined = p.find(
|
|
217
|
+
(x) => definedMap.has(x) && definedMap.get(x).has(o.name)
|
|
218
|
+
);
|
|
204
219
|
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
220
|
+
if (!isDefined) {
|
|
221
|
+
identifierNodes.push([o, p, info]);
|
|
222
|
+
}
|
|
208
223
|
}
|
|
209
224
|
|
|
210
|
-
if (o.type == "
|
|
225
|
+
if (o.type == "TryStatement") {
|
|
211
226
|
isIllegal = true;
|
|
212
227
|
return "EXIT";
|
|
213
228
|
}
|
|
@@ -220,75 +235,221 @@ export default class Flatten extends Transform {
|
|
|
220
235
|
return;
|
|
221
236
|
}
|
|
222
237
|
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
modified.delete(name);
|
|
226
|
-
});
|
|
238
|
+
var newFnName = this.getPlaceholder() + "_flat_" + currentFnName;
|
|
239
|
+
var flatObjectName = this.getPlaceholder() + "_flat_object";
|
|
227
240
|
|
|
228
|
-
|
|
241
|
+
const getFlatObjectMember = (propertyName: string) => {
|
|
242
|
+
return MemberExpression(
|
|
243
|
+
Identifier(flatObjectName),
|
|
244
|
+
Literal(propertyName),
|
|
245
|
+
true
|
|
246
|
+
);
|
|
247
|
+
};
|
|
229
248
|
|
|
230
|
-
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);
|
|
231
257
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
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;
|
|
235
266
|
|
|
236
|
-
|
|
267
|
+
ok(!info.spec.isDefined);
|
|
237
268
|
|
|
238
|
-
|
|
239
|
-
var resultName = this.getPlaceholder();
|
|
240
|
-
var propName = this.gen.generate();
|
|
269
|
+
var type = info.spec.isModified ? "setter" : "getter";
|
|
241
270
|
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
// return (argument)
|
|
253
|
-
// to
|
|
254
|
-
// return [ [modifiedRefs], ]
|
|
255
|
-
if (o.type == "ReturnStatement" && getVarContext(o, p) === object) {
|
|
256
|
-
return () => {
|
|
257
|
-
var returnObject = ObjectExpression(
|
|
258
|
-
output.map((outputName) =>
|
|
259
|
-
Property(
|
|
260
|
-
Literal(newOutputNames[outputName]),
|
|
261
|
-
Identifier(outputName),
|
|
262
|
-
true
|
|
263
|
-
)
|
|
264
|
-
)
|
|
265
|
-
);
|
|
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
|
+
}
|
|
266
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
|
+
}
|
|
311
|
+
|
|
312
|
+
// Typeof expression check
|
|
267
313
|
if (
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
o.argument.name == "undefined"
|
|
272
|
-
)
|
|
314
|
+
p[0].type === "UnaryExpression" &&
|
|
315
|
+
p[0].operator === "typeof" &&
|
|
316
|
+
p[0].argument === o
|
|
273
317
|
) {
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
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
|
+
)
|
|
277
351
|
);
|
|
352
|
+
break;
|
|
278
353
|
}
|
|
279
354
|
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
Identifier(resultName),
|
|
284
|
-
Identifier(propName),
|
|
285
|
-
false
|
|
286
|
-
),
|
|
287
|
-
returnObject
|
|
288
|
-
);
|
|
289
|
-
};
|
|
355
|
+
// calls flatObject.get_identifier_value()
|
|
356
|
+
this.replace(o, getFlatObjectMember(getterPropName));
|
|
357
|
+
break;
|
|
290
358
|
}
|
|
291
|
-
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
// Create the getter and setter functions
|
|
362
|
+
var flatObjectProperties: Node[] = [];
|
|
363
|
+
|
|
364
|
+
// Getter functions
|
|
365
|
+
for (var identifierName in getterPropNames) {
|
|
366
|
+
var getterPropName = getterPropNames[identifierName];
|
|
367
|
+
|
|
368
|
+
flatObjectProperties.push(
|
|
369
|
+
Property(
|
|
370
|
+
Literal(getterPropName),
|
|
371
|
+
FunctionExpression(
|
|
372
|
+
[],
|
|
373
|
+
[ReturnStatement(Identifier(identifierName))]
|
|
374
|
+
),
|
|
375
|
+
true,
|
|
376
|
+
"get"
|
|
377
|
+
)
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
|
|
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
|
+
}
|
|
401
|
+
|
|
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
|
+
}
|
|
449
|
+
|
|
450
|
+
if (!this.isDebug) {
|
|
451
|
+
shuffle(flatObjectProperties);
|
|
452
|
+
}
|
|
292
453
|
|
|
293
454
|
var newBody = getBlockBody(object.body);
|
|
294
455
|
|
|
@@ -297,179 +458,85 @@ export default class Flatten extends Transform {
|
|
|
297
458
|
newBody.shift();
|
|
298
459
|
}
|
|
299
460
|
|
|
300
|
-
var
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
ArrayPattern(clone(object.params)),
|
|
304
|
-
Identifier(resultName),
|
|
305
|
-
],
|
|
461
|
+
var newFunctionDeclaration = FunctionDeclaration(
|
|
462
|
+
newFnName,
|
|
463
|
+
[ArrayPattern(clone(object.params)), Identifier(flatObjectName)],
|
|
306
464
|
newBody
|
|
307
465
|
);
|
|
308
466
|
|
|
309
|
-
|
|
310
|
-
|
|
467
|
+
newFunctionDeclaration.async = !!object.async;
|
|
468
|
+
newFunctionDeclaration.generator = false;
|
|
311
469
|
|
|
312
|
-
this.flattenedFns.push(
|
|
313
|
-
VariableDeclarator(newName, newFunctionExpression)
|
|
314
|
-
);
|
|
470
|
+
this.flattenedFns.push(newFunctionDeclaration);
|
|
315
471
|
|
|
316
|
-
var
|
|
317
|
-
this.getPlaceholder()
|
|
318
|
-
);
|
|
472
|
+
var argumentsName = this.getPlaceholder();
|
|
319
473
|
|
|
320
|
-
//
|
|
321
|
-
var
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
Literal(outputName),
|
|
325
|
-
true
|
|
326
|
-
);
|
|
327
|
-
|
|
328
|
-
// newFn.call([...refs], ...arguments, resultObject)
|
|
329
|
-
var callExpression = CallExpression(Identifier(newName), [
|
|
330
|
-
ArrayExpression(input.map((name) => Identifier(name))),
|
|
331
|
-
ArrayExpression(newParamNames.map((name) => Identifier(name))),
|
|
332
|
-
Identifier(resultName),
|
|
474
|
+
// newFn.call([...arguments], flatObject)
|
|
475
|
+
var callExpression = CallExpression(Identifier(newFnName), [
|
|
476
|
+
Identifier(argumentsName),
|
|
477
|
+
Identifier(flatObjectName),
|
|
333
478
|
]);
|
|
334
479
|
|
|
335
480
|
var newObjectBody: Node[] = [
|
|
336
|
-
// var
|
|
481
|
+
// var flatObject = { get(), set() };
|
|
337
482
|
VariableDeclaration([
|
|
338
|
-
VariableDeclarator(
|
|
483
|
+
VariableDeclarator(
|
|
484
|
+
flatObjectName,
|
|
485
|
+
ObjectExpression(flatObjectProperties)
|
|
486
|
+
),
|
|
339
487
|
]),
|
|
340
488
|
|
|
341
|
-
|
|
342
|
-
|
|
489
|
+
ReturnStatement(
|
|
490
|
+
newFunctionDeclaration.async
|
|
343
491
|
? AwaitExpression(callExpression)
|
|
344
492
|
: callExpression
|
|
345
493
|
),
|
|
346
494
|
];
|
|
347
495
|
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
// realVar
|
|
351
|
-
outputReversed.forEach((outputName) => {
|
|
352
|
-
newObjectBody.push(
|
|
353
|
-
ExpressionStatement(
|
|
354
|
-
AssignmentExpression(
|
|
355
|
-
"=",
|
|
356
|
-
Identifier(outputName),
|
|
357
|
-
getOutputMemberExpression(newOutputNames[outputName])
|
|
358
|
-
)
|
|
359
|
-
)
|
|
360
|
-
);
|
|
361
|
-
});
|
|
496
|
+
object.body = BlockStatement(newObjectBody);
|
|
362
497
|
|
|
363
|
-
//
|
|
364
|
-
var
|
|
365
|
-
var decoyNodes = [
|
|
366
|
-
// if (result.random) throw result.prop.random
|
|
367
|
-
IfStatement(
|
|
368
|
-
MemberExpression(
|
|
369
|
-
Identifier(resultName),
|
|
370
|
-
Literal(this.gen.generate()),
|
|
371
|
-
true
|
|
372
|
-
),
|
|
373
|
-
[
|
|
374
|
-
ThrowStatement(
|
|
375
|
-
NewExpression(Identifier("Error"), [
|
|
376
|
-
getOutputMemberExpression(this.gen.generate()),
|
|
377
|
-
])
|
|
378
|
-
),
|
|
379
|
-
]
|
|
380
|
-
),
|
|
381
|
-
// if (result.random) return true;
|
|
382
|
-
IfStatement(
|
|
383
|
-
MemberExpression(
|
|
384
|
-
Identifier(resultName),
|
|
385
|
-
Literal(this.gen.generate()),
|
|
386
|
-
true
|
|
387
|
-
),
|
|
388
|
-
[ReturnStatement(Literal(true))]
|
|
389
|
-
),
|
|
390
|
-
// if (result.random) return result;
|
|
391
|
-
IfStatement(
|
|
392
|
-
MemberExpression(
|
|
393
|
-
Identifier(resultName),
|
|
394
|
-
Literal(this.gen.generate()),
|
|
395
|
-
true
|
|
396
|
-
),
|
|
397
|
-
[ReturnStatement(Identifier(resultName))]
|
|
398
|
-
),
|
|
399
|
-
// if (result.random) return result.random;
|
|
400
|
-
IfStatement(
|
|
401
|
-
MemberExpression(Identifier(resultName), Literal(decoyKey), true),
|
|
402
|
-
[
|
|
403
|
-
ReturnStatement(
|
|
404
|
-
MemberExpression(Identifier(resultName), Literal(decoyKey), true)
|
|
405
|
-
),
|
|
406
|
-
]
|
|
407
|
-
),
|
|
408
|
-
// if(result.random1) return result.random2;
|
|
409
|
-
IfStatement(
|
|
410
|
-
MemberExpression(
|
|
411
|
-
Identifier(resultName),
|
|
412
|
-
Literal(this.gen.generate()),
|
|
413
|
-
true
|
|
414
|
-
),
|
|
415
|
-
[
|
|
416
|
-
ReturnStatement(
|
|
417
|
-
MemberExpression(
|
|
418
|
-
Identifier(resultName),
|
|
419
|
-
Literal(this.gen.generate()),
|
|
420
|
-
true
|
|
421
|
-
)
|
|
422
|
-
),
|
|
423
|
-
]
|
|
424
|
-
),
|
|
425
|
-
// if(result.random) return flatFn;
|
|
426
|
-
IfStatement(
|
|
427
|
-
MemberExpression(
|
|
428
|
-
Identifier(resultName),
|
|
429
|
-
Literal(this.gen.generate()),
|
|
430
|
-
true
|
|
431
|
-
),
|
|
432
|
-
[ReturnStatement(Identifier(newName))]
|
|
433
|
-
),
|
|
434
|
-
// if(result.random) flatFn = undefined;
|
|
435
|
-
IfStatement(
|
|
436
|
-
MemberExpression(
|
|
437
|
-
Identifier(resultName),
|
|
438
|
-
Literal(this.gen.generate()),
|
|
439
|
-
true
|
|
440
|
-
),
|
|
441
|
-
[
|
|
442
|
-
ExpressionStatement(
|
|
443
|
-
AssignmentExpression(
|
|
444
|
-
"=",
|
|
445
|
-
Identifier(newName),
|
|
446
|
-
Identifier("undefined")
|
|
447
|
-
)
|
|
448
|
-
),
|
|
449
|
-
]
|
|
450
|
-
),
|
|
451
|
-
// if(!result) return;
|
|
452
|
-
IfStatement(UnaryExpression("!", Identifier(resultName)), [
|
|
453
|
-
ReturnStatement(),
|
|
454
|
-
]),
|
|
455
|
-
].filter(() => chance(25));
|
|
456
|
-
|
|
457
|
-
// if (result.output) return result.output.returnValue;
|
|
458
|
-
// this is the real return statement, it is always added
|
|
459
|
-
decoyNodes.push(
|
|
460
|
-
IfStatement(
|
|
461
|
-
MemberExpression(Identifier(resultName), Literal(propName), true),
|
|
462
|
-
[ReturnStatement(getOutputMemberExpression(returnOutputName))]
|
|
463
|
-
)
|
|
464
|
-
);
|
|
498
|
+
// Preserve function.length property
|
|
499
|
+
var originalFunctionLength = computeFunctionLength(object.params);
|
|
465
500
|
|
|
466
|
-
|
|
501
|
+
object.params = [SpreadElement(Identifier(argumentsName))];
|
|
467
502
|
|
|
468
|
-
|
|
503
|
+
if (originalFunctionLength !== 0) {
|
|
504
|
+
if (!this.functionLengthName) {
|
|
505
|
+
this.functionLengthName = this.getPlaceholder();
|
|
469
506
|
|
|
470
|
-
|
|
507
|
+
prepend(
|
|
508
|
+
parents[parents.length - 1] || object,
|
|
509
|
+
FunctionLengthTemplate.single({ name: this.functionLengthName })
|
|
510
|
+
);
|
|
511
|
+
}
|
|
471
512
|
|
|
472
|
-
|
|
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
|
+
}
|
|
473
540
|
};
|
|
474
541
|
}
|
|
475
542
|
}
|