js-confuser 1.5.8 → 1.5.9

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 (62) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/dist/index.js +45 -4
  3. package/dist/obfuscator.js +10 -5
  4. package/dist/options.js +2 -3
  5. package/dist/order.js +3 -3
  6. package/dist/transforms/antiTooling.js +1 -1
  7. package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +4 -2
  8. package/dist/transforms/dispatcher.js +3 -3
  9. package/dist/transforms/es5/antiClass.js +6 -2
  10. package/dist/transforms/es5/antiDestructuring.js +1 -1
  11. package/dist/transforms/eval.js +11 -0
  12. package/dist/transforms/extraction/duplicateLiteralsRemoval.js +4 -4
  13. package/dist/transforms/extraction/objectExtraction.js +6 -1
  14. package/dist/transforms/flatten.js +73 -50
  15. package/dist/transforms/hexadecimalNumbers.js +34 -9
  16. package/dist/transforms/identifier/movedDeclarations.js +1 -1
  17. package/dist/transforms/minify.js +22 -6
  18. package/dist/transforms/rgf.js +4 -4
  19. package/dist/transforms/stack.js +1 -1
  20. package/dist/transforms/string/stringConcealing.js +2 -2
  21. package/dist/traverse.js +0 -8
  22. package/dist/util/compare.js +2 -2
  23. package/dist/util/insert.js +20 -6
  24. package/package.json +1 -1
  25. package/src/index.ts +57 -19
  26. package/src/obfuscator.ts +6 -1
  27. package/src/options.ts +10 -2
  28. package/src/order.ts +3 -3
  29. package/src/transforms/antiTooling.ts +1 -1
  30. package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +14 -2
  31. package/src/transforms/dispatcher.ts +4 -3
  32. package/src/transforms/es5/antiClass.ts +10 -1
  33. package/src/transforms/es5/antiDestructuring.ts +1 -1
  34. package/src/transforms/eval.ts +18 -0
  35. package/src/transforms/extraction/duplicateLiteralsRemoval.ts +5 -5
  36. package/src/transforms/extraction/objectExtraction.ts +12 -5
  37. package/src/transforms/flatten.ts +181 -128
  38. package/src/transforms/hexadecimalNumbers.ts +37 -9
  39. package/src/transforms/identifier/movedDeclarations.ts +1 -1
  40. package/src/transforms/minify.ts +37 -5
  41. package/src/transforms/rgf.ts +4 -3
  42. package/src/transforms/stack.ts +3 -1
  43. package/src/transforms/string/stringConcealing.ts +2 -2
  44. package/src/traverse.ts +1 -8
  45. package/src/types.ts +9 -1
  46. package/src/util/compare.ts +2 -2
  47. package/src/util/insert.ts +37 -8
  48. package/test/code/ES6.src.js +14 -0
  49. package/test/code/NewFeatures.test.ts +19 -0
  50. package/test/index.test.ts +13 -1
  51. package/test/transforms/antiTooling.test.ts +30 -0
  52. package/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts +22 -0
  53. package/test/transforms/dispatcher.test.ts +24 -0
  54. package/test/transforms/es5/antiClass.test.ts +33 -0
  55. package/test/transforms/eval.test.ts +53 -0
  56. package/test/transforms/extraction/objectExtraction.test.ts +21 -0
  57. package/test/transforms/flatten.test.ts +146 -3
  58. package/test/transforms/identifier/renameVariables.test.ts +26 -0
  59. package/test/transforms/minify.test.ts +66 -0
  60. package/test/transforms/rgf.test.ts +56 -0
  61. package/test/transforms/string/stringConcealing.test.ts +33 -0
  62. package/test/util/compare.test.ts +23 -1
@@ -214,7 +214,7 @@ export default class StringConcealing extends Transform {
214
214
  if (Math.random() > 0.5) {
215
215
  callExpr = CallExpression(
216
216
  MemberExpression(Identifier(fnName), Identifier("apply"), false),
217
- [ThisExpression(), ArrayExpression([Literal(index)])]
217
+ [Identifier("undefined"), ArrayExpression([Literal(index)])]
218
218
  );
219
219
  }
220
220
 
@@ -222,7 +222,7 @@ export default class StringConcealing extends Transform {
222
222
  else if (Math.random() > 0.5) {
223
223
  callExpr = CallExpression(
224
224
  MemberExpression(Identifier(fnName), Identifier("call"), false),
225
- [ThisExpression(), Literal(index)]
225
+ [Identifier("undefined"), Literal(index)]
226
226
  );
227
227
  }
228
228
 
package/src/traverse.ts CHANGED
@@ -39,16 +39,9 @@ export type ExitCallback = () => void;
39
39
  export function walk(
40
40
  object: Node | Node[],
41
41
  parents: Node[],
42
- onEnter: EnterCallback,
43
- seen = new Set<Node>()
42
+ onEnter: EnterCallback
44
43
  ): "EXIT" | void {
45
44
  if (typeof object === "object" && object) {
46
- if (seen.has(object as any)) {
47
- console.log(object);
48
- throw new Error("Already seen: " + (object as any).type);
49
- }
50
- seen.add(object as any);
51
-
52
45
  var newParents: Node[] = [object as Node, ...parents];
53
46
 
54
47
  if (!Array.isArray(object)) {
package/src/types.ts CHANGED
@@ -119,4 +119,12 @@ export type IJsConfuserDebugObfuscation = (
119
119
  code: string,
120
120
  options: ObfuscateOptions,
121
121
  callback: (name: string, complete: number, totalTransforms: number) => void
122
- ) => Promise<string>;
122
+ ) => Promise<{
123
+ obfuscated: string;
124
+ transformationTimes: { [transformName: string]: number };
125
+ parseTime: number;
126
+ compileTime: number;
127
+ obfuscationTime: number;
128
+ totalTransforms: number;
129
+ totalPossibleTransforms: number;
130
+ }>;
@@ -53,8 +53,8 @@ export function isValidIdentifier(name: string): boolean {
53
53
  return false;
54
54
  }
55
55
 
56
- var x = name.match(/^[A-z$_][A-z0-9$_]*/);
57
- return x && x[0] == name;
56
+ var x = name.match(/^[A-Za-z$_][A-Za-z0-9$_]*/);
57
+ return !!(x && x[0] == name);
58
58
  }
59
59
 
60
60
  export function isInsideType(
@@ -113,8 +113,14 @@ export function getDefiningContext(o: Node, p: Node[]): Node {
113
113
  var variableDeclaration = p.find((x) => x.type == "VariableDeclaration");
114
114
  ok(variableDeclaration);
115
115
 
116
- if (variableDeclaration.kind === "let") {
117
- return getLexContext(o, p);
116
+ if (
117
+ variableDeclaration.kind === "let" ||
118
+ variableDeclaration.kind === "const"
119
+ ) {
120
+ var context = getVarContext(o, p);
121
+ if (context && context.type === "Program") {
122
+ return getLexContext(o, p);
123
+ }
118
124
  }
119
125
  }
120
126
 
@@ -178,7 +184,7 @@ export function getBlockBody(block: Node): Node[] {
178
184
  return getBlockBody(block.body);
179
185
  }
180
186
 
181
- export function getIndexDirect(object: Node, parent: Node[]): string {
187
+ export function getIndexDirect(object: Node, parent: Node): string {
182
188
  return Object.keys(parent).find((x) => parent[x] == object);
183
189
  }
184
190
 
@@ -255,16 +261,25 @@ export function prepend(block: Node, ...nodes: Node[]) {
255
261
  ok(!Array.isArray(block), "block should not be array");
256
262
 
257
263
  if (block.type == "Program") {
258
- var decs = 0;
264
+ var moveBy = 0;
259
265
  block.body.forEach((stmt, i) => {
260
266
  if (stmt.type == "ImportDeclaration") {
261
- if (decs == i) {
262
- decs++;
267
+ if (moveBy == i) {
268
+ moveBy++;
269
+ }
270
+ }
271
+
272
+ if (
273
+ stmt.type === "ExpressionStatement" &&
274
+ typeof stmt.directive === "string"
275
+ ) {
276
+ if (moveBy == i) {
277
+ moveBy++;
263
278
  }
264
279
  }
265
280
  });
266
281
 
267
- block.body.splice(decs, 0, ...nodes);
282
+ block.body.splice(moveBy, 0, ...nodes);
268
283
  } else {
269
284
  getBlockBody(block).unshift(...nodes);
270
285
  }
@@ -313,7 +328,10 @@ export function clone<T>(object: T): T {
313
328
  * @param p
314
329
  * @returns
315
330
  */
316
- export function isForInitialize(o, p): "initializer" | "left-hand" | false {
331
+ export function isForInitialize(
332
+ o: Node,
333
+ p: Node[]
334
+ ): "initializer" | "left-hand" | false {
317
335
  validateChain(o, p);
318
336
 
319
337
  var forIndex = p.findIndex(
@@ -322,6 +340,17 @@ export function isForInitialize(o, p): "initializer" | "left-hand" | false {
322
340
  x.type == "ForInStatement" ||
323
341
  x.type == "ForOfStatement"
324
342
  );
343
+
344
+ if (
345
+ p
346
+ .slice(0, forIndex)
347
+ .find((x) =>
348
+ ["ArrowFunctionExpression", "BlockStatement"].includes(x.type)
349
+ )
350
+ ) {
351
+ return false;
352
+ }
353
+
325
354
  if (forIndex !== -1) {
326
355
  if (p[forIndex].type == "ForStatement") {
327
356
  if (p[forIndex].init == (p[forIndex - 1] || o)) {
@@ -73,3 +73,17 @@ for (var x of [3, 3, 5]) {
73
73
  sum += x;
74
74
  }
75
75
  expect(sum).toStrictEqual(11);
76
+
77
+ // Variant #12 More complex for-loop initializer
78
+ var outside = 12;
79
+ for (
80
+ var myFunction = function () {
81
+ return outside;
82
+ };
83
+ false;
84
+
85
+ ) {}
86
+
87
+ var TEST_OUTPUT = myFunction();
88
+
89
+ expect(TEST_OUTPUT).toStrictEqual(12);
@@ -0,0 +1,19 @@
1
+ import JsConfuser from "../../src/index";
2
+
3
+ // https://github.com/MichaelXF/js-confuser/issues/79
4
+ test("Variant #1: Support BigInt Literals (1n)", async () => {
5
+ var code = `
6
+ TEST_OUTPUT = 1n;
7
+ `;
8
+
9
+ var output = await JsConfuser(code, {
10
+ target: "node",
11
+ renameVariables: true,
12
+ });
13
+
14
+ var TEST_OUTPUT;
15
+ eval(output);
16
+
17
+ expect(typeof TEST_OUTPUT).toStrictEqual("bigint");
18
+ expect(TEST_OUTPUT).toStrictEqual(1n);
19
+ });
@@ -230,7 +230,19 @@ describe("debugObfuscation", () => {
230
230
  callback
231
231
  );
232
232
 
233
- expect(typeof output).toStrictEqual("string");
233
+ expect(typeof output).toStrictEqual("object");
234
+ expect(typeof output.obfuscated).toStrictEqual("string");
235
+ expect(typeof output.obfuscationTime).toStrictEqual("number");
236
+ expect(typeof output.compileTime).toStrictEqual("number");
237
+ expect(typeof output.parseTime).toStrictEqual("number");
238
+ expect(typeof output.totalPossibleTransforms).toStrictEqual("number");
239
+ expect(typeof output.totalTransforms).toStrictEqual("number");
240
+ expect(typeof output.transformationTimes).toStrictEqual("object");
241
+ expect(typeof output.transformationTimes.RenameVariables).toStrictEqual(
242
+ "number"
243
+ );
244
+
245
+ eval(output.obfuscated);
234
246
  expect(called).toStrictEqual(true);
235
247
  });
236
248
  });
@@ -0,0 +1,30 @@
1
+ import JsConfuser from "../../src/index";
2
+
3
+ // https://github.com/MichaelXF/js-confuser/issues/74
4
+ test("Variant #1: Don't break Symbols", async () => {
5
+ if (typeof Symbol !== "undefined") {
6
+ for (var i = 0; i < 6; i++) {
7
+ var output = await JsConfuser(
8
+ `
9
+
10
+ var sym1 = Symbol();
11
+
12
+ if (true) {
13
+ sym1;
14
+ sym1;
15
+ sym1;
16
+ }
17
+
18
+ TEST_OUTPUT = sym1;
19
+
20
+ `,
21
+ { target: "node", renameVariables: true }
22
+ );
23
+
24
+ var TEST_OUTPUT;
25
+
26
+ eval(output);
27
+ expect(typeof TEST_OUTPUT).toStrictEqual("symbol");
28
+ }
29
+ }
30
+ });
@@ -708,3 +708,25 @@ test("Variant #21: Don't move Import Declarations", async () => {
708
708
  "1cac63f39fd68d8c531f27b807610fb3d50f0fc3f186995767fb6316e7200a3e"
709
709
  );
710
710
  });
711
+
712
+ // https://github.com/MichaelXF/js-confuser/issues/81
713
+ test("Variant #22: Don't break typeof expression", async () => {
714
+ var output = await JsConfuser(
715
+ `
716
+ TEST_OUTPUT = false;
717
+ if(typeof nonExistentVariable === "undefined") {
718
+ TEST_OUTPUT = true;
719
+ }
720
+ `,
721
+ {
722
+ target: "node",
723
+ controlFlowFlattening: true,
724
+ }
725
+ );
726
+
727
+ var TEST_OUTPUT;
728
+
729
+ eval(output);
730
+
731
+ expect(TEST_OUTPUT).toStrictEqual(true);
732
+ });
@@ -330,3 +330,27 @@ it("should apply to every level of the code", async () => {
330
330
 
331
331
  expect(value).toStrictEqual(100);
332
332
  });
333
+
334
+ // https://github.com/MichaelXF/js-confuser/issues/77
335
+ it("should work with code that uses toString() function", async () => {
336
+ var output = await JsConfuser(
337
+ `
338
+ function myFunction(){
339
+
340
+ }
341
+
342
+ TEST_OUTPUT = toString();
343
+ `,
344
+ {
345
+ target: "node",
346
+ dispatcher: true,
347
+ }
348
+ );
349
+
350
+ var toString = () => "Correct Value";
351
+ var TEST_OUTPUT;
352
+
353
+ eval(output);
354
+
355
+ expect(TEST_OUTPUT).toStrictEqual("Correct Value");
356
+ });
@@ -392,3 +392,36 @@ it("should work with stringConcealing and hide method names", async () => {
392
392
 
393
393
  expect(TEST_VALUE).toStrictEqual(100);
394
394
  });
395
+
396
+ // https://github.com/MichaelXF/js-confuser/issues/72
397
+ it("should support class fields", async () => {
398
+ var output = await JsConfuser(
399
+ `
400
+ class MyClass {
401
+ myField = 1;
402
+ ["myComputedField"] = 2;
403
+
404
+ static myStaticField = 3;
405
+ static ["myComputedStaticField"] = 4;
406
+ }
407
+
408
+ var myObject = new MyClass();
409
+ TEST_OUTPUT_1 = myObject.myField;
410
+ TEST_OUTPUT_2 = myObject.myComputedField;
411
+ TEST_OUTPUT_3 = MyClass.myStaticField;
412
+ TEST_OUTPUT_4 = MyClass.myComputedStaticField;
413
+ `,
414
+ {
415
+ target: "node",
416
+ es5: true,
417
+ }
418
+ );
419
+
420
+ var TEST_OUTPUT_1, TEST_OUTPUT_2, TEST_OUTPUT_3, TEST_OUTPUT_4;
421
+
422
+ eval(output);
423
+ expect(TEST_OUTPUT_1).toStrictEqual(1);
424
+ expect(TEST_OUTPUT_2).toStrictEqual(2);
425
+ expect(TEST_OUTPUT_3).toStrictEqual(3);
426
+ expect(TEST_OUTPUT_4).toStrictEqual(4);
427
+ });
@@ -76,3 +76,56 @@ it("should work with Integrity also enabled", async () => {
76
76
 
77
77
  expect(value).toStrictEqual("Hello World");
78
78
  });
79
+
80
+ it("should work on async functions", async () => {
81
+ var output = await JsConfuser(
82
+ `
83
+ async function myFunction(){
84
+ return "Correct Value";
85
+ }
86
+
87
+ (async ()=>{
88
+ TEST_FUNCTION( await myFunction() );
89
+ })();
90
+ `,
91
+ { target: "node", eval: true }
92
+ );
93
+
94
+ expect(output).toContain("eval");
95
+
96
+ var wasCalled = false;
97
+
98
+ function TEST_FUNCTION(value) {
99
+ wasCalled = true;
100
+ expect(value).toStrictEqual("Correct Value");
101
+ }
102
+
103
+ eval(output);
104
+
105
+ setTimeout(() => {
106
+ expect(wasCalled).toStrictEqual(true);
107
+ }, 1000);
108
+ });
109
+
110
+ it("should work on generator functions", async () => {
111
+ var output = await JsConfuser(
112
+ `
113
+ function* myFunction(){
114
+ yield "Correct Value";
115
+ }
116
+
117
+ const gen = myFunction();
118
+
119
+ TEST_OUTPUT = gen.next().value;
120
+ `,
121
+ { target: "node", eval: true }
122
+ );
123
+
124
+ expect(output).toContain("eval");
125
+
126
+ var TEST_OUTPUT;
127
+
128
+ eval(output);
129
+
130
+ expect(TEST_OUTPUT).toStrictEqual("Correct Value");
131
+ });
@@ -446,3 +446,24 @@ it("should not apply to objects with non-init properties (method, set, get)", as
446
446
  expect(output).toContain("TEST_OBJECT");
447
447
  expect(output).toContain("set ");
448
448
  });
449
+
450
+ // https://github.com/MichaelXF/js-confuser/issues/78
451
+ it("should handle objects with spread elements", async () => {
452
+ var output = await JsConfuser(
453
+ `
454
+ var x = { firstName: "John", lastName: "Doe" }
455
+ var y = { ...x };
456
+
457
+ TEST_OUTPUT = y;
458
+ `,
459
+ {
460
+ target: "node",
461
+ objectExtraction: true,
462
+ }
463
+ );
464
+
465
+ var TEST_OUTPUT;
466
+ eval(output);
467
+
468
+ expect(TEST_OUTPUT).toStrictEqual({ firstName: "John", lastName: "Doe" });
469
+ });
@@ -4,7 +4,7 @@ it("should bring independent to the global level", async () => {
4
4
  var output = await JsConfuser.obfuscate(
5
5
  `
6
6
  function container(){
7
- function nested(){
7
+ function nested(param){
8
8
 
9
9
  }
10
10
 
@@ -17,7 +17,8 @@ it("should bring independent to the global level", async () => {
17
17
  }
18
18
  );
19
19
 
20
- expect(output).toContain("set");
20
+ // Ensure flatten was applied
21
+ expect(output).toContain("[param]");
21
22
  });
22
23
 
23
24
  it("should have correct return values", async () => {
@@ -255,7 +256,8 @@ it("should work when pattern-based assignment expressions are involved", async (
255
256
  }
256
257
  );
257
258
 
258
- expect(output).toContain("set");
259
+ // Ensure flatten was applied
260
+ expect(output).toContain("[i],[]");
259
261
 
260
262
  var value = "never_called",
261
263
  input = (x) => (value = x);
@@ -263,3 +265,144 @@ it("should work when pattern-based assignment expressions are involved", async (
263
265
  eval(output);
264
266
  expect(value).toStrictEqual(1);
265
267
  });
268
+
269
+ it("should work on async functions", async () => {
270
+ var output = await JsConfuser.obfuscate(
271
+ `
272
+ async function timeout(ms){
273
+ return await new Promise((resolve, reject)=>{
274
+ setTimeout(()=>{
275
+ resolve();
276
+ }, ms);
277
+ });
278
+ }
279
+
280
+ (async ()=>{
281
+ var startTime = Date.now();
282
+
283
+ await timeout(1000);
284
+
285
+ var endTime = Date.now();
286
+
287
+ var duration = endTime - startTime;
288
+
289
+ TEST_CALLBACK(duration);
290
+ })();
291
+ `,
292
+ {
293
+ target: "node",
294
+ flatten: true,
295
+ }
296
+ );
297
+
298
+ expect(output).toContain("_flat_timeout");
299
+
300
+ var wasCalled = false;
301
+ var TEST_CALLBACK = (time) => {
302
+ expect(time).toBeGreaterThan(500);
303
+ wasCalled = true;
304
+ };
305
+
306
+ eval(output);
307
+
308
+ setTimeout(() => {
309
+ expect(wasCalled).toStrictEqual(true);
310
+ }, 2000);
311
+ });
312
+
313
+ it("should work on Function Expressions", async () => {
314
+ var output = await JsConfuser.obfuscate(
315
+ `
316
+ var outsideVar = "Correct Value";
317
+
318
+ var myFunctionExpression = function(){
319
+ return outsideVar;
320
+ }
321
+
322
+ TEST_OUTPUT = myFunctionExpression();
323
+ `,
324
+ {
325
+ target: "node",
326
+ flatten: true,
327
+ }
328
+ );
329
+
330
+ // Ensure flatten applied
331
+ expect(output).toContain("_flat_myFunctionExpression");
332
+
333
+ var TEST_OUTPUT;
334
+ eval(output);
335
+
336
+ expect(TEST_OUTPUT).toStrictEqual("Correct Value");
337
+ });
338
+
339
+ it("should work on Properties", async () => {
340
+ var output = await JsConfuser.obfuscate(
341
+ `
342
+ var outsideVar = "Incorrect Value";
343
+
344
+ var myObject = {
345
+ myInitProperty: function(){
346
+ return outsideVar;
347
+ },
348
+
349
+ myMethodProperty(){
350
+ return;
351
+ },
352
+
353
+ get myGetProperty(){
354
+ return;
355
+ },
356
+
357
+ set mySetProperty(val){
358
+ outsideVar = val;
359
+ }
360
+ }
361
+
362
+ myObject.mySetProperty = "Correct Value";
363
+ TEST_OUTPUT = myObject.myInitProperty();
364
+ `,
365
+ {
366
+ target: "node",
367
+ flatten: true,
368
+ }
369
+ );
370
+
371
+ // Ensure flatten applied
372
+ expect(output).toContain("_flat_myInitProperty");
373
+
374
+ var TEST_OUTPUT;
375
+ eval(output);
376
+
377
+ expect(TEST_OUTPUT).toStrictEqual("Correct Value");
378
+ });
379
+
380
+ it("should work with RGF enabled", async () => {
381
+ var output = await JsConfuser.obfuscate(
382
+ `
383
+ var outsideVar = "Correct Value";
384
+
385
+ function myFunction(){
386
+ return outsideVar;
387
+ }
388
+
389
+ TEST_OUTPUT = myFunction();
390
+ `,
391
+ {
392
+ target: "node",
393
+ flatten: true,
394
+ rgf: true,
395
+ }
396
+ );
397
+
398
+ // Ensure flatten applied
399
+ expect(output).toContain("_flat_myFunction");
400
+
401
+ // Ensure RGF applied
402
+ expect(output).toContain("new Function");
403
+
404
+ var TEST_OUTPUT;
405
+ eval(output);
406
+
407
+ expect(TEST_OUTPUT).toStrictEqual("Correct Value");
408
+ });
@@ -474,3 +474,29 @@ test("Variant #19: Don't break Import Declarations", async () => {
474
474
  "1cac63f39fd68d8c531f27b807610fb3d50f0fc3f186995767fb6316e7200a3e"
475
475
  );
476
476
  });
477
+
478
+ // https://github.com/MichaelXF/js-confuser/issues/80
479
+ test("Variant #20: Don't break code with var and let variables in same scope", async () => {
480
+ var output = await JsConfuser(
481
+ `
482
+ function log(param) {
483
+ let message = param;
484
+ var isWarning = false;
485
+ var isError = false;
486
+
487
+ TEST_OUTPUT = message;
488
+ };
489
+
490
+ log("Correct Value");
491
+ `,
492
+ {
493
+ target: "node",
494
+ renameVariables: true,
495
+ }
496
+ );
497
+
498
+ var TEST_OUTPUT;
499
+ eval(output);
500
+
501
+ expect(TEST_OUTPUT).toStrictEqual("Correct Value");
502
+ });
@@ -269,6 +269,7 @@ test("Variant #15: Removing implied 'return'", async () => {
269
269
  function MyFunction(){
270
270
  var output = "Hello World";
271
271
  console.log(output);
272
+ this; // Stop arrow function conversion
272
273
  return;
273
274
  }
274
275
 
@@ -366,3 +367,68 @@ test("Variant #19: Remove unreachable code following a throw statement", async (
366
367
 
367
368
  expect(output).not.toContain("unreachableStmt");
368
369
  });
370
+
371
+ // https://github.com/MichaelXF/js-confuser/issues/76
372
+ test("Variant #20: Properly handle objects with `, ^, [, ] as keys", async () => {
373
+ var output = await JsConfuser(
374
+ `
375
+ TEST_OBJECT = {
376
+ "\`": true,
377
+ "^": true,
378
+ "]": true,
379
+ "[": true
380
+ };
381
+ `,
382
+ {
383
+ target: "node",
384
+ minify: true,
385
+ }
386
+ );
387
+
388
+ var TEST_OBJECT;
389
+ eval(output);
390
+
391
+ expect(TEST_OBJECT).toStrictEqual({
392
+ "`": true,
393
+ "^": true,
394
+ "]": true,
395
+ "[": true,
396
+ });
397
+ });
398
+
399
+ // https://github.com/MichaelXF/js-confuser/issues/75
400
+ test("Variant #21: Properly handle Object constructor (Function Declaration)", async () => {
401
+ var output = await JsConfuser(
402
+ `
403
+ function MyClass() {};
404
+
405
+ var myObject = new MyClass();
406
+
407
+ TEST_OUTPUT = myObject instanceof MyClass;
408
+ `,
409
+ { target: "node", minify: true }
410
+ );
411
+
412
+ var TEST_OUTPUT = false;
413
+ eval(output);
414
+
415
+ expect(TEST_OUTPUT).toStrictEqual(true);
416
+ });
417
+
418
+ test("Variant #22: Properly handle Object constructor (Function Expression)", async () => {
419
+ var output = await JsConfuser(
420
+ `
421
+ var MyClass = function() {};
422
+
423
+ var myObject = new MyClass();
424
+
425
+ TEST_OUTPUT = myObject instanceof MyClass;
426
+ `,
427
+ { target: "node", minify: true }
428
+ );
429
+
430
+ var TEST_OUTPUT = false;
431
+ eval(output);
432
+
433
+ expect(TEST_OUTPUT).toStrictEqual(true);
434
+ });