js-confuser 1.2.2 → 1.4.2

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 (78) hide show
  1. package/CHANGELOG.md +132 -0
  2. package/README.md +4 -1
  3. package/dist/parser.js +1 -2
  4. package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +482 -91
  5. package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +4 -0
  6. package/dist/transforms/controlFlowFlattening/{switchCaseObfucation.js → switchCaseObfuscation.js} +2 -2
  7. package/dist/transforms/deadCode.js +1 -1
  8. package/dist/transforms/dispatcher.js +7 -6
  9. package/dist/transforms/eval.js +1 -1
  10. package/dist/transforms/extraction/duplicateLiteralsRemoval.js +4 -2
  11. package/dist/transforms/hideInitializingCode.js +4 -1
  12. package/dist/transforms/identifier/globalConcealing.js +18 -8
  13. package/dist/transforms/identifier/variableAnalysis.js +1 -1
  14. package/dist/transforms/label.js +11 -2
  15. package/dist/transforms/lock/antiDebug.js +32 -13
  16. package/dist/transforms/lock/lock.js +3 -3
  17. package/dist/transforms/minify.js +2 -2
  18. package/dist/transforms/opaquePredicates.js +4 -2
  19. package/dist/transforms/preparation/preparation.js +8 -0
  20. package/dist/transforms/renameLabels.js +17 -3
  21. package/dist/transforms/rgf.js +8 -3
  22. package/dist/transforms/stack.js +1 -1
  23. package/dist/transforms/string/encoding.js +74 -0
  24. package/dist/transforms/string/stringCompression.js +6 -2
  25. package/dist/transforms/string/stringConcealing.js +1 -1
  26. package/dist/transforms/string/stringSplitting.js +6 -0
  27. package/dist/traverse.js +0 -34
  28. package/dist/util/gen.js +3 -1
  29. package/dist/util/identifiers.js +8 -18
  30. package/dist/util/insert.js +4 -38
  31. package/package.json +2 -2
  32. package/src/options.ts +3 -3
  33. package/src/parser.ts +1 -2
  34. package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +735 -134
  35. package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +6 -0
  36. package/src/transforms/controlFlowFlattening/{switchCaseObfucation.ts → switchCaseObfuscation.ts} +6 -2
  37. package/src/transforms/deadCode.ts +8 -0
  38. package/src/transforms/dispatcher.ts +16 -6
  39. package/src/transforms/eval.ts +2 -1
  40. package/src/transforms/extraction/duplicateLiteralsRemoval.ts +40 -5
  41. package/src/transforms/hideInitializingCode.ts +432 -425
  42. package/src/transforms/identifier/globalConcealing.ts +102 -38
  43. package/src/transforms/identifier/variableAnalysis.ts +1 -1
  44. package/src/transforms/label.ts +20 -2
  45. package/src/transforms/lock/antiDebug.ts +69 -33
  46. package/src/transforms/lock/lock.ts +4 -5
  47. package/src/transforms/minify.ts +2 -1
  48. package/src/transforms/opaquePredicates.ts +25 -3
  49. package/src/transforms/preparation/preparation.ts +8 -1
  50. package/src/transforms/renameLabels.ts +26 -3
  51. package/src/transforms/rgf.ts +6 -1
  52. package/src/transforms/stack.ts +2 -1
  53. package/src/transforms/string/encoding.ts +107 -1
  54. package/src/transforms/string/stringCompression.ts +28 -3
  55. package/src/transforms/string/stringConcealing.ts +2 -0
  56. package/src/transforms/string/stringSplitting.ts +11 -0
  57. package/src/transforms/transform.ts +1 -2
  58. package/src/traverse.ts +0 -30
  59. package/src/util/gen.ts +5 -3
  60. package/src/util/identifiers.ts +18 -19
  61. package/src/util/insert.ts +10 -76
  62. package/src/util/scope.ts +9 -9
  63. package/test/{transforms/compare.test.ts → compare.test.ts} +2 -2
  64. package/test/index.test.ts +109 -1
  65. package/test/templates/template.test.ts +14 -0
  66. package/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts +392 -10
  67. package/test/transforms/dispatcher.test.ts +30 -0
  68. package/test/transforms/eval.test.ts +28 -0
  69. package/test/transforms/flatten.test.ts +28 -0
  70. package/test/transforms/hideInitializingCode.test.ts +336 -336
  71. package/test/transforms/identifier/renameVariables.test.ts +31 -0
  72. package/test/transforms/lock/antiDebug.test.ts +43 -0
  73. package/test/transforms/renameLabels.test.ts +33 -0
  74. package/test/transforms/rgf.test.ts +29 -0
  75. package/test/transforms/string/stringSplitting.test.ts +33 -0
  76. package/test/util/identifiers.test.ts +105 -17
  77. package/dist/util/expr.js +0 -60
  78. package/src/util/expr.ts +0 -56
@@ -1,6 +1,12 @@
1
1
  import Template from "../../templates/template";
2
2
 
3
- const Encoding = {
3
+ const Encoding: {
4
+ [encoding_name: string]: {
5
+ encode: (s) => string;
6
+ decode: (s) => string;
7
+ template: ReturnType<typeof Template>;
8
+ };
9
+ } = {
4
10
  ascii85: {
5
11
  encode(a) {
6
12
  var b, c, d, e, f, g, h, i, j, k;
@@ -89,6 +95,7 @@ const Encoding = {
89
95
  }
90
96
  `),
91
97
  },
98
+
92
99
  base32: {
93
100
  encode: function (s) {
94
101
  var a = "!\"#$%&'()*+,-./0123456789:;<=>?@";
@@ -199,6 +206,105 @@ const Encoding = {
199
206
  }
200
207
  `),
201
208
  },
209
+
210
+ hexTable: {
211
+ encode: function (str) {
212
+ var output = "";
213
+
214
+ for (var j = 0; j < str.length; j += 3) {
215
+ var chunk = str.substring(j, j + 3);
216
+ if (!chunk) {
217
+ continue;
218
+ }
219
+
220
+ chunk = chunk + "~";
221
+
222
+ var uniqueChars = new Set([]);
223
+ for (var char of chunk) {
224
+ uniqueChars.add(char);
225
+ }
226
+
227
+ var keys = Array.from(uniqueChars).sort();
228
+ var table = {},
229
+ i = 0;
230
+ for (var key of keys) {
231
+ table[key] = i++;
232
+ }
233
+
234
+ var idx = [];
235
+ for (var char of chunk) {
236
+ idx.push(table[char]);
237
+ }
238
+
239
+ var table64 = "0x";
240
+ for (var i = keys.length - 1; i >= 0; i--) {
241
+ table64 += keys[i].charCodeAt(0).toString(16).toUpperCase();
242
+ }
243
+
244
+ var idxInt = 0;
245
+ for (var i = idx.length - 1; i >= 0; i--) {
246
+ idxInt = (idxInt << 3) | idx[i];
247
+ }
248
+
249
+ var idx64 = "0x" + idxInt.toString(16).toUpperCase();
250
+
251
+ // console.log(chunk, table, idx, table64, idx64);
252
+
253
+ output += table64 + "," + idx64 + ",";
254
+ }
255
+
256
+ if (output.endsWith(",")) {
257
+ output = output.substring(0, output.length - 1);
258
+ }
259
+
260
+ return "{" + output + "}";
261
+ },
262
+
263
+ decode: function (str) {
264
+ var output = "";
265
+
266
+ str = str.substring(1, str.length - 1);
267
+ var chunks = str.split(",");
268
+
269
+ for (var i = 0; i < chunks.length; i += 2) {
270
+ var arr = [chunks[i], chunks[i + 1]];
271
+
272
+ var [table, idx] = arr.map(Number);
273
+
274
+ // console.log(table, idx);
275
+ while (idx) {
276
+ output += String.fromCharCode((table >> (8 * (idx & 7))) & 0xff);
277
+ idx >>= 3;
278
+ }
279
+ }
280
+
281
+ return output.replace(/~/g, "");
282
+ },
283
+
284
+ template: Template(`
285
+ function {name}(str){
286
+ var output = "";
287
+
288
+ str = str.substring(1, str.length - 1);
289
+ var chunks = str.split(",");
290
+
291
+ for (var i = 0; i < chunks.length; i += 2) {
292
+ var arr = [chunks[i], chunks[i + 1]];
293
+
294
+ var [table, idx] = arr.map(Number);
295
+
296
+ // console.log(table, idx);
297
+ while (idx) {
298
+ output += String.fromCharCode((table >> (8 * (idx & 7))) & 0xff);
299
+ idx >>= 3;
300
+ }
301
+ }
302
+
303
+ return output.replace(/~/g, "");
304
+ }
305
+
306
+ `),
307
+ },
202
308
  };
203
309
 
204
310
  export default Encoding;
@@ -6,6 +6,7 @@ import { isDirective } from "../../util/compare";
6
6
  import {
7
7
  CallExpression,
8
8
  FunctionDeclaration,
9
+ FunctionExpression,
9
10
  Identifier,
10
11
  Literal,
11
12
  MemberExpression,
@@ -105,19 +106,43 @@ export default class StringCompression extends Transform {
105
106
 
106
107
  var split = this.getPlaceholder();
107
108
  var decoder = this.getPlaceholder();
109
+ var getStringName = this.getPlaceholder();
108
110
 
109
111
  var encoded = LZ_encode(this.string);
110
112
  if (LZ_decode(encoded) !== this.string) {
111
113
  this.error(new Error("String failed to be decoded"));
112
114
  }
113
115
 
114
- var callExpression = CallExpression(Identifier(decoder), [
115
- Literal(encoded),
116
+ var getStringParamName = this.getPlaceholder();
117
+ var decoderParamName = this.getPlaceholder();
118
+
119
+ var callExpression = CallExpression(Identifier(decoderParamName), [
120
+ CallExpression(Identifier(getStringParamName), []),
116
121
  ]);
117
122
 
118
123
  prepend(
119
124
  tree,
120
- VariableDeclaration(VariableDeclarator(split, callExpression))
125
+ VariableDeclaration(
126
+ VariableDeclarator(
127
+ split,
128
+ CallExpression(
129
+ FunctionExpression(
130
+ [Identifier(getStringParamName), Identifier(decoderParamName)],
131
+ [ReturnStatement(callExpression)]
132
+ ),
133
+ [Identifier(getStringName), Identifier(decoder)]
134
+ )
135
+ )
136
+ )
137
+ );
138
+
139
+ append(
140
+ tree,
141
+ FunctionDeclaration(
142
+ getStringName,
143
+ [],
144
+ [ReturnStatement(Literal(encoded))]
145
+ )
121
146
  );
122
147
 
123
148
  append(
@@ -106,6 +106,8 @@ export default class StringConcealing extends Transform {
106
106
  function ${getterFn}(x, y, z, a = ${decodeFn}, b = ${cacheName}){
107
107
  if ( z ) {
108
108
  return y[${cacheName}[z]] = ${getterFn}(x, y);
109
+ } else if ( y ) {
110
+ [b, y] = [a(b), x || z]
109
111
  }
110
112
 
111
113
  return y ? x[b[y]] : ${cacheName}[x] || (z=(b[x], a), ${cacheName}[x] = z(${this.arrayName}[x]))
@@ -6,6 +6,7 @@ import { ObfuscateOrder } from "../../order";
6
6
  import { isModuleSource } from "./stringConcealing";
7
7
  import { isDirective } from "../../util/compare";
8
8
  import { ok } from "assert";
9
+ import { ComputeProbabilityMap } from "../../probability";
9
10
 
10
11
  export default class StringSplitting extends Transform {
11
12
  joinPrototype: string;
@@ -71,6 +72,16 @@ export default class StringSplitting extends Transform {
71
72
  return;
72
73
  }
73
74
 
75
+ if (
76
+ !ComputeProbabilityMap(
77
+ this.options.stringSplitting,
78
+ (x) => x,
79
+ object.value
80
+ )
81
+ ) {
82
+ return;
83
+ }
84
+
74
85
  var binaryExpression;
75
86
  var parent;
76
87
  var last = chunks.pop();
@@ -1,4 +1,4 @@
1
- import traverse, { getDepth, getBlock, ExitCallback } from "../traverse";
1
+ import traverse, { ExitCallback } from "../traverse";
2
2
  import { AddComment, Node } from "../util/gen";
3
3
  import {
4
4
  alphabeticalGenerator,
@@ -6,7 +6,6 @@ import {
6
6
  getRandomInteger,
7
7
  } from "../util/random";
8
8
  import { ok } from "assert";
9
- import { isValidIdentifier } from "../util/compare";
10
9
  import Obfuscator from "../obfuscator";
11
10
  import { ObfuscateOptions } from "../options";
12
11
  import { ComputeProbabilityMap } from "../probability";
package/src/traverse.ts CHANGED
@@ -1,16 +1,6 @@
1
1
  import { Node } from "./util/gen";
2
2
  import { validateChain } from "./util/identifiers";
3
3
 
4
- /**
5
- * Returns all the scopes given parents array.
6
- * - `[object, ...parents]` is recommended.
7
- *
8
- * @param parents
9
- */
10
- export function getBlocks(parents: any[]): any[] {
11
- return parents.filter((x) => isBlock(x));
12
- }
13
-
14
4
  /**
15
5
  * A block refers to any object that has a **`.body`** property where code is nested.
16
6
  *
@@ -40,26 +30,6 @@ export function isBlock(object: any) {
40
30
  );
41
31
  }
42
32
 
43
- /**
44
- * Returns a numerical representation of the depth.
45
- * - Depth is how many blocks nested.
46
- * - Program = 1 depth
47
- * - First Fn = 2 depth
48
- * - Nested Fn = 3 depth
49
- * - Second Fn = 2 depth
50
- * - etc...
51
- * @param object
52
- * @param parents
53
- */
54
- export function getDepth(object: any, parents: any[]) {
55
- if (!Array.isArray(parents)) {
56
- throw new Error("parents should be an array");
57
- }
58
- var scopes = getBlocks([object, ...parents].filter((x) => x));
59
-
60
- return scopes.length;
61
- }
62
-
63
33
  export type EnterCallback = (
64
34
  object: Node,
65
35
  parents: Node[]
package/src/util/gen.ts CHANGED
@@ -134,7 +134,9 @@ export function ThisExpression() {
134
134
  return { type: "ThisExpression" };
135
135
  }
136
136
 
137
- export function SwitchCase(test: any, consequent: any[]) {
137
+ export function SwitchCase(test: any, consequent: Node[]) {
138
+ ok(test === null || test);
139
+ ok(Array.isArray(consequent));
138
140
  return {
139
141
  type: "SwitchCase",
140
142
  test,
@@ -142,7 +144,7 @@ export function SwitchCase(test: any, consequent: any[]) {
142
144
  };
143
145
  }
144
146
 
145
- export function SwitchDefaultCase(consequent: any[]) {
147
+ export function SwitchDefaultCase(consequent: Node[]) {
146
148
  return SwitchCase(null, consequent);
147
149
  }
148
150
 
@@ -496,7 +498,7 @@ export function AssignmentPattern(left: Node, right: Node) {
496
498
  ok(left);
497
499
  ok(right);
498
500
  return {
499
- type: "AssignmentExpression",
501
+ type: "AssignmentPattern",
500
502
  left: left,
501
503
  right: right,
502
504
  };
@@ -30,17 +30,6 @@ export function validateChain(object: Node, parents: Node[]) {
30
30
  }
31
31
  }
32
32
 
33
- export function isWithinClass(object: Node, parents: Node[]) {
34
- return (
35
- isWithin(object, parents, "ClassDeclaration") ||
36
- isWithin(object, parents, "ClassExpression")
37
- );
38
- }
39
-
40
- export function isWithin(object: Node, parents: Node[], type: string): boolean {
41
- return [object, ...parents].some((x) => x.type == type);
42
- }
43
-
44
33
  /**
45
34
  * Returns detailed information about the given Identifier node.
46
35
  * @param object
@@ -117,10 +106,16 @@ export function getIdentifierInfo(object: Node, parents: Node[]) {
117
106
 
118
107
  var isFunctionCall = parent.callee == object; // NewExpression and CallExpression
119
108
 
109
+ var assignmentIndex = parents.findIndex(
110
+ (p) => p.type === "AssignmentExpression"
111
+ );
112
+
120
113
  var isAssignmentLeft =
121
- parent.type == "AssignmentExpression" && parent.left == object;
114
+ assignmentIndex !== -1 &&
115
+ parents[assignmentIndex].left === (parents[assignmentIndex - 1] || object);
122
116
  var isAssignmentValue =
123
- parent.type == "AssignmentExpression" && parent.right == object;
117
+ assignmentIndex !== -1 &&
118
+ parents[assignmentIndex].right === (parents[assignmentIndex - 1] || object);
124
119
 
125
120
  var isUpdateExpression = parent.type == "UpdateExpression";
126
121
 
@@ -353,7 +348,7 @@ export function getDefiningIdentifier(object: Node, parents: Node[]): Location {
353
348
  }
354
349
  }
355
350
 
356
- export function isFunctionParameter(o: Node, p: Node[]) {
351
+ export function isFunctionParameter(o: Node, p: Node[], c?: Node) {
357
352
  ok(o);
358
353
  ok(p);
359
354
  validateChain(o, p);
@@ -366,7 +361,7 @@ export function isFunctionParameter(o: Node, p: Node[]) {
366
361
  return false;
367
362
  }
368
363
 
369
- var c = getVarContext(o, p);
364
+ c = c || getVarContext(o, p);
370
365
  if (c === object) {
371
366
  var pIndex = p.indexOf(object.params);
372
367
  if (pIndex == -1) {
@@ -377,8 +372,7 @@ export function isFunctionParameter(o: Node, p: Node[]) {
377
372
  var paramIndex = object.params.indexOf(param);
378
373
  ok(paramIndex !== -1);
379
374
 
380
- var sliced = p.slice(p.indexOf(paramIndex));
381
- ok(!sliced.includes(o));
375
+ var sliced = p.slice(0, pIndex);
382
376
 
383
377
  var isReferenced = true;
384
378
  var i = 0;
@@ -392,7 +386,12 @@ export function isFunctionParameter(o: Node, p: Node[]) {
392
386
  break;
393
387
  }
394
388
 
395
- if (node.type == "ObjectPattern" && node.key === down) {
389
+ if (
390
+ node.type == "Property" &&
391
+ node.key === down &&
392
+ sliced[i + 2] &&
393
+ sliced[i + 2].type == "ObjectPattern"
394
+ ) {
396
395
  isReferenced = false;
397
396
  break;
398
397
  }
@@ -420,7 +419,7 @@ export function getFunctionParameters(
420
419
 
421
420
  walk(object.params, [object, ...parents], (o, p) => {
422
421
  if (o.type == "Identifier") {
423
- if (isFunctionParameter(o, p)) {
422
+ if (isFunctionParameter(o, p, object)) {
424
423
  locations.push([o, p]);
425
424
  }
426
425
  }
@@ -1,6 +1,6 @@
1
1
  import { ok } from "assert";
2
- import { getBlock, isBlock, getBlocks } from "../traverse";
3
- import { Node, Location } from "./gen";
2
+ import { getBlock, isBlock } from "../traverse";
3
+ import { Node } from "./gen";
4
4
  import { getIdentifierInfo, validateChain } from "./identifiers";
5
5
 
6
6
  /**
@@ -125,35 +125,18 @@ export function getDefiningContext(o: Node, p: Node[]): Node {
125
125
  return getVarContext(o, p);
126
126
  }
127
127
 
128
- export function getReferencingContexts(o: Node, p: Node[]): Node[] {
128
+ export function getReferencingContexts(
129
+ o: Node,
130
+ p: Node[],
131
+ info?: ReturnType<typeof getIdentifierInfo>
132
+ ): Node[] {
129
133
  validateChain(o, p);
130
134
  ok(o.type == "Identifier");
131
135
 
132
- var info = getIdentifierInfo(o, p);
133
- ok(info.spec.isReferenced);
134
-
135
- var assignmentPatternIndex = p.findIndex(
136
- (x) => x.type == "AssignmentPattern"
137
- );
138
- if (assignmentPatternIndex != -1) {
139
- if (
140
- p[assignmentPatternIndex].right == (p[assignmentPatternIndex - 1] || o)
141
- ) {
142
- var sliced = p.slice(assignmentPatternIndex);
143
- var fnIndex = sliced.findIndex((x) => isFunction(x));
144
- var associatedFn = sliced[fnIndex];
145
- if (
146
- fnIndex !== -1 &&
147
- sliced[fnIndex].params == (sliced[fnIndex - 1] || o)
148
- ) {
149
- if (associatedFn == getVarContext(o, p)) {
150
- return isLexContext(associatedFn.body)
151
- ? [associatedFn, associatedFn.body]
152
- : [associatedFn];
153
- }
154
- }
155
- }
136
+ if (!info) {
137
+ info = getIdentifierInfo(o, p);
156
138
  }
139
+ ok(info.spec.isReferenced);
157
140
 
158
141
  return [getVarContext(o, p), getLexContext(o, p)];
159
142
  }
@@ -326,52 +309,3 @@ export function isForInitialize(o, p): "initializer" | "left-hand" | false {
326
309
 
327
310
  return false;
328
311
  }
329
-
330
- export function isInBranch(object: Node, parents: Node[], context: Node) {
331
- ok(object);
332
- ok(parents);
333
- ok(context);
334
-
335
- ok(parents.includes(context));
336
-
337
- var definingContext =
338
- parents[0].type == "FunctionDeclaration" && parents[0].id == object
339
- ? getVarContext(parents[0], parents.slice(1))
340
- : getVarContext(object, parents);
341
-
342
- var contextIndex = parents.findIndex((x) => x === context);
343
- var slicedParents = parents.slice(0, contextIndex);
344
-
345
- ok(!slicedParents.includes(object), "slicedParents includes object");
346
-
347
- var slicedTypes = new Set(slicedParents.map((x) => x.type));
348
-
349
- var isBranch = definingContext !== context;
350
- if (!isBranch) {
351
- if (
352
- [
353
- "IfStatement",
354
- "ForStatement",
355
- "ForInStatement",
356
- "ForOfStatement",
357
- "WhileStatement",
358
- "DoWhileStatement",
359
- "SwitchStatement",
360
- "ConditionalExpression",
361
- "LogicalExpression",
362
- "TryStatement",
363
- "ChainExpression",
364
- "BinaryExpression",
365
- "FunctionExpression",
366
- "FunctionDeclaration",
367
- "ArrowFunctionExpression",
368
- "ClassExpression",
369
- "ClassDeclaration",
370
- ].find((x) => slicedTypes.has(x))
371
- ) {
372
- isBranch = true;
373
- }
374
- }
375
-
376
- return isBranch;
377
- }
package/src/util/scope.ts CHANGED
@@ -1,9 +1,9 @@
1
- import { isBlock } from "../traverse";
2
-
3
- export function isLexicalScope(object) {
4
- return isBlock(object) || object.type == "SwitchCase";
5
- }
6
-
7
- export function getLexicalScope(object, parents) {
8
- return [object, ...parents].find((node) => isLexicalScope(node));
9
- }
1
+ import { isBlock } from "../traverse";
2
+
3
+ export function isLexicalScope(object) {
4
+ return isBlock(object) || object.type == "SwitchCase";
5
+ }
6
+
7
+ export function getLexicalScope(object, parents) {
8
+ return [object, ...parents].find((node) => isLexicalScope(node));
9
+ }
@@ -1,10 +1,10 @@
1
- import { isIndependent } from "../../src/util/compare";
1
+ import { isIndependent } from "../src/util/compare";
2
2
  import {
3
3
  ArrayExpression,
4
4
  FunctionExpression,
5
5
  Identifier,
6
6
  Literal,
7
- } from "../../src/util/gen";
7
+ } from "../src/util/gen";
8
8
 
9
9
  describe("isIndependent", () => {
10
10
  it("should return true for literals", () => {
@@ -1,4 +1,7 @@
1
- import JsConfuser from "../src/index";
1
+ import JsConfuser, {
2
+ debugObfuscation,
3
+ debugTransformations,
4
+ } from "../src/index";
2
5
 
3
6
  it("should be a function", async () => {
4
7
  expect(typeof JsConfuser).toBe("function");
@@ -126,3 +129,108 @@ it("should error when invalid endDate is passed in", async () => {
126
129
  return await JsConfuser("5+5", invalid);
127
130
  }).rejects.toThrow();
128
131
  });
132
+
133
+ it("should error when source code is not a string", async () => {
134
+ await expect(async () => {
135
+ return await JsConfuser({} as any, {
136
+ target: "node",
137
+ preset: "low",
138
+ });
139
+ }).rejects.toThrow();
140
+ });
141
+
142
+ it("should error when invalid source code is passed in", async () => {
143
+ await expect(async () => {
144
+ return await JsConfuser("#?!if?//for:;1(function:class{))]][]", {
145
+ target: "node",
146
+ preset: "low",
147
+ });
148
+ }).rejects.toThrow();
149
+ });
150
+
151
+ describe("obfuscateAST", () => {
152
+ test("Variant #1: Mutate AST", async () => {
153
+ var AST = {
154
+ type: "Program",
155
+ body: [
156
+ {
157
+ type: "ExpressionStatement",
158
+ expression: { type: "Literal", value: true },
159
+ },
160
+ ],
161
+ };
162
+ var before = JSON.stringify(AST);
163
+
164
+ JsConfuser.obfuscateAST(AST, { target: "node", es5: true });
165
+
166
+ var after = JSON.stringify(AST);
167
+
168
+ // Same object reference
169
+ expect(AST === AST).toStrictEqual(true);
170
+
171
+ // Different string
172
+ expect(before !== after).toStrictEqual(false);
173
+ });
174
+
175
+ test("Variant #2: Error on invalid parameters", async () => {
176
+ await expect(async () => {
177
+ return await JsConfuser.obfuscateAST("string", {
178
+ target: "node",
179
+ preset: "low",
180
+ });
181
+ }).rejects.toThrow();
182
+ });
183
+
184
+ test("Variant #3: Error on invalid AST", async () => {
185
+ await expect(async () => {
186
+ var invalidAST = {
187
+ type: "NotProgram",
188
+ };
189
+
190
+ return await JsConfuser.obfuscateAST(invalidAST, {
191
+ target: "node",
192
+ preset: "low",
193
+ });
194
+ }).rejects.toThrow();
195
+ });
196
+ });
197
+
198
+ describe("debugTransformations", () => {
199
+ test("Variant #1: Return array of objects containing `name`, `code`, and `ms` properties", async () => {
200
+ var frames = await debugTransformations(`console.log(1)`, {
201
+ target: "node",
202
+ preset: "low",
203
+ });
204
+
205
+ expect(Array.isArray(frames)).toStrictEqual(true);
206
+ expect(frames.length).toBeTruthy();
207
+
208
+ frames.forEach((frame) => {
209
+ expect(typeof frame.name).toStrictEqual("string");
210
+ expect(typeof frame.code).toStrictEqual("string");
211
+ expect(typeof frame.ms).toStrictEqual("number");
212
+ });
213
+ });
214
+ });
215
+
216
+ describe("debugObfuscation", () => {
217
+ test("Variant #1: Return array of objects containing code, ms, and name properties", async () => {
218
+ var called = false;
219
+
220
+ var callback = (name, complete, totalTransforms) => {
221
+ expect(typeof name).toStrictEqual("string");
222
+ expect(typeof complete).toStrictEqual("number");
223
+ expect(typeof totalTransforms).toStrictEqual("number");
224
+
225
+ called = true;
226
+ };
227
+ var output = await debugObfuscation(
228
+ `console.log(1)`,
229
+ { target: "node", preset: "low" },
230
+ callback
231
+ );
232
+
233
+ expect(typeof output).toStrictEqual("string");
234
+ expect(called).toStrictEqual(true);
235
+ });
236
+ });
@@ -0,0 +1,14 @@
1
+ import Template from "../../src/templates/template";
2
+
3
+ describe("Template", () => {
4
+ test("Variant #1: Error when invalid code passed in", () => {
5
+ var _consoleError = console.error;
6
+ console.error = null;
7
+
8
+ expect(() => {
9
+ Template(`#&!#Ylet{}class)--1]?|:!@#`).compile();
10
+ }).toThrow();
11
+
12
+ console.error = _consoleError;
13
+ });
14
+ });