js-confuser 1.6.0 → 1.7.1

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 (67) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/README.md +215 -172
  3. package/dist/constants.js +6 -2
  4. package/dist/obfuscator.js +0 -6
  5. package/dist/options.js +4 -4
  6. package/dist/presets.js +6 -7
  7. package/dist/templates/crash.js +2 -2
  8. package/dist/templates/functionLength.js +16 -0
  9. package/dist/transforms/dispatcher.js +10 -1
  10. package/dist/transforms/extraction/duplicateLiteralsRemoval.js +95 -59
  11. package/dist/transforms/extraction/objectExtraction.js +6 -1
  12. package/dist/transforms/flatten.js +224 -147
  13. package/dist/transforms/identifier/movedDeclarations.js +38 -85
  14. package/dist/transforms/identifier/renameVariables.js +94 -41
  15. package/dist/transforms/lock/lock.js +0 -37
  16. package/dist/transforms/minify.js +2 -2
  17. package/dist/transforms/rgf.js +145 -244
  18. package/dist/transforms/stack.js +42 -1
  19. package/dist/transforms/transform.js +1 -1
  20. package/dist/util/gen.js +2 -1
  21. package/dist/util/identifiers.js +38 -4
  22. package/dist/util/insert.js +24 -3
  23. package/docs/ControlFlowFlattening.md +595 -0
  24. package/{Countermeasures.md → docs/Countermeasures.md} +1 -15
  25. package/docs/ES5.md +197 -0
  26. package/{Integrity.md → docs/Integrity.md} +2 -2
  27. package/docs/RGF.md +419 -0
  28. package/package.json +2 -2
  29. package/src/constants.ts +3 -0
  30. package/src/obfuscator.ts +0 -4
  31. package/src/options.ts +9 -86
  32. package/src/presets.ts +6 -7
  33. package/src/templates/crash.ts +10 -10
  34. package/src/templates/functionLength.ts +14 -0
  35. package/src/transforms/dispatcher.ts +15 -1
  36. package/src/transforms/extraction/duplicateLiteralsRemoval.ts +135 -130
  37. package/src/transforms/extraction/objectExtraction.ts +4 -0
  38. package/src/transforms/flatten.ts +357 -290
  39. package/src/transforms/identifier/movedDeclarations.ts +50 -96
  40. package/src/transforms/identifier/renameVariables.ts +120 -56
  41. package/src/transforms/lock/lock.ts +1 -42
  42. package/src/transforms/minify.ts +11 -2
  43. package/src/transforms/rgf.ts +221 -402
  44. package/src/transforms/stack.ts +62 -0
  45. package/src/transforms/transform.ts +6 -2
  46. package/src/util/gen.ts +7 -2
  47. package/src/util/identifiers.ts +48 -4
  48. package/src/util/insert.ts +26 -2
  49. package/test/code/ES6.src.js +24 -0
  50. package/test/transforms/dispatcher.test.ts +27 -0
  51. package/test/transforms/extraction/duplicateLiteralsRemoval.test.ts +21 -8
  52. package/test/transforms/extraction/objectExtraction.test.ts +35 -15
  53. package/test/transforms/flatten.test.ts +352 -88
  54. package/test/transforms/identifier/globalConcealing.test.ts +23 -2
  55. package/test/transforms/identifier/movedDeclarations.test.ts +37 -9
  56. package/test/transforms/identifier/renameVariables.test.ts +37 -0
  57. package/test/transforms/lock/integrity.test.ts +24 -0
  58. package/test/transforms/lock/lock.test.ts +1 -48
  59. package/test/transforms/minify.test.ts +19 -0
  60. package/test/transforms/rgf.test.ts +262 -353
  61. package/test/transforms/stack.test.ts +52 -0
  62. package/test/util/identifiers.test.ts +134 -1
  63. package/test/util/insert.test.ts +57 -3
  64. package/src/transforms/eval.ts +0 -89
  65. package/src/transforms/identifier/nameRecycling.ts +0 -280
  66. package/test/transforms/eval.test.ts +0 -131
  67. package/test/transforms/identifier/nameRecycling.test.ts +0 -205
@@ -6,6 +6,7 @@ import { walk } from "../traverse";
6
6
  import {
7
7
  AssignmentExpression,
8
8
  BinaryExpression,
9
+ CallExpression,
9
10
  ExpressionStatement,
10
11
  Identifier,
11
12
  IfStatement,
@@ -18,6 +19,7 @@ import {
18
19
  } from "../util/gen";
19
20
  import { getIdentifierInfo } from "../util/identifiers";
20
21
  import {
22
+ computeFunctionLength,
21
23
  getBlockBody,
22
24
  getDefiningContext,
23
25
  getReferencingContexts,
@@ -28,10 +30,14 @@ import {
28
30
  } from "../util/insert";
29
31
  import { chance, choice, getRandomInteger } from "../util/random";
30
32
  import Transform from "./transform";
33
+ import { noRenameVariablePrefix } from "../constants";
34
+ import { FunctionLengthTemplate } from "../templates/functionLength";
31
35
 
32
36
  export default class Stack extends Transform {
33
37
  mangledExpressionsMade: number;
34
38
 
39
+ functionLengthName: string;
40
+
35
41
  constructor(o) {
36
42
  super(o, ObfuscateOrder.Stack);
37
43
 
@@ -111,8 +117,14 @@ export default class Stack extends Transform {
111
117
  });
112
118
 
113
119
  var startingSize = subscripts.size;
120
+ var isIllegal = false;
114
121
 
115
122
  walk(object.body, [object, ...parents], (o, p) => {
123
+ if (o.type === "Identifier" && o.name === "arguments") {
124
+ isIllegal = true;
125
+ return "EXIT";
126
+ }
127
+
116
128
  if (o.type == "Identifier") {
117
129
  var info = getIdentifierInfo(o, p);
118
130
  if (!info.spec.isReferenced || info.spec.isExported) {
@@ -128,6 +140,10 @@ export default class Stack extends Transform {
128
140
  illegal.add(o.name);
129
141
  }
130
142
 
143
+ if (o.name.startsWith(noRenameVariablePrefix)) {
144
+ illegal.add(o.name);
145
+ }
146
+
131
147
  if (
132
148
  info.isClauseParameter ||
133
149
  info.isFunctionParameter ||
@@ -200,6 +216,8 @@ export default class Stack extends Transform {
200
216
  }
201
217
  });
202
218
 
219
+ if (isIllegal) return;
220
+
203
221
  illegal.forEach((name) => {
204
222
  defined.delete(name);
205
223
  referenced.delete(name);
@@ -467,6 +485,9 @@ export default class Stack extends Transform {
467
485
  object.body.body.splice(parseInt(index) + i, 0, rotateNodes[index]);
468
486
  });
469
487
 
488
+ // Preserve function.length property
489
+ var originalFunctionLength = computeFunctionLength(object.params);
490
+
470
491
  // Set the params for this function to be the stack array
471
492
  object.params = [RestElement(Identifier(stackName))];
472
493
 
@@ -475,6 +496,47 @@ export default class Stack extends Transform {
475
496
  object.body,
476
497
  Template(`${stackName}["length"] = ${startingSize}`).single()
477
498
  );
499
+
500
+ if (originalFunctionLength !== 0) {
501
+ if (!this.functionLengthName) {
502
+ this.functionLengthName = this.getPlaceholder();
503
+ prepend(
504
+ parents[parents.length - 1] || object,
505
+ FunctionLengthTemplate.single({ name: this.functionLengthName })
506
+ );
507
+ }
508
+
509
+ if (object.type === "FunctionDeclaration") {
510
+ var body = parents[0];
511
+ if (Array.isArray(body)) {
512
+ var index = body.indexOf(object);
513
+
514
+ body.splice(
515
+ index,
516
+ 0,
517
+ ExpressionStatement(
518
+ CallExpression(Identifier(this.functionLengthName), [
519
+ Identifier(object.id.name),
520
+ Literal(originalFunctionLength),
521
+ ])
522
+ )
523
+ );
524
+ }
525
+ } else {
526
+ ok(
527
+ object.type === "FunctionExpression" ||
528
+ object.type === "ArrowFunctionExpression"
529
+ );
530
+
531
+ this.replace(
532
+ object,
533
+ CallExpression(Identifier(this.functionLengthName), [
534
+ { ...object },
535
+ Literal(originalFunctionLength),
536
+ ])
537
+ );
538
+ }
539
+ }
478
540
  };
479
541
  }
480
542
  }
@@ -9,7 +9,11 @@ import { ok } from "assert";
9
9
  import Obfuscator from "../obfuscator";
10
10
  import { ObfuscateOptions } from "../options";
11
11
  import { ComputeProbabilityMap } from "../probability";
12
- import { reservedIdentifiers, reservedKeywords } from "../constants";
12
+ import {
13
+ placeholderVariablePrefix,
14
+ reservedIdentifiers,
15
+ reservedKeywords,
16
+ } from "../constants";
13
17
  import { ObfuscateOrder } from "../order";
14
18
 
15
19
  /**
@@ -176,7 +180,7 @@ export default class Transform {
176
180
  [...Array(size)]
177
181
  .map(() => Math.floor(Math.random() * 10).toString(10))
178
182
  .join("");
179
- return "__p_" + genRanHex(10);
183
+ return placeholderVariablePrefix + genRanHex(10);
180
184
  }
181
185
 
182
186
  /**
package/src/util/gen.ts CHANGED
@@ -171,7 +171,12 @@ export function BreakStatement(label?: string) {
171
171
  };
172
172
  }
173
173
 
174
- export function Property(key: Node, value: Node, computed = false) {
174
+ export function Property(
175
+ key: Node,
176
+ value: Node,
177
+ computed = false,
178
+ kind: "init" | "set" | "get" = "init"
179
+ ) {
175
180
  if (!key) {
176
181
  throw new Error("key is undefined");
177
182
  }
@@ -183,7 +188,7 @@ export function Property(key: Node, value: Node, computed = false) {
183
188
  key: key,
184
189
  computed: computed,
185
190
  value: value,
186
- kind: "init",
191
+ kind: kind,
187
192
  method: false,
188
193
  shorthand: false,
189
194
  };
@@ -30,6 +30,23 @@ export function validateChain(object: Node, parents: Node[]) {
30
30
  }
31
31
  }
32
32
 
33
+ function objectPatternCheck(object: Node, parents: Node[]) {
34
+ var objectPatternIndex = parents.findIndex((x) => x.type === "ObjectPattern");
35
+ if (objectPatternIndex == -1) {
36
+ return true;
37
+ }
38
+
39
+ var property = parents[objectPatternIndex].properties.find(
40
+ (property) => parents[objectPatternIndex - 2] === property
41
+ );
42
+
43
+ if (property.key === (parents[objectPatternIndex - 3] || object)) {
44
+ return false;
45
+ }
46
+
47
+ return true;
48
+ }
49
+
33
50
  /**
34
51
  * Returns detailed information about the given Identifier node.
35
52
  * @param object
@@ -74,19 +91,43 @@ export function getIdentifierInfo(object: Node, parents: Node[]) {
74
91
  var isVariableDeclaration =
75
92
  varIndex != -1 &&
76
93
  parents[varIndex].id == (parents[varIndex - 1] || object) &&
77
- parents.find((x) => x.type == "VariableDeclaration");
94
+ parents.find((x) => x.type == "VariableDeclaration") &&
95
+ objectPatternCheck(object, parents);
96
+
97
+ var functionIndex = parents.findIndex((x) => isFunction(x));
98
+
99
+ // Assignment pattern check!
100
+ if (isVariableDeclaration) {
101
+ var slicedParents = parents.slice(
102
+ 0,
103
+ functionIndex != -1 ? Math.min(varIndex, functionIndex) : varIndex
104
+ );
105
+ var i = 0;
106
+ for (var parent of slicedParents) {
107
+ var childNode = slicedParents[i - 1] || object;
108
+ if (parent.type === "AssignmentPattern" && parent.right === childNode) {
109
+ isVariableDeclaration = false;
110
+ break;
111
+ }
112
+ i++;
113
+ }
114
+ }
78
115
 
79
116
  var forIndex = parents.findIndex((x) => x.type == "ForStatement");
80
117
  var isForInitializer =
81
118
  forIndex != -1 &&
82
119
  parents[forIndex].init == (parents[forIndex - 1] || object);
83
120
 
84
- var functionIndex = parents.findIndex((x) => isFunction(x));
85
-
86
121
  var isFunctionDeclaration =
87
122
  functionIndex != -1 &&
88
123
  parents[functionIndex].type == "FunctionDeclaration" &&
89
124
  parents[functionIndex].id == object;
125
+
126
+ var isNamedFunctionExpression =
127
+ functionIndex != -1 &&
128
+ parents[functionIndex].type === "FunctionExpression" &&
129
+ parents[functionIndex].id === object;
130
+
90
131
  var isAFunctionParameter = isFunctionParameter(object, parents);
91
132
 
92
133
  var isClauseParameter = false;
@@ -112,7 +153,9 @@ export function getIdentifierInfo(object: Node, parents: Node[]) {
112
153
 
113
154
  var isAssignmentLeft =
114
155
  assignmentIndex !== -1 &&
115
- parents[assignmentIndex].left === (parents[assignmentIndex - 1] || object);
156
+ parents[assignmentIndex].left ===
157
+ (parents[assignmentIndex - 1] || object) &&
158
+ objectPatternCheck(object, parents);
116
159
  var isAssignmentValue =
117
160
  assignmentIndex !== -1 &&
118
161
  parents[assignmentIndex].right === (parents[assignmentIndex - 1] || object);
@@ -272,6 +315,7 @@ export function getIdentifierInfo(object: Node, parents: Node[]) {
272
315
  isDefined:
273
316
  isVariableDeclaration ||
274
317
  isFunctionDeclaration ||
318
+ isNamedFunctionExpression ||
275
319
  isAFunctionParameter ||
276
320
  isClassDeclaration ||
277
321
  isClauseParameter ||
@@ -145,13 +145,13 @@ export function getAllDefiningContexts(o: Node, p: Node[]): Node[] {
145
145
  // Get Function
146
146
  var fn = getFunction(o, p);
147
147
 
148
- contexts.push(fn.body);
148
+ // contexts.push(fn.body);
149
149
  }
150
150
 
151
151
  if (info.isClauseParameter) {
152
152
  var catchClause = p.find((x) => x.type === "CatchClause");
153
153
  if (catchClause) {
154
- contexts.push(catchClause.body);
154
+ return [catchClause];
155
155
  }
156
156
  }
157
157
 
@@ -376,3 +376,27 @@ export function isForInitialize(
376
376
 
377
377
  return false;
378
378
  }
379
+
380
+ /**
381
+ * Computes the `function.length` property given the parameter nodes.
382
+ *
383
+ * @param params
384
+ * @returns
385
+ */
386
+ export function computeFunctionLength(params: Node[]): number {
387
+ var count = 0;
388
+
389
+ for (var parameterNode of params) {
390
+ if (
391
+ parameterNode.type === "Identifier" ||
392
+ parameterNode.type === "ObjectPattern" ||
393
+ parameterNode.type === "ArrayPattern"
394
+ ) {
395
+ count++;
396
+ } else {
397
+ break;
398
+ }
399
+ }
400
+
401
+ return count;
402
+ }
@@ -203,6 +203,30 @@ function labeledBreaksAndContinues() {
203
203
  var variant15 = labeledBreaksAndContinues();
204
204
  expect(variant15).toStrictEqual(15);
205
205
 
206
+ // Variant #16: Function.length property
207
+ var variant16 = function (
208
+ n1,
209
+ n2,
210
+ n3,
211
+ n4,
212
+ n5,
213
+ n6,
214
+ n7,
215
+ n8,
216
+ n9,
217
+ n10,
218
+ n11,
219
+ n12,
220
+ n13,
221
+ n14,
222
+ n15,
223
+ n16
224
+ ) {
225
+ var _ = true;
226
+ };
227
+
228
+ expect(variant16.length).toStrictEqual(16);
229
+
206
230
  // Set 'ranAllTest' to TRUE
207
231
  ranAllTest = true;
208
232
 
@@ -373,3 +373,30 @@ test("Variant #16: Don't change functions that use 'eval'", async () => {
373
373
 
374
374
  expect(TEST_OUTPUT).toStrictEqual(2);
375
375
  });
376
+
377
+ // https://github.com/MichaelXF/js-confuser/issues/103
378
+ test("Variant #17: Don't break default parameter, function expression", async () => {
379
+ var output = await JsConfuser(
380
+ `
381
+ var X = "Correct Value";
382
+
383
+ function printX(
384
+ getX = function () {
385
+ return X;
386
+ }
387
+ ) {
388
+ var X = "Incorrect Value";
389
+
390
+ TEST_OUTPUT = getX();
391
+ }
392
+
393
+ printX();
394
+ `,
395
+ { target: "node", dispatcher: true }
396
+ );
397
+
398
+ var TEST_OUTPUT;
399
+ eval(output);
400
+
401
+ expect(TEST_OUTPUT).toStrictEqual("Correct Value");
402
+ });
@@ -1,6 +1,6 @@
1
1
  import JsConfuser from "../../../src/index";
2
2
 
3
- it("should remove duplicate literals", async () => {
3
+ test("Variant #1: Remove duplicate literals", async () => {
4
4
  var code = `
5
5
 
6
6
  var TEST_ARRAY = [5,5];
@@ -15,7 +15,7 @@ it("should remove duplicate literals", async () => {
15
15
  expect(output).toContain("5");
16
16
  });
17
17
 
18
- it("should remove duplicate literals and execute correctly", async () => {
18
+ test("Variant #2: Remove duplicate literals and execute correctly", async () => {
19
19
  var code = `
20
20
 
21
21
  TEST_ARRAY = [5,5];
@@ -36,7 +36,7 @@ it("should remove duplicate literals and execute correctly", async () => {
36
36
  expect(TEST_ARRAY).toEqual([5, 5]);
37
37
  });
38
38
 
39
- it("should remove 'undefined' and 'null' values", async () => {
39
+ test("Variant #3: Remove 'undefined' and 'null' values", async () => {
40
40
  var code = `
41
41
 
42
42
  TEST_ARRAY = [undefined,undefined,null,null];
@@ -60,7 +60,7 @@ it("should remove 'undefined' and 'null' values", async () => {
60
60
  expect(TEST_ARRAY).toEqual([undefined, undefined, null, null]);
61
61
  });
62
62
 
63
- it("should not remove empty strings", async () => {
63
+ test("Variant #4: Do not remove empty strings", async () => {
64
64
  var code = `
65
65
 
66
66
  TEST_ARRAY = ['','','',''];
@@ -80,7 +80,7 @@ it("should not remove empty strings", async () => {
80
80
  expect(TEST_ARRAY).toEqual(["", "", "", ""]);
81
81
  });
82
82
 
83
- it("should work with NaN values", async () => {
83
+ test("Variant #5: Work with NaN values", async () => {
84
84
  var code = `
85
85
 
86
86
  TEST_ARRAY = [NaN];
@@ -98,7 +98,7 @@ it("should work with NaN values", async () => {
98
98
  expect(TEST_ARRAY[0] === TEST_ARRAY[0]).toStrictEqual(false);
99
99
  });
100
100
 
101
- it("should work on property keys", async () => {
101
+ test("Variant #6: Work on property keys", async () => {
102
102
  var code = `
103
103
  var myObject = {
104
104
  myKey: 100
@@ -124,7 +124,7 @@ it("should work on property keys", async () => {
124
124
  expect(TEST_VAR).toStrictEqual(100);
125
125
  });
126
126
 
127
- it("should work on class keys", async () => {
127
+ test("Variant #7: Work on class keys", async () => {
128
128
  var code = `
129
129
  class MyClass {
130
130
  myMethod(){
@@ -150,7 +150,7 @@ it("should work on class keys", async () => {
150
150
  expect(TEST_VAR).toStrictEqual(100);
151
151
  });
152
152
 
153
- it("should not encode constructor key", async () => {
153
+ test("Variant #8: Do not encode constructor key", async () => {
154
154
  var code = `
155
155
  class MyClass {
156
156
  constructor(){
@@ -177,3 +177,16 @@ it("should not encode constructor key", async () => {
177
177
 
178
178
  expect(TEST_VAR).toStrictEqual(100);
179
179
  });
180
+
181
+ // https://github.com/MichaelXF/js-confuser/issues/105
182
+ test("Variant #9: Undefined as variable name", async () => {
183
+ var output = await JsConfuser(
184
+ `
185
+ var undefined = 0;
186
+ var undefined = 1;
187
+ `,
188
+ { target: "node", duplicateLiteralsRemoval: true }
189
+ );
190
+
191
+ eval(output);
192
+ });
@@ -1,6 +1,6 @@
1
1
  import JsConfuser from "../../../src/index";
2
2
 
3
- it("should extract properties", async () => {
3
+ test("Variant #1: Extract properties", async () => {
4
4
  var code = `
5
5
  var TEST_OBJECT = {
6
6
  TEST_1: "Hello World",
@@ -34,7 +34,7 @@ it("should extract properties", async () => {
34
34
  eval(output);
35
35
  });
36
36
 
37
- it("should extract function properties correctly", async () => {
37
+ test("Variant #2: Extract function properties correctly", async () => {
38
38
  var code = `
39
39
  var TEST_OBJECT = {
40
40
  isBoolean: x=>typeof x === "boolean",
@@ -68,7 +68,7 @@ it("should extract function properties correctly", async () => {
68
68
  eval(output);
69
69
  });
70
70
 
71
- it("should not extract properties on with dynamically added keys", async () => {
71
+ test("Variant #3: Not extract properties on with dynamically added keys", async () => {
72
72
  var code = `
73
73
  var TEST_OBJECT = {
74
74
  first_key: 1
@@ -100,7 +100,7 @@ it("should not extract properties on with dynamically added keys", async () => {
100
100
  eval(output);
101
101
  });
102
102
 
103
- it("should not extract properties on with dynamically added keys even when in nested contexts", async () => {
103
+ test("Variant #4: Not extract properties on with dynamically added keys even when in nested contexts", async () => {
104
104
  var code = `
105
105
  var TEST_OBJECT = {
106
106
  first_key: 1
@@ -135,7 +135,7 @@ it("should not extract properties on with dynamically added keys even when in ne
135
135
  eval(output);
136
136
  });
137
137
 
138
- it("should not extract properties on objects with computed properties", async () => {
138
+ test("Variant #5: Not extract properties on objects with computed properties", async () => {
139
139
  var code = `
140
140
 
141
141
  var key = "111"
@@ -166,7 +166,7 @@ it("should not extract properties on objects with computed properties", async ()
166
166
  eval(output);
167
167
  });
168
168
 
169
- it("should not extract properties on objects with computed properties (string)", async () => {
169
+ test("Variant #6: Not extract properties on objects with computed properties (string)", async () => {
170
170
  var code = `
171
171
 
172
172
  var v = "key";
@@ -197,7 +197,7 @@ it("should not extract properties on objects with computed properties (string)",
197
197
  eval(output);
198
198
  });
199
199
 
200
- it("should not extract properties on objects when the object is referenced independently", async () => {
200
+ test("Variant #7: Not extract properties on objects when the object is referenced independently", async () => {
201
201
  var code = `
202
202
 
203
203
  var TEST_OBJECT = {
@@ -229,7 +229,7 @@ it("should not extract properties on objects when the object is referenced indep
229
229
  eval(output);
230
230
  });
231
231
 
232
- it("should not extract properties on objects when the variable gets redefined", async () => {
232
+ test("Variant #8: Not extract properties on objects when the variable gets redefined", async () => {
233
233
  var code = `
234
234
 
235
235
  var TEST_OBJECT = {
@@ -260,7 +260,7 @@ it("should not extract properties on objects when the variable gets redefined",
260
260
  eval(output);
261
261
  });
262
262
 
263
- it("should not extract properties on objects when the variable gets reassigned", async () => {
263
+ test("Variant #9: Not extract properties on objects when the variable gets reassigned", async () => {
264
264
  var code = `
265
265
 
266
266
  var TEST_OBJECT = {
@@ -292,7 +292,7 @@ it("should not extract properties on objects when the variable gets reassigned",
292
292
  eval(output);
293
293
  });
294
294
 
295
- it("should not extract properties on objects with methods referencing 'this'", async () => {
295
+ test("Variant #10: Not extract properties on objects with methods referencing 'this'", async () => {
296
296
  var code = `
297
297
 
298
298
  var TEST_OBJECT = {
@@ -325,7 +325,7 @@ it("should not extract properties on objects with methods referencing 'this'", a
325
325
  eval(output);
326
326
  });
327
327
 
328
- it("should not extract properties on objects when properties are dynamically deleted", async () => {
328
+ test("Variant #11: Not extract properties on objects when properties are dynamically deleted", async () => {
329
329
  var code = `
330
330
 
331
331
  var TEST_OBJECT = {
@@ -356,7 +356,7 @@ it("should not extract properties on objects when properties are dynamically del
356
356
  eval(output);
357
357
  });
358
358
 
359
- it("should not extract properties on objects with computed accessors", async () => {
359
+ test("Variant #12: Not extract properties on objects with computed accessors", async () => {
360
360
  var code = `
361
361
 
362
362
  var TEST_OBJECT = {
@@ -388,7 +388,7 @@ it("should not extract properties on objects with computed accessors", async ()
388
388
  eval(output);
389
389
  });
390
390
 
391
- it("should properly use custom callback to exclude certain names from being changed", async () => {
391
+ test("Variant #13: Properly use custom callback to exclude certain names from being changed", async () => {
392
392
  var code = `
393
393
 
394
394
  var TEST_OBJECT = {
@@ -424,7 +424,7 @@ it("should properly use custom callback to exclude certain names from being chan
424
424
  eval(output);
425
425
  });
426
426
 
427
- it("should not apply to objects with non-init properties (method, set, get)", async () => {
427
+ test("Variant #14: Not apply to objects with non-init properties (method, set, get)", async () => {
428
428
  var code = `
429
429
 
430
430
  var realValue = 0;
@@ -448,7 +448,7 @@ it("should not apply to objects with non-init properties (method, set, get)", as
448
448
  });
449
449
 
450
450
  // https://github.com/MichaelXF/js-confuser/issues/78
451
- it("should handle objects with spread elements", async () => {
451
+ test("Variant #15: Handle objects with spread elements", async () => {
452
452
  var output = await JsConfuser(
453
453
  `
454
454
  var x = { firstName: "John", lastName: "Doe" }
@@ -467,3 +467,23 @@ it("should handle objects with spread elements", async () => {
467
467
 
468
468
  expect(TEST_OUTPUT).toStrictEqual({ firstName: "John", lastName: "Doe" });
469
469
  });
470
+
471
+ // https://github.com/MichaelXF/js-confuser/issues/106
472
+ test("Variant #16: Handle const declarations", async () => {
473
+ var output = await JsConfuser(
474
+ `
475
+ const obj = {prop: 0};
476
+ obj.prop = 1;
477
+ TEST_OUTPUT = obj.prop;
478
+ `,
479
+ {
480
+ target: "node",
481
+ objectExtraction: true,
482
+ }
483
+ );
484
+
485
+ var TEST_OUTPUT;
486
+ eval(output);
487
+
488
+ expect(TEST_OUTPUT).toStrictEqual(1);
489
+ });