js-confuser 1.5.8 → 1.6.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.
Files changed (139) hide show
  1. package/.github/workflows/node.js.yml +2 -2
  2. package/CHANGELOG.md +69 -0
  3. package/README.md +143 -7
  4. package/dist/index.js +33 -4
  5. package/dist/obfuscator.js +30 -31
  6. package/dist/options.js +4 -5
  7. package/dist/order.js +4 -6
  8. package/dist/probability.js +2 -4
  9. package/dist/templates/bufferToString.js +13 -0
  10. package/dist/templates/crash.js +2 -2
  11. package/dist/templates/es5.js +18 -0
  12. package/dist/transforms/antiTooling.js +1 -1
  13. package/dist/transforms/calculator.js +77 -21
  14. package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +980 -367
  15. package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +8 -3
  16. package/dist/transforms/controlFlowFlattening/switchCaseObfuscation.js +25 -26
  17. package/dist/transforms/deadCode.js +33 -25
  18. package/dist/transforms/dispatcher.js +7 -6
  19. package/dist/transforms/es5/antiClass.js +6 -2
  20. package/dist/transforms/es5/antiDestructuring.js +3 -1
  21. package/dist/transforms/es5/es5.js +31 -34
  22. package/dist/transforms/eval.js +11 -0
  23. package/dist/transforms/extraction/duplicateLiteralsRemoval.js +8 -5
  24. package/dist/transforms/extraction/objectExtraction.js +6 -1
  25. package/dist/transforms/finalizer.js +82 -0
  26. package/dist/transforms/flatten.js +82 -55
  27. package/dist/transforms/hexadecimalNumbers.js +34 -9
  28. package/dist/transforms/identifier/globalAnalysis.js +88 -0
  29. package/dist/transforms/identifier/globalConcealing.js +10 -83
  30. package/dist/transforms/identifier/movedDeclarations.js +2 -8
  31. package/dist/transforms/identifier/renameVariables.js +39 -27
  32. package/dist/transforms/identifier/variableAnalysis.js +58 -62
  33. package/dist/transforms/minify.js +80 -61
  34. package/dist/transforms/opaquePredicates.js +1 -1
  35. package/dist/transforms/preparation/preparation.js +2 -2
  36. package/dist/transforms/preparation.js +231 -0
  37. package/dist/transforms/renameLabels.js +1 -1
  38. package/dist/transforms/rgf.js +4 -5
  39. package/dist/transforms/stack.js +87 -26
  40. package/dist/transforms/string/encoding.js +150 -179
  41. package/dist/transforms/string/stringCompression.js +14 -15
  42. package/dist/transforms/string/stringConcealing.js +25 -8
  43. package/dist/transforms/string/stringEncoding.js +13 -24
  44. package/dist/transforms/transform.js +11 -18
  45. package/dist/traverse.js +24 -18
  46. package/dist/util/compare.js +2 -2
  47. package/dist/util/gen.js +15 -0
  48. package/dist/util/insert.js +31 -7
  49. package/dist/util/random.js +15 -0
  50. package/package.json +5 -5
  51. package/src/index.ts +57 -19
  52. package/src/obfuscator.ts +26 -29
  53. package/src/options.ts +17 -21
  54. package/src/order.ts +4 -8
  55. package/src/probability.ts +2 -3
  56. package/src/templates/bufferToString.ts +68 -0
  57. package/src/templates/crash.ts +5 -9
  58. package/src/templates/es5.ts +131 -0
  59. package/src/transforms/antiTooling.ts +1 -1
  60. package/src/transforms/calculator.ts +122 -59
  61. package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +1583 -571
  62. package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +18 -3
  63. package/src/transforms/deadCode.ts +383 -26
  64. package/src/transforms/dispatcher.ts +8 -6
  65. package/src/transforms/es5/antiClass.ts +10 -1
  66. package/src/transforms/es5/antiDestructuring.ts +3 -1
  67. package/src/transforms/es5/es5.ts +32 -77
  68. package/src/transforms/eval.ts +18 -0
  69. package/src/transforms/extraction/duplicateLiteralsRemoval.ts +9 -6
  70. package/src/transforms/extraction/objectExtraction.ts +12 -5
  71. package/src/transforms/finalizer.ts +75 -0
  72. package/src/transforms/flatten.ts +194 -151
  73. package/src/transforms/identifier/globalAnalysis.ts +85 -0
  74. package/src/transforms/identifier/globalConcealing.ts +14 -103
  75. package/src/transforms/identifier/movedDeclarations.ts +4 -11
  76. package/src/transforms/identifier/renameVariables.ts +37 -30
  77. package/src/transforms/identifier/variableAnalysis.ts +66 -73
  78. package/src/transforms/minify.ts +116 -77
  79. package/src/transforms/opaquePredicates.ts +2 -2
  80. package/src/transforms/preparation.ts +238 -0
  81. package/src/transforms/renameLabels.ts +2 -2
  82. package/src/transforms/rgf.ts +6 -7
  83. package/src/transforms/stack.ts +97 -37
  84. package/src/transforms/string/encoding.ts +115 -212
  85. package/src/transforms/string/stringCompression.ts +27 -18
  86. package/src/transforms/string/stringConcealing.ts +41 -11
  87. package/src/transforms/string/stringEncoding.ts +18 -18
  88. package/src/transforms/transform.ts +15 -21
  89. package/src/traverse.ts +24 -12
  90. package/src/types.ts +11 -2
  91. package/src/util/compare.ts +2 -2
  92. package/src/util/gen.ts +21 -1
  93. package/src/util/insert.ts +49 -9
  94. package/src/util/random.ts +13 -0
  95. package/test/code/Cash.test.ts +1 -1
  96. package/test/code/Dynamic.test.ts +12 -10
  97. package/test/code/ES6.src.js +136 -0
  98. package/test/code/ES6.test.ts +28 -2
  99. package/test/code/NewFeatures.test.ts +19 -0
  100. package/test/index.test.ts +15 -2
  101. package/test/probability.test.ts +44 -0
  102. package/test/templates/template.test.ts +1 -1
  103. package/test/transforms/antiTooling.test.ts +52 -0
  104. package/test/transforms/calculator.test.ts +40 -0
  105. package/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts +713 -149
  106. package/test/transforms/controlFlowFlattening/expressionObfuscation.test.ts +173 -0
  107. package/test/transforms/deadCode.test.ts +66 -15
  108. package/test/transforms/dispatcher.test.ts +44 -1
  109. package/test/transforms/es5/antiClass.test.ts +33 -0
  110. package/test/transforms/es5/antiDestructuring.test.ts +16 -0
  111. package/test/transforms/eval.test.ts +53 -0
  112. package/test/transforms/extraction/objectExtraction.test.ts +21 -0
  113. package/test/transforms/flatten.test.ts +195 -3
  114. package/test/transforms/identifier/movedDeclarations.test.ts +27 -0
  115. package/test/transforms/identifier/renameVariables.test.ts +108 -0
  116. package/test/transforms/lock/antiDebug.test.ts +2 -2
  117. package/test/transforms/minify.test.ts +151 -0
  118. package/test/transforms/preparation.test.ts +157 -0
  119. package/test/transforms/rgf.test.ts +56 -29
  120. package/test/transforms/stack.test.ts +91 -21
  121. package/test/transforms/string/stringCompression.test.ts +39 -0
  122. package/test/transforms/string/stringConcealing.test.ts +115 -0
  123. package/test/transforms/string/stringEncoding.test.ts +53 -2
  124. package/test/transforms/transform.test.ts +66 -0
  125. package/test/traverse.test.ts +139 -0
  126. package/test/util/compare.test.ts +23 -1
  127. package/src/transforms/controlFlowFlattening/choiceFlowObfuscation.ts +0 -87
  128. package/src/transforms/controlFlowFlattening/controlFlowObfuscation.ts +0 -203
  129. package/src/transforms/controlFlowFlattening/switchCaseObfuscation.ts +0 -130
  130. package/src/transforms/hexadecimalNumbers.ts +0 -31
  131. package/src/transforms/hideInitializingCode.ts +0 -432
  132. package/src/transforms/label.ts +0 -64
  133. package/src/transforms/preparation/nameConflicts.ts +0 -102
  134. package/src/transforms/preparation/preparation.ts +0 -176
  135. package/test/transforms/controlFlowFlattening/controlFlowObfuscation.test.ts +0 -101
  136. package/test/transforms/controlFlowFlattening/switchCaseObfuscation.test.ts +0 -120
  137. package/test/transforms/hideInitializingCode.test.ts +0 -336
  138. package/test/transforms/preparation/nameConflicts.test.ts +0 -52
  139. package/test/transforms/preparation/preparation.test.ts +0 -62
@@ -1,15 +1,14 @@
1
+ import { ok } from "assert";
1
2
  import { reservedIdentifiers } from "../constants";
2
3
  import { ObfuscateOrder } from "../order";
3
4
  import traverse, { walk } from "../traverse";
4
5
  import {
5
- FunctionDeclaration,
6
6
  Identifier,
7
7
  ReturnStatement,
8
8
  VariableDeclaration,
9
9
  VariableDeclarator,
10
10
  CallExpression,
11
11
  MemberExpression,
12
- ThisExpression,
13
12
  ArrayExpression,
14
13
  ExpressionStatement,
15
14
  AssignmentExpression,
@@ -19,21 +18,16 @@ import {
19
18
  FunctionExpression,
20
19
  ObjectExpression,
21
20
  Property,
22
- SpreadElement,
23
21
  Literal,
24
22
  IfStatement,
25
23
  ThrowStatement,
26
24
  NewExpression,
25
+ AwaitExpression,
26
+ UnaryExpression,
27
27
  } from "../util/gen";
28
28
  import { getIdentifierInfo } from "../util/identifiers";
29
- import {
30
- getBlockBody,
31
- getVarContext,
32
- isFunction,
33
- prepend,
34
- clone,
35
- } from "../util/insert";
36
- import { shuffle } from "../util/random";
29
+ import { getBlockBody, getVarContext, prepend, clone } from "../util/insert";
30
+ import { chance, shuffle } from "../util/random";
37
31
  import Transform from "./transform";
38
32
 
39
33
  /**
@@ -46,20 +40,19 @@ import Transform from "./transform";
46
40
  * return [ref1, ref2, refN, returnValue];
47
41
  * }
48
42
  * ```
43
+ *
44
+ * Flatten is used to make functions eligible for the RGF transformation.
49
45
  */
50
46
  export default class Flatten extends Transform {
51
47
  definedNames: Map<Node, Set<string>>;
52
-
53
- flatMapName: string;
54
- flatNode: Node;
55
- gen: any;
48
+ flattenedFns: Node[];
49
+ gen: ReturnType<Transform["getGenerator"]>;
56
50
 
57
51
  constructor(o) {
58
52
  super(o, ObfuscateOrder.Flatten);
59
53
 
60
54
  this.definedNames = new Map();
61
- this.flatMapName = null;
62
- this.flatNode = null;
55
+ this.flattenedFns = [];
63
56
  this.gen = this.getGenerator();
64
57
  }
65
58
 
@@ -87,33 +80,64 @@ export default class Flatten extends Transform {
87
80
  });
88
81
 
89
82
  super.apply(tree);
83
+
84
+ if (this.flattenedFns.length) {
85
+ prepend(tree, VariableDeclaration(this.flattenedFns));
86
+ }
90
87
  }
91
88
 
92
89
  match(object: Node, parents: Node[]) {
93
90
  return (
94
- object.type == "FunctionDeclaration" &&
91
+ (object.type == "FunctionDeclaration" ||
92
+ object.type === "FunctionExpression") &&
95
93
  object.body.type == "BlockStatement" &&
96
94
  !object.generator &&
97
- !object.async &&
98
95
  !object.params.find((x) => x.type !== "Identifier")
99
96
  );
100
97
  }
101
98
 
102
99
  transform(object: Node, parents: Node[]) {
103
100
  return () => {
104
- //
101
+ if (parents[0]) {
102
+ // Don't change class methods
103
+ if (
104
+ parents[0].type === "MethodDefinition" &&
105
+ parents[0].value === object
106
+ ) {
107
+ return;
108
+ }
105
109
 
106
- if (
107
- parents.find(
108
- (x) =>
109
- x.type == "ClassExpression" ||
110
- x.type == "ClassDeclaration" ||
111
- x.type == "MethodDefinition"
112
- )
113
- ) {
114
- return;
110
+ // Don't change getter/setter methods
111
+ if (
112
+ parents[0].type === "Property" &&
113
+ parents[0].value === object &&
114
+ parents[0].kind !== "init"
115
+ ) {
116
+ return;
117
+ }
115
118
  }
116
119
 
120
+ ok(
121
+ object.type === "FunctionDeclaration" ||
122
+ object.type === "FunctionExpression"
123
+ );
124
+
125
+ // The name is purely for debugging purposes
126
+ var currentFnName =
127
+ object.type === "FunctionDeclaration"
128
+ ? object.id?.name
129
+ : parents[0]?.type === "VariableDeclarator" &&
130
+ parents[0].id?.type === "Identifier" &&
131
+ parents[0].id?.name;
132
+
133
+ if (parents[0]?.type === "Property" && parents[0]?.key) {
134
+ currentFnName =
135
+ currentFnName ||
136
+ String(parents[0]?.key?.name || parents[0]?.key?.value);
137
+ }
138
+
139
+ if (!currentFnName) currentFnName = "unnamed";
140
+
117
141
  var defined = new Set<string>();
118
142
  var references = new Set<string>();
119
143
  var modified = new Set<string>();
@@ -147,9 +171,7 @@ export default class Flatten extends Transform {
147
171
 
148
172
  if (o.hidden) {
149
173
  illegal.add(o.name);
150
- }
151
-
152
- if (info.spec.isDefined) {
174
+ } else if (info.spec.isDefined) {
153
175
  defined.add(o.name);
154
176
  } else if (info.spec.isModified) {
155
177
  modified.add(o.name);
@@ -198,9 +220,6 @@ export default class Flatten extends Transform {
198
220
  return;
199
221
  }
200
222
 
201
- illegal.forEach((name) => {
202
- defined.delete(name);
203
- });
204
223
  defined.forEach((name) => {
205
224
  references.delete(name);
206
225
  modified.delete(name);
@@ -216,16 +235,35 @@ export default class Flatten extends Transform {
216
235
 
217
236
  var output = Array.from(modified);
218
237
 
219
- var newName = this.gen.generate();
220
- var valName = this.getPlaceholder();
238
+ var newName = this.getPlaceholder() + "_flat_" + currentFnName;
221
239
  var resultName = this.getPlaceholder();
222
240
  var propName = this.gen.generate();
223
241
 
242
+ var newOutputNames: { [originalName: string]: string } =
243
+ Object.create(null);
244
+ output.forEach((name) => {
245
+ newOutputNames[name] = this.gen.generate();
246
+ });
247
+ var returnOutputName = this.gen.generate();
248
+
224
249
  getBlockBody(object.body).push(ReturnStatement());
225
250
  walk(object.body, [object, ...parents], (o, p) => {
226
- return () => {
227
- if (o.type == "ReturnStatement" && getVarContext(o, p) === object) {
228
- var elements = output.map(Identifier);
251
+ // Change return statements from
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
+ );
266
+
229
267
  if (
230
268
  o.argument &&
231
269
  !(
@@ -233,11 +271,12 @@ export default class Flatten extends Transform {
233
271
  o.argument.name == "undefined"
234
272
  )
235
273
  ) {
236
- elements.unshift(clone(o.argument));
274
+ // FIX: The return argument must be executed first so it must use 'unshift'
275
+ returnObject.properties.unshift(
276
+ Property(Literal(returnOutputName), clone(o.argument), true)
277
+ );
237
278
  }
238
279
 
239
- o.argument = ArrayExpression(elements);
240
-
241
280
  o.argument = AssignmentExpression(
242
281
  "=",
243
282
  MemberExpression(
@@ -245,188 +284,192 @@ export default class Flatten extends Transform {
245
284
  Identifier(propName),
246
285
  false
247
286
  ),
248
- o.argument
287
+ returnObject
249
288
  );
250
- }
251
- };
289
+ };
290
+ }
252
291
  });
253
292
 
254
293
  var newBody = getBlockBody(object.body);
255
294
 
256
- newBody.unshift(
257
- VariableDeclaration(
258
- VariableDeclarator(
259
- ArrayPattern([
260
- ArrayPattern(input.map(Identifier)),
261
- ArrayPattern(clone(object.params)),
262
- Identifier(resultName),
263
- ]),
264
-
265
- Identifier(valName)
266
- )
267
- )
268
- );
269
-
270
- if (!this.flatMapName) {
271
- this.flatMapName = this.getPlaceholder();
272
- prepend(
273
- parents[parents.length - 1],
274
- VariableDeclaration(
275
- VariableDeclarator(
276
- this.flatMapName,
277
- (this.flatNode = ObjectExpression([]))
278
- )
279
- )
280
- );
295
+ // Remove 'use strict' directive
296
+ if (newBody.length > 0 && newBody[0].directive) {
297
+ newBody.shift();
281
298
  }
282
299
 
283
300
  var newFunctionExpression = FunctionExpression(
284
- [Identifier(valName)],
301
+ [
302
+ ArrayPattern(input.map((name) => Identifier(name))),
303
+ ArrayPattern(clone(object.params)),
304
+ Identifier(resultName),
305
+ ],
285
306
  newBody
286
307
  );
287
308
 
288
309
  newFunctionExpression.async = !!object.async;
289
310
  newFunctionExpression.generator = !!object.generator;
290
311
 
291
- var property = Property(
292
- Identifier(newName),
293
- newFunctionExpression,
294
- false
312
+ this.flattenedFns.push(
313
+ VariableDeclarator(newName, newFunctionExpression)
295
314
  );
296
- property.kind = "set";
297
-
298
- this.flatNode.properties.push(property);
299
315
 
300
- var identifier = MemberExpression(
301
- Identifier(this.flatMapName),
302
- Identifier(newName),
303
- false
316
+ var newParamNames: string[] = object.params.map(() =>
317
+ this.getPlaceholder()
304
318
  );
305
319
 
306
- var newParamNodes = object.params.map(() =>
307
- Identifier(this.getPlaceholder())
308
- );
309
-
310
- // var result = newFn.call([...refs], ...arguments)
311
- var call = VariableDeclaration([
312
- VariableDeclarator(resultName, ArrayExpression([])),
313
- VariableDeclarator(
314
- "_",
315
- AssignmentExpression(
316
- "=",
317
- identifier,
318
- ArrayExpression([
319
- ArrayExpression(input.map(Identifier)),
320
- ArrayExpression([...newParamNodes]),
321
- Identifier(resultName),
322
- ])
323
- )
324
- ),
325
- ]);
326
-
327
320
  // result.pop()
328
- var pop = CallExpression(
321
+ var getOutputMemberExpression = (outputName) =>
329
322
  MemberExpression(
330
- MemberExpression(Identifier(resultName), Identifier(propName), false),
331
- Literal("pop"),
323
+ MemberExpression(Identifier(resultName), Literal(propName), true),
324
+ Literal(outputName),
332
325
  true
333
- ),
334
- []
335
- );
326
+ );
336
327
 
337
- // var result = newFn.call([...refs], ...arguments)
338
- // modified1 = result.pop();
339
- // modified2 = result.pop();
340
- // ...modifiedN = result.pop();...
341
- //
342
- // return result.pop()
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),
333
+ ]);
334
+
335
+ var newObjectBody: Node[] = [
336
+ // var resultObject = {};
337
+ VariableDeclaration([
338
+ VariableDeclarator(resultName, ObjectExpression([])),
339
+ ]),
340
+
341
+ ExpressionStatement(
342
+ newFunctionExpression.async
343
+ ? AwaitExpression(callExpression)
344
+ : callExpression
345
+ ),
346
+ ];
343
347
 
344
- var newObjectBody: Node[] = [call];
345
348
  var outputReversed = [...output].reverse();
346
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
+ });
362
+
347
363
  // DECOY STATEMENTS
348
364
  var decoyKey = this.gen.generate();
349
365
  var decoyNodes = [
366
+ // if (result.random) throw result.prop.random
350
367
  IfStatement(
351
368
  MemberExpression(
352
369
  Identifier(resultName),
353
- Identifier(this.gen.generate()),
354
- false
370
+ Literal(this.gen.generate()),
371
+ true
355
372
  ),
356
373
  [
357
374
  ThrowStatement(
358
375
  NewExpression(Identifier("Error"), [
359
- Literal(this.getPlaceholder()),
376
+ getOutputMemberExpression(this.gen.generate()),
360
377
  ])
361
378
  ),
362
379
  ]
363
380
  ),
381
+ // if (result.random) return true;
364
382
  IfStatement(
365
383
  MemberExpression(
366
384
  Identifier(resultName),
367
- Identifier(this.gen.generate()),
368
- false
385
+ Literal(this.gen.generate()),
386
+ true
369
387
  ),
370
- [ReturnStatement(Identifier(resultName))]
388
+ [ReturnStatement(Literal(true))]
371
389
  ),
390
+ // if (result.random) return result;
372
391
  IfStatement(
373
392
  MemberExpression(
374
393
  Identifier(resultName),
375
- Identifier(this.gen.generate()),
376
- false
394
+ Literal(this.gen.generate()),
395
+ true
377
396
  ),
378
397
  [ReturnStatement(Identifier(resultName))]
379
398
  ),
399
+ // if (result.random) return result.random;
380
400
  IfStatement(
381
- MemberExpression(Identifier(resultName), Identifier(decoyKey), false),
401
+ MemberExpression(Identifier(resultName), Literal(decoyKey), true),
382
402
  [
383
403
  ReturnStatement(
384
- MemberExpression(
385
- Identifier(resultName),
386
- Identifier(decoyKey),
387
- false
388
- )
404
+ MemberExpression(Identifier(resultName), Literal(decoyKey), true)
389
405
  ),
390
406
  ]
391
407
  ),
408
+ // if(result.random1) return result.random2;
392
409
  IfStatement(
393
410
  MemberExpression(
394
411
  Identifier(resultName),
395
- Identifier(this.gen.generate()),
396
- false
412
+ Literal(this.gen.generate()),
413
+ true
397
414
  ),
398
415
  [
399
416
  ReturnStatement(
400
417
  MemberExpression(
401
418
  Identifier(resultName),
402
- Identifier(this.gen.generate()),
403
- false
419
+ Literal(this.gen.generate()),
420
+ true
404
421
  )
405
422
  ),
406
423
  ]
407
424
  ),
408
- ];
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
+ );
409
465
 
410
466
  shuffle(decoyNodes);
411
- decoyNodes.forEach((decoyNode) => {
412
- if (Math.random() < 0.5) {
413
- newObjectBody.push(decoyNode);
414
- }
415
- });
416
467
 
417
- newObjectBody.push(
418
- ...outputReversed.map((name) => {
419
- return ExpressionStatement(
420
- AssignmentExpression("=", Identifier(name), clone(pop))
421
- );
422
- }),
423
-
424
- ReturnStatement(clone(pop))
425
- );
468
+ newObjectBody.push(...decoyNodes);
426
469
 
427
470
  object.body = BlockStatement(newObjectBody);
428
471
 
429
- object.params = newParamNodes;
472
+ object.params = newParamNames.map((name) => Identifier(name));
430
473
  };
431
474
  }
432
475
  }
@@ -0,0 +1,85 @@
1
+ import { reservedKeywords } from "../../constants";
2
+ import { Location, Node } from "../../util/gen";
3
+ import { getIdentifierInfo } from "../../util/identifiers";
4
+ import Transform from "../transform";
5
+
6
+ /**
7
+ * Global Analysis is responsible for finding all the global variables used in the code.
8
+ *
9
+ * A 'global variable' is one that is:
10
+ * - Referenced
11
+ * - Never defined or overridden
12
+ */
13
+ export default class GlobalAnalysis extends Transform {
14
+ notGlobals: Set<string>;
15
+ globals: { [name: string]: Location[] };
16
+
17
+ constructor(o) {
18
+ super(o);
19
+
20
+ this.globals = Object.create(null);
21
+ this.notGlobals = new Set();
22
+ }
23
+
24
+ match(object: Node, parents: Node[]) {
25
+ return object.type == "Identifier" && !reservedKeywords.has(object.name);
26
+ }
27
+
28
+ transform(object: Node, parents: Node[]) {
29
+ // no touching `import()` or `import x from ...`
30
+ var importIndex = parents.findIndex(
31
+ (x) => x.type == "ImportExpression" || x.type == "ImportDeclaration"
32
+ );
33
+ if (importIndex !== -1) {
34
+ if (
35
+ parents[importIndex].source === (parents[importIndex - 1] || object)
36
+ ) {
37
+ return;
38
+ }
39
+ }
40
+
41
+ var info = getIdentifierInfo(object, parents);
42
+ if (!info.spec.isReferenced) {
43
+ return;
44
+ }
45
+
46
+ // Cannot be defined or overridden
47
+ if (info.spec.isDefined || info.spec.isModified) {
48
+ delete this.globals[object.name];
49
+
50
+ this.notGlobals.add(object.name);
51
+ return;
52
+ }
53
+
54
+ // Add to globals
55
+ if (!this.notGlobals.has(object.name)) {
56
+ if (!this.globals[object.name]) {
57
+ this.globals[object.name] = [];
58
+ }
59
+
60
+ this.globals[object.name].push([object, parents]);
61
+ }
62
+
63
+ var assignmentIndex = parents.findIndex(
64
+ (x) => x.type == "AssignmentExpression"
65
+ );
66
+ var updateIndex = parents.findIndex((x) => x.type == "UpdateExpression");
67
+
68
+ if (
69
+ (assignmentIndex != -1 &&
70
+ parents[assignmentIndex].left ===
71
+ (parents[assignmentIndex - 1] || object)) ||
72
+ updateIndex != -1
73
+ ) {
74
+ var memberIndex = parents.findIndex((x) => x.type == "MemberExpression");
75
+ if (
76
+ memberIndex == -1 ||
77
+ memberIndex > (assignmentIndex == -1 ? assignmentIndex : updateIndex)
78
+ ) {
79
+ delete this.globals[object.name];
80
+
81
+ this.notGlobals.add(object.name);
82
+ }
83
+ }
84
+ }
85
+ }