js-confuser 1.7.1 → 1.7.3

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 (153) hide show
  1. package/.github/workflows/node.js.yml +1 -1
  2. package/CHANGELOG.md +73 -0
  3. package/README.md +32 -31
  4. package/dist/compiler.js +2 -8
  5. package/dist/constants.js +22 -10
  6. package/dist/index.js +15 -30
  7. package/dist/obfuscator.js +15 -62
  8. package/dist/options.js +33 -40
  9. package/dist/order.js +4 -7
  10. package/dist/parser.js +5 -13
  11. package/dist/precedence.js +6 -8
  12. package/dist/presets.js +4 -6
  13. package/dist/probability.js +13 -24
  14. package/dist/templates/bufferToString.js +121 -5
  15. package/dist/templates/core.js +35 -0
  16. package/dist/templates/crash.js +22 -11
  17. package/dist/templates/es5.js +125 -6
  18. package/dist/templates/functionLength.js +24 -6
  19. package/dist/templates/globals.js +9 -0
  20. package/dist/templates/template.js +189 -43
  21. package/dist/transforms/antiTooling.js +26 -22
  22. package/dist/transforms/calculator.js +19 -55
  23. package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +242 -333
  24. package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +46 -25
  25. package/dist/transforms/deadCode.js +542 -31
  26. package/dist/transforms/dispatcher.js +112 -112
  27. package/dist/transforms/es5/antiClass.js +70 -44
  28. package/dist/transforms/es5/antiDestructuring.js +14 -38
  29. package/dist/transforms/es5/antiES6Object.js +39 -48
  30. package/dist/transforms/es5/antiSpreadOperator.js +5 -14
  31. package/dist/transforms/es5/antiTemplate.js +10 -19
  32. package/dist/transforms/es5/es5.js +7 -40
  33. package/dist/transforms/extraction/classExtraction.js +83 -0
  34. package/dist/transforms/extraction/duplicateLiteralsRemoval.js +41 -80
  35. package/dist/transforms/extraction/objectExtraction.js +24 -56
  36. package/dist/transforms/finalizer.js +6 -20
  37. package/dist/transforms/flatten.js +51 -99
  38. package/dist/transforms/identifier/globalAnalysis.js +21 -26
  39. package/dist/transforms/identifier/globalConcealing.js +72 -56
  40. package/dist/transforms/identifier/movedDeclarations.js +66 -38
  41. package/dist/transforms/identifier/renameVariables.js +36 -68
  42. package/dist/transforms/identifier/variableAnalysis.js +21 -48
  43. package/dist/transforms/lock/antiDebug.js +20 -25
  44. package/dist/transforms/lock/integrity.js +53 -52
  45. package/dist/transforms/lock/lock.js +161 -126
  46. package/dist/transforms/minify.js +77 -108
  47. package/dist/transforms/opaquePredicates.js +12 -49
  48. package/dist/transforms/preparation.js +28 -49
  49. package/dist/transforms/renameLabels.js +5 -22
  50. package/dist/transforms/rgf.js +125 -72
  51. package/dist/transforms/shuffle.js +42 -47
  52. package/dist/transforms/stack.js +41 -98
  53. package/dist/transforms/string/encoding.js +76 -27
  54. package/dist/transforms/string/stringCompression.js +75 -68
  55. package/dist/transforms/string/stringConcealing.js +127 -135
  56. package/dist/transforms/string/stringEncoding.js +6 -26
  57. package/dist/transforms/string/stringSplitting.js +5 -30
  58. package/dist/transforms/transform.js +76 -104
  59. package/dist/traverse.js +11 -18
  60. package/dist/util/compare.js +27 -29
  61. package/dist/util/gen.js +32 -86
  62. package/dist/util/guard.js +5 -1
  63. package/dist/util/identifiers.js +9 -72
  64. package/dist/util/insert.js +27 -77
  65. package/dist/util/math.js +0 -3
  66. package/dist/util/object.js +3 -7
  67. package/dist/util/random.js +31 -36
  68. package/dist/util/scope.js +6 -3
  69. package/docs/Countermeasures.md +13 -6
  70. package/docs/Integrity.md +35 -28
  71. package/docs/RGF.md +6 -1
  72. package/docs/RenameVariables.md +116 -0
  73. package/docs/TamperProtection.md +100 -0
  74. package/docs/Template.md +117 -0
  75. package/package.json +3 -3
  76. package/src/constants.ts +17 -0
  77. package/src/index.ts +7 -5
  78. package/src/options.ts +60 -7
  79. package/src/order.ts +2 -2
  80. package/src/templates/bufferToString.ts +79 -11
  81. package/src/templates/core.ts +29 -0
  82. package/src/templates/crash.ts +6 -38
  83. package/src/templates/es5.ts +1 -1
  84. package/src/templates/functionLength.ts +21 -3
  85. package/src/templates/globals.ts +3 -0
  86. package/src/templates/template.ts +205 -46
  87. package/src/transforms/antiTooling.ts +33 -11
  88. package/src/transforms/calculator.ts +4 -2
  89. package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +12 -5
  90. package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +46 -10
  91. package/src/transforms/deadCode.ts +74 -42
  92. package/src/transforms/dispatcher.ts +99 -73
  93. package/src/transforms/es5/antiClass.ts +25 -12
  94. package/src/transforms/es5/antiDestructuring.ts +1 -1
  95. package/src/transforms/es5/antiES6Object.ts +2 -2
  96. package/src/transforms/es5/antiTemplate.ts +1 -1
  97. package/src/transforms/extraction/classExtraction.ts +168 -0
  98. package/src/transforms/extraction/duplicateLiteralsRemoval.ts +11 -16
  99. package/src/transforms/extraction/objectExtraction.ts +4 -15
  100. package/src/transforms/flatten.ts +20 -5
  101. package/src/transforms/identifier/globalAnalysis.ts +18 -1
  102. package/src/transforms/identifier/globalConcealing.ts +119 -72
  103. package/src/transforms/identifier/movedDeclarations.ts +90 -24
  104. package/src/transforms/identifier/renameVariables.ts +16 -1
  105. package/src/transforms/lock/antiDebug.ts +2 -2
  106. package/src/transforms/lock/integrity.ts +13 -11
  107. package/src/transforms/lock/lock.ts +122 -30
  108. package/src/transforms/minify.ts +28 -13
  109. package/src/transforms/opaquePredicates.ts +2 -2
  110. package/src/transforms/preparation.ts +16 -0
  111. package/src/transforms/rgf.ts +139 -12
  112. package/src/transforms/shuffle.ts +3 -3
  113. package/src/transforms/stack.ts +19 -4
  114. package/src/transforms/string/encoding.ts +88 -51
  115. package/src/transforms/string/stringCompression.ts +86 -17
  116. package/src/transforms/string/stringConcealing.ts +148 -118
  117. package/src/transforms/string/stringEncoding.ts +1 -2
  118. package/src/transforms/string/stringSplitting.ts +1 -2
  119. package/src/transforms/transform.ts +63 -46
  120. package/src/types.ts +2 -0
  121. package/src/util/compare.ts +39 -5
  122. package/src/util/gen.ts +10 -3
  123. package/src/util/guard.ts +10 -0
  124. package/src/util/insert.ts +17 -0
  125. package/src/util/random.ts +81 -1
  126. package/src/util/scope.ts +14 -2
  127. package/test/code/Cash.test.ts +94 -5
  128. package/test/code/StrictMode.src.js +65 -0
  129. package/test/code/StrictMode.test.js +37 -0
  130. package/test/compare.test.ts +62 -2
  131. package/test/options.test.ts +129 -55
  132. package/test/templates/template.test.ts +211 -1
  133. package/test/transforms/controlFlowFlattening/expressionObfuscation.test.ts +37 -18
  134. package/test/transforms/dispatcher.test.ts +55 -0
  135. package/test/transforms/extraction/classExtraction.test.ts +86 -0
  136. package/test/transforms/extraction/duplicateLiteralsRemoval.test.ts +8 -0
  137. package/test/transforms/extraction/objectExtraction.test.ts +2 -0
  138. package/test/transforms/identifier/globalConcealing.test.ts +89 -0
  139. package/test/transforms/identifier/movedDeclarations.test.ts +61 -0
  140. package/test/transforms/identifier/renameVariables.test.ts +75 -1
  141. package/test/transforms/lock/tamperProtection.test.ts +336 -0
  142. package/test/transforms/minify.test.ts +37 -0
  143. package/test/transforms/rgf.test.ts +50 -0
  144. package/dist/transforms/controlFlowFlattening/choiceFlowObfuscation.js +0 -62
  145. package/dist/transforms/controlFlowFlattening/controlFlowObfuscation.js +0 -159
  146. package/dist/transforms/controlFlowFlattening/switchCaseObfuscation.js +0 -106
  147. package/dist/transforms/eval.js +0 -84
  148. package/dist/transforms/hexadecimalNumbers.js +0 -63
  149. package/dist/transforms/hideInitializingCode.js +0 -270
  150. package/dist/transforms/identifier/nameRecycling.js +0 -218
  151. package/dist/transforms/label.js +0 -67
  152. package/dist/transforms/preparation/nameConflicts.js +0 -116
  153. package/dist/transforms/preparation/preparation.js +0 -188
@@ -509,7 +509,14 @@ test.each(["hexadecimal", "mangled", "number", "zeroWidth"])(
509
509
  `
510
510
  var myVar1 = "Correct Value";
511
511
 
512
- TEST_OUTPUT = myVar1;
512
+ function myFunction(myVar2){
513
+ myVar2 = myVar1;
514
+ let myVar3 = myVar2;
515
+ var myVar4 = myVar3;
516
+ return myVar4;
517
+ }
518
+
519
+ TEST_OUTPUT = myFunction();
513
520
  `,
514
521
  {
515
522
  target: "node",
@@ -619,3 +626,70 @@ test("Variant #25: Reference catch parameter", async () => {
619
626
 
620
627
  expect(TEST_OUTPUT).toStrictEqual("Correct Value");
621
628
  });
629
+
630
+ test("Variant #26: Transform __JS_CONFUSER_VAR__ to access variable mappings", async () => {
631
+ var output = await JsConfuser(
632
+ `
633
+ var myVar1 = "Incorrect Value";
634
+
635
+ function myFunction(){
636
+ var myVar1 = "Correct Value";
637
+ TEST_OUTPUT = eval( __JS_CONFUSER_VAR__(myVar1) );
638
+ }
639
+
640
+ myFunction();
641
+ `,
642
+ { target: "node", renameVariables: true }
643
+ );
644
+
645
+ expect(output).not.toContain("myVar1");
646
+ expect(output).not.toContain("__JS_CONFUSER_VAR__");
647
+
648
+ var TEST_OUTPUT;
649
+
650
+ eval(output);
651
+ expect(TEST_OUTPUT).toStrictEqual("Correct Value");
652
+ });
653
+
654
+ test("Variant #27: Transform __JS_CONFUSER_VAR__ even when Rename Variables is disabled", async () => {
655
+ var output = await JsConfuser(
656
+ `
657
+ var name = "John Doe";
658
+ TEST_OUTPUT = __JS_CONFUSER_VAR__(name);
659
+ `,
660
+ { target: "node", renameVariables: false }
661
+ );
662
+
663
+ expect(output).not.toContain("__JS_CONFUSER_VAR__");
664
+
665
+ var TEST_OUTPUT;
666
+
667
+ eval(output);
668
+ expect(TEST_OUTPUT).toStrictEqual("name");
669
+ });
670
+
671
+ test("Variant #28: Transform __JS_CONFUSER_VAR__ on High Preset", async () => {
672
+ var output = await JsConfuser(
673
+ `
674
+ function myFunction(){
675
+ var a
676
+ var b
677
+ var c
678
+
679
+ return "Correct Value"
680
+ }
681
+ TEST_OUTPUT = eval(__JS_CONFUSER_VAR__(myFunction) + "()");
682
+ `,
683
+ {
684
+ target: "node",
685
+ preset: "high",
686
+ }
687
+ );
688
+
689
+ expect(output).not.toContain("__JS_CONFUSER_VAR__");
690
+
691
+ var TEST_OUTPUT;
692
+ eval(output);
693
+
694
+ expect(TEST_OUTPUT).toStrictEqual("Correct Value");
695
+ });
@@ -0,0 +1,336 @@
1
+ import JsConfuser from "../../../src/index";
2
+
3
+ var _eval = eval;
4
+
5
+ function evalInNonStrictMode(str: string) {
6
+ var TEST_OUTPUT;
7
+
8
+ function TEST_OUTPUT_SET(value) {
9
+ TEST_OUTPUT = value;
10
+ }
11
+
12
+ try {
13
+ // 'new Function' runs in non-strict mode
14
+ // The original 'eval' function is passed in each test
15
+ // This is because once 'eval' is changed, it is changed for all new Function() calls!
16
+ var fn = new Function("TEST_OUTPUT_SET", "eval", str);
17
+
18
+ fn(TEST_OUTPUT_SET, _eval);
19
+ } catch (err) {
20
+ return { error: err, TEST_OUTPUT: TEST_OUTPUT };
21
+ }
22
+
23
+ return { error: null, TEST_OUTPUT: TEST_OUTPUT };
24
+ }
25
+
26
+ describe("Global Concealing", () => {
27
+ test("Variant #1: Detect Eval tamper (no tamper)", async () => {
28
+ var code = `
29
+ global.TEST_GLOBAL_OUTPUT = global.TEST_GLOBAL;
30
+ `;
31
+
32
+ var output = await JsConfuser(code, {
33
+ target: "node",
34
+ globalConcealing: true,
35
+ lock: {
36
+ tamperProtection: true,
37
+ },
38
+ });
39
+
40
+ var TEST_GLOBAL = {};
41
+ (global as any).TEST_GLOBAL = TEST_GLOBAL;
42
+
43
+ evalInNonStrictMode(output);
44
+
45
+ // Make reuse global variable as 'new Function' runs in isolated environment
46
+ var TEST_OUTPUT = (global as any).TEST_GLOBAL_OUTPUT;
47
+
48
+ expect(TEST_OUTPUT).toStrictEqual(TEST_GLOBAL);
49
+ });
50
+
51
+ test("Variant #2: Detect Eval tamper (tampered)", async () => {
52
+ var code = `
53
+ function onTamperDetected(){
54
+ TEST_OUTPUT_SET(true);
55
+ }
56
+ global.TEST_GLOBAL_VARIANT_7_OUTPUT = global.TEST_GLOBAL_VARIANT_7;
57
+ `;
58
+
59
+ var output = await JsConfuser(code, {
60
+ target: "node",
61
+ globalConcealing: (varName) => varName != "TEST_OUTPUT_SET",
62
+ lock: {
63
+ tamperProtection: true,
64
+ countermeasures: "onTamperDetected",
65
+ },
66
+ });
67
+
68
+ // Inject 'eval' tamper code
69
+ output =
70
+ `var _eval = eval;
71
+ eval = (codeStr)=>( console.log(codeStr), _eval(codeStr) );
72
+ ` + output;
73
+
74
+ var TEST_GLOBAL_VARIANT_7 = {};
75
+ (global as any).TEST_GLOBAL_VARIANT_7 = TEST_GLOBAL_VARIANT_7;
76
+
77
+ var { error, TEST_OUTPUT } = evalInNonStrictMode(output);
78
+
79
+ expect(error).toBeNull();
80
+ expect(TEST_OUTPUT).toStrictEqual(true);
81
+ });
82
+
83
+ test("Variant #3: Native check on functions", async () => {
84
+ var mockConsoleLog = (...msgs) => {
85
+ console.log(...msgs);
86
+ };
87
+ mockConsoleLog.toString = () => "{ [native code] }";
88
+ (global as any).mockConsoleLog = mockConsoleLog;
89
+
90
+ var output = await JsConfuser(
91
+ `
92
+ function onTamperDetected(){
93
+ TEST_OUTPUT_SET(true);
94
+ }
95
+ mockConsoleLog("console.log was not tampered")
96
+ `,
97
+ {
98
+ target: "node",
99
+ globalConcealing: (varName) => varName != "TEST_OUTPUT_SET",
100
+ lock: {
101
+ tamperProtection: true,
102
+ countermeasures: "onTamperDetected",
103
+ },
104
+ }
105
+ );
106
+
107
+ var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
108
+ (global as any).Object.getOwnPropertyDescriptor = () => undefined;
109
+
110
+ var { TEST_OUTPUT, error } = evalInNonStrictMode(output);
111
+
112
+ (global as any).Object.getOwnPropertyDescriptor = getOwnPropertyDescriptor;
113
+
114
+ expect(TEST_OUTPUT).not.toStrictEqual(true);
115
+ expect(error).toBeNull();
116
+ });
117
+
118
+ test("Variant #4: Native check on functions (tampered)", async () => {
119
+ var mockConsoleLog = (...msgs) => {
120
+ console.log(...msgs);
121
+ };
122
+ mockConsoleLog.toString = () => "[native code]";
123
+ (global as any).mockConsoleLog = mockConsoleLog;
124
+
125
+ var output = await JsConfuser(
126
+ `
127
+ function onTamperDetected(){
128
+ TEST_OUTPUT_SET(true);
129
+ }
130
+
131
+ mockConsoleLog("console.log was not tampered")
132
+ `,
133
+ {
134
+ target: "node",
135
+ globalConcealing: (varName) => varName != "TEST_OUTPUT_SET",
136
+ lock: {
137
+ tamperProtection: true,
138
+ countermeasures: "onTamperDetected",
139
+ },
140
+ }
141
+ );
142
+
143
+ (global as any).mockConsoleLog = (...str) =>
144
+ console.log("Tampered console.log: ", ...str);
145
+
146
+ // Unfortunately the program errors dude to console.log being tampered
147
+ var { TEST_OUTPUT, error } = evalInNonStrictMode(output);
148
+
149
+ expect(TEST_OUTPUT).toStrictEqual(true);
150
+
151
+ // Ensure error was thrown
152
+ expect(error).not.toBeNull();
153
+ });
154
+
155
+ test("Variant #5: Native check on non-existent functions", async () => {
156
+ var output = await JsConfuser(
157
+ `
158
+ a.b.c.d()
159
+ `,
160
+ {
161
+ target: "node",
162
+ globalConcealing: true,
163
+ lock: {
164
+ tamperProtection: true,
165
+ },
166
+ }
167
+ );
168
+ });
169
+
170
+ test("Variant #6: Custom implementation for lock.tamperProtection", async () => {
171
+ var foundNames = [];
172
+ var output = await JsConfuser(
173
+ `
174
+ fetch()
175
+ console.log()
176
+ shouldBeFound()
177
+ console["trace"]()
178
+ var NotFound = "NotFound"
179
+ console[NotFound]()
180
+
181
+ toString()
182
+
183
+ var shouldNotBeFound;
184
+
185
+ shouldNotBeFound()
186
+ `,
187
+ {
188
+ target: "node",
189
+ globalConcealing: true,
190
+ lock: {
191
+ tamperProtection: (fnName) => {
192
+ foundNames.push(fnName);
193
+
194
+ return false;
195
+ },
196
+ },
197
+ }
198
+ );
199
+
200
+ expect(foundNames).toContain("fetch");
201
+ expect(foundNames).toContain("console.log");
202
+ expect(foundNames).toContain("shouldBeFound");
203
+ expect(foundNames).toContain("console.trace");
204
+ expect(foundNames).toContain("toString");
205
+
206
+ expect(foundNames.join("")).not.toContain("NotFound");
207
+
208
+ expect(foundNames).not.toContain("shouldNotBeFound");
209
+ });
210
+
211
+ test("Variant #7: Protect native function Math.floor", async () => {
212
+ var output = await JsConfuser(
213
+ `
214
+ TEST_OUTPUT_SET(Math.floor(10.1));
215
+ `,
216
+ {
217
+ target: "node",
218
+ globalConcealing: (varName) => varName != "TEST_OUTPUT_SET",
219
+ lock: {
220
+ tamperProtection: true,
221
+ },
222
+ }
223
+ );
224
+
225
+ expect(output).not.toContain("Math['floor");
226
+
227
+ var { TEST_OUTPUT, error } = evalInNonStrictMode(output);
228
+
229
+ expect(error).toBeNull();
230
+ expect(TEST_OUTPUT).toStrictEqual(10);
231
+ });
232
+ });
233
+
234
+ describe("RGF", () => {
235
+ test("Variant #1: Use Eval instead of new Function", async () => {
236
+ var output = await JsConfuser(
237
+ `
238
+ function myFunction1(){
239
+ TEST_OUTPUT_SET(true);
240
+ }
241
+
242
+ myFunction1();
243
+ `,
244
+ {
245
+ target: "node",
246
+ rgf: true,
247
+ lock: {
248
+ tamperProtection: true,
249
+ },
250
+ renameVariables: true,
251
+
252
+ // Allow RGF to transform 'myFunction1'
253
+ // Otherwise, RGF will skip 'myFunction1' as 'TEST_OUTPUT_SET' is an outside variable
254
+ globalVariables: new Set(["TEST_OUTPUT_SET"]),
255
+ }
256
+ );
257
+
258
+ expect(output).not.toContain(
259
+ "function myFunction1(){TEST_OUTPUT_SET(true)"
260
+ );
261
+ expect(output).toContain("eval");
262
+ expect(output).not.toContain("new Function");
263
+
264
+ var { TEST_OUTPUT, error } = evalInNonStrictMode(output);
265
+
266
+ expect(error).toBeNull();
267
+ expect(TEST_OUTPUT).toStrictEqual(true);
268
+ });
269
+
270
+ test("Variant #2: Detect Eval tamper", async () => {
271
+ var output = await JsConfuser(
272
+ `
273
+ function onTamperDetected(){
274
+ TEST_OUTPUT_SET("Correct Value");
275
+ }
276
+ function myFunction1(){
277
+ TEST_OUTPUT_SET("Function still called");
278
+ }
279
+
280
+ myFunction1();
281
+ `,
282
+ {
283
+ target: "node",
284
+ rgf: true,
285
+ lock: {
286
+ tamperProtection: true,
287
+ countermeasures: "onTamperDetected",
288
+ },
289
+ renameVariables: true,
290
+
291
+ // Allow RGF to transform 'myFunction1'
292
+ // Otherwise, RGF will skip 'myFunction1' as 'TEST_OUTPUT_SET' is an outside variable
293
+ globalVariables: new Set(["TEST_OUTPUT_SET"]),
294
+ }
295
+ );
296
+
297
+ expect(output).not.toContain("function myFunction1(){TEST_OUTPUT_SET(");
298
+ expect(output).toContain("eval");
299
+
300
+ // Inject 'eval' tamper code
301
+ output =
302
+ `var _eval = eval;
303
+ eval = (code)=>( TEST_OUTPUT_SET(code), console.log(code), _eval(code) );` +
304
+ output;
305
+
306
+ var { TEST_OUTPUT, error } = evalInNonStrictMode(output);
307
+
308
+ expect(TEST_OUTPUT).toStrictEqual("Correct Value");
309
+ expect(error).toBeTruthy(); // An error occurs because the RGF array was not initialized
310
+ });
311
+ });
312
+
313
+ describe("Strict Mode", () => {
314
+ test("Variant #1: Disallow Strict Mode", async () => {
315
+ var output = await JsConfuser(
316
+ `
317
+ "use strict"; // Note: Jest testing environment is already in Strict Mode
318
+ function onTamperDetected(){
319
+ TEST_OUTPUT = true;
320
+ }
321
+ `,
322
+ {
323
+ target: "node",
324
+ lock: {
325
+ tamperProtection: true,
326
+ countermeasures: "onTamperDetected",
327
+ },
328
+ }
329
+ );
330
+
331
+ var TEST_OUTPUT;
332
+ eval(output);
333
+
334
+ expect(TEST_OUTPUT).toStrictEqual(true);
335
+ });
336
+ });
@@ -211,6 +211,16 @@ test("Variant #11: Shorten 'undefined' to 'void 0'", async () => {
211
211
  });
212
212
 
213
213
  expect(output2).toContain("var x={[void 0]:1}");
214
+
215
+ var output3 = await JsConfuser(
216
+ `try { var undefined; (undefined) = true } catch(e) {}`,
217
+ {
218
+ target: "node",
219
+ minify: true,
220
+ }
221
+ );
222
+
223
+ eval(output3);
214
224
  });
215
225
 
216
226
  test("Variant #11: Shorten 'Infinity' to 1/0", async () => {
@@ -536,3 +546,30 @@ test("Variant #27: Preserve function.length property", async () => {
536
546
 
537
547
  expect(TEST_OUTPUT).toStrictEqual(6);
538
548
  });
549
+
550
+ // https://github.com/MichaelXF/js-confuser/issues/125
551
+ test("Variant #28: Don't break destructuring assignment", async () => {
552
+ var output = await JsConfuser(
553
+ `
554
+ let objectSlice = [];
555
+ objectSlice.push({
556
+ a: 1,
557
+ b: 2,
558
+ c: 3,
559
+ })
560
+ for (let {
561
+ a,
562
+ b,
563
+ c
564
+ } of objectSlice) {
565
+ TEST_OUTPUT = a + b + c;
566
+ }
567
+ `,
568
+ { target: "node", minify: true }
569
+ );
570
+
571
+ var TEST_OUTPUT;
572
+ eval(output);
573
+
574
+ expect(TEST_OUTPUT).toStrictEqual(6);
575
+ });
@@ -326,3 +326,53 @@ test("Variant #10: Configurable by custom function option", async () => {
326
326
  expect(TEST_OUTPUT_1).toStrictEqual(false);
327
327
  expect(TEST_OUTPUT_2).toStrictEqual(true);
328
328
  });
329
+
330
+ test("Variant #11: Function containing function should both be changed", async function () {
331
+ var output = await JsConfuser(
332
+ `
333
+ function FunctionA(){
334
+ function FunctionB(){
335
+ var bVar = 10;
336
+ return bVar
337
+ }
338
+
339
+ var bFn = FunctionB;
340
+ var aVar = bFn();
341
+ return aVar + 1
342
+ }
343
+
344
+ TEST_OUTPUT = FunctionA();
345
+ `,
346
+ { target: "node", rgf: true }
347
+ );
348
+
349
+ // 2 means one Function changed, 3 means two Functions changed
350
+ expect(output.split("new Function").length).toStrictEqual(3);
351
+
352
+ var TEST_OUTPUT;
353
+ eval(output);
354
+
355
+ expect(TEST_OUTPUT).toStrictEqual(11);
356
+ });
357
+
358
+ test("Variant #12: Preserve Function.length", async function () {
359
+ var output = await JsConfuser(
360
+ `
361
+ function myFunction(a,b,c,d = ""){ // Function.length = 3
362
+
363
+ }
364
+
365
+ myFunction()
366
+ TEST_OUTPUT = myFunction.length
367
+ `,
368
+ {
369
+ target: "node",
370
+ rgf: true,
371
+ }
372
+ );
373
+
374
+ var TEST_OUTPUT;
375
+ eval(output);
376
+
377
+ expect(TEST_OUTPUT).toStrictEqual(3);
378
+ });
@@ -1,62 +0,0 @@
1
- "use strict";
2
-
3
- Object.defineProperty(exports, "__esModule", {
4
- value: true
5
- });
6
- exports.default = void 0;
7
-
8
- var _gen = require("../../util/gen");
9
-
10
- var _transform = _interopRequireDefault(require("../transform"));
11
-
12
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
-
14
- class ChoiceFlowObfuscation extends _transform.default {
15
- constructor(o) {
16
- super(o);
17
- }
18
-
19
- match(object, parents) {
20
- return object.type == "IfStatement";
21
- }
22
-
23
- transform(object, parents) {
24
- return () => {
25
- var body = parents[0];
26
- var element = object;
27
-
28
- if (parents[0].type == "LabeledStatement") {
29
- body = parents[1];
30
- element = parents[0];
31
- }
32
-
33
- var before = [];
34
- var isNested = parents[0].type == "IfStatement" && parents[0].alternate === object;
35
-
36
- if (!isNested && (!Array.isArray(body) || body.indexOf(element) === -1)) {
37
- return;
38
- }
39
-
40
- var result = this.getPlaceholder();
41
- before.push((0, _gen.VariableDeclaration)((0, _gen.VariableDeclarator)(result)));
42
- var yesBody = object.consequent ? object.consequent.type == "BlockStatement" ? [...object.consequent.body] : [object.consequent] : [];
43
- yesBody.unshift((0, _gen.ExpressionStatement)((0, _gen.AssignmentExpression)("=", (0, _gen.Identifier)(result), (0, _gen.Literal)(1))));
44
- var noBody = object.alternate ? object.alternate.type == "BlockStatement" ? [...object.alternate.body] : [object.alternate] : [];
45
- noBody.unshift((0, _gen.ExpressionStatement)((0, _gen.AssignmentExpression)("=", (0, _gen.Identifier)(result), (0, _gen.Literal)(1))));
46
- var elseTest = (0, _gen.UnaryExpression)("!", (0, _gen.Identifier)(result));
47
- var newObject = (0, _gen.TryStatement)([(0, _gen.IfStatement)({ ...object.test
48
- }, [(0, _gen.ThrowStatement)((0, _gen.Identifier)(result))])], (0, _gen.CatchClause)((0, _gen.Identifier)(this.getPlaceholder()), yesBody), [(0, _gen.IfStatement)(elseTest, noBody)]);
49
-
50
- if (isNested) {
51
- this.replace(object, (0, _gen.BlockStatement)([...before, { ...newObject
52
- }]));
53
- } else {
54
- body.splice(body.indexOf(element), 0, ...before);
55
- this.replace(object, newObject);
56
- }
57
- };
58
- }
59
-
60
- }
61
-
62
- exports.default = ChoiceFlowObfuscation;