js-confuser 1.7.2 → 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 (96) hide show
  1. package/.github/workflows/node.js.yml +1 -1
  2. package/CHANGELOG.md +35 -0
  3. package/README.md +20 -4
  4. package/dist/constants.js +7 -2
  5. package/dist/index.js +8 -0
  6. package/dist/options.js +12 -2
  7. package/dist/templates/bufferToString.js +26 -5
  8. package/dist/templates/core.js +35 -0
  9. package/dist/templates/crash.js +8 -39
  10. package/dist/templates/es5.js +1 -1
  11. package/dist/templates/functionLength.js +1 -1
  12. package/dist/templates/globals.js +1 -1
  13. package/dist/templates/template.js +173 -68
  14. package/dist/transforms/antiTooling.js +1 -1
  15. package/dist/transforms/calculator.js +2 -2
  16. package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +8 -2
  17. package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +1 -1
  18. package/dist/transforms/deadCode.js +34 -24
  19. package/dist/transforms/dispatcher.js +8 -4
  20. package/dist/transforms/es5/antiClass.js +11 -11
  21. package/dist/transforms/es5/antiDestructuring.js +1 -1
  22. package/dist/transforms/es5/antiES6Object.js +2 -2
  23. package/dist/transforms/es5/antiTemplate.js +1 -1
  24. package/dist/transforms/extraction/duplicateLiteralsRemoval.js +2 -2
  25. package/dist/transforms/identifier/globalAnalysis.js +13 -0
  26. package/dist/transforms/identifier/globalConcealing.js +41 -6
  27. package/dist/transforms/identifier/renameVariables.js +7 -0
  28. package/dist/transforms/lock/antiDebug.js +2 -2
  29. package/dist/transforms/lock/integrity.js +9 -9
  30. package/dist/transforms/lock/lock.js +106 -20
  31. package/dist/transforms/minify.js +1 -1
  32. package/dist/transforms/opaquePredicates.js +2 -2
  33. package/dist/transforms/preparation.js +12 -0
  34. package/dist/transforms/rgf.js +32 -3
  35. package/dist/transforms/shuffle.js +3 -3
  36. package/dist/transforms/stack.js +8 -2
  37. package/dist/transforms/string/encoding.js +6 -3
  38. package/dist/transforms/string/stringCompression.js +34 -3
  39. package/dist/transforms/string/stringConcealing.js +7 -6
  40. package/dist/transforms/transform.js +26 -4
  41. package/dist/util/guard.js +5 -0
  42. package/dist/util/random.js +26 -0
  43. package/docs/Countermeasures.md +13 -6
  44. package/docs/Integrity.md +35 -28
  45. package/docs/RGF.md +6 -1
  46. package/docs/RenameVariables.md +116 -0
  47. package/docs/TamperProtection.md +100 -0
  48. package/docs/Template.md +117 -0
  49. package/package.json +1 -1
  50. package/src/constants.ts +5 -0
  51. package/src/index.ts +7 -5
  52. package/src/options.ts +47 -7
  53. package/src/templates/bufferToString.ts +34 -4
  54. package/src/templates/core.ts +29 -0
  55. package/src/templates/crash.ts +6 -38
  56. package/src/templates/es5.ts +1 -1
  57. package/src/templates/functionLength.ts +1 -1
  58. package/src/templates/globals.ts +1 -1
  59. package/src/templates/template.ts +185 -86
  60. package/src/transforms/antiTooling.ts +1 -1
  61. package/src/transforms/calculator.ts +4 -2
  62. package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +10 -3
  63. package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +1 -1
  64. package/src/transforms/deadCode.ts +74 -26
  65. package/src/transforms/dispatcher.ts +9 -5
  66. package/src/transforms/es5/antiClass.ts +15 -11
  67. package/src/transforms/es5/antiDestructuring.ts +1 -1
  68. package/src/transforms/es5/antiES6Object.ts +2 -2
  69. package/src/transforms/es5/antiTemplate.ts +1 -1
  70. package/src/transforms/extraction/duplicateLiteralsRemoval.ts +2 -6
  71. package/src/transforms/identifier/globalAnalysis.ts +18 -1
  72. package/src/transforms/identifier/globalConcealing.ts +94 -11
  73. package/src/transforms/identifier/renameVariables.ts +16 -1
  74. package/src/transforms/lock/antiDebug.ts +2 -2
  75. package/src/transforms/lock/integrity.ts +13 -11
  76. package/src/transforms/lock/lock.ts +122 -30
  77. package/src/transforms/minify.ts +1 -1
  78. package/src/transforms/opaquePredicates.ts +2 -2
  79. package/src/transforms/preparation.ts +16 -0
  80. package/src/transforms/rgf.ts +46 -8
  81. package/src/transforms/shuffle.ts +3 -3
  82. package/src/transforms/stack.ts +9 -3
  83. package/src/transforms/string/encoding.ts +10 -7
  84. package/src/transforms/string/stringCompression.ts +81 -9
  85. package/src/transforms/string/stringConcealing.ts +10 -6
  86. package/src/transforms/transform.ts +35 -47
  87. package/src/types.ts +2 -0
  88. package/src/util/guard.ts +10 -0
  89. package/src/util/random.ts +81 -1
  90. package/test/code/Cash.test.ts +84 -1
  91. package/test/compare.test.ts +5 -5
  92. package/test/options.test.ts +18 -0
  93. package/test/templates/template.test.ts +211 -1
  94. package/test/transforms/identifier/globalConcealing.test.ts +70 -0
  95. package/test/transforms/identifier/renameVariables.test.ts +75 -1
  96. package/test/transforms/lock/tamperProtection.test.ts +336 -0
@@ -4,12 +4,18 @@ import { ComputeProbabilityMap } from "../../probability";
4
4
  import Template from "../../templates/template";
5
5
  import { isDirective, isModuleSource } from "../../util/compare";
6
6
  import {
7
+ AssignmentExpression,
8
+ BinaryExpression,
7
9
  CallExpression,
10
+ ExpressionStatement,
8
11
  FunctionDeclaration,
9
12
  FunctionExpression,
10
13
  Identifier,
14
+ IfStatement,
11
15
  Literal,
12
16
  MemberExpression,
17
+ ObjectExpression,
18
+ Property,
13
19
  ReturnStatement,
14
20
  VariableDeclaration,
15
21
  VariableDeclarator,
@@ -17,6 +23,14 @@ import {
17
23
  import { append, prepend } from "../../util/insert";
18
24
  import Transform from "../transform";
19
25
  import { predictableFunctionTag } from "../../constants";
26
+ import {
27
+ chance,
28
+ choice,
29
+ getRandomFalseExpression,
30
+ getRandomInteger,
31
+ getRandomString,
32
+ splitIntoChunks,
33
+ } from "../../util/random";
20
34
 
21
35
  function LZ_encode(c) {
22
36
  ok(c);
@@ -58,7 +72,7 @@ function LZ_decode(b) {
58
72
  return g.join("");
59
73
  }
60
74
 
61
- const DecodeTemplate = Template(
75
+ const DecodeTemplate = new Template(
62
76
  `function {name}(b){
63
77
  var o,
64
78
  f,
@@ -141,15 +155,72 @@ export default class StringCompression extends Transform {
141
155
  )
142
156
  );
143
157
 
144
- append(
145
- tree,
146
- FunctionDeclaration(
147
- getStringName,
148
- [],
149
- [ReturnStatement(Literal(encoded))]
150
- )
158
+ var keys = new Set<string>();
159
+ var keysToMake = getRandomInteger(4, 14);
160
+ for (var i = 0; i < keysToMake; i++) {
161
+ keys.add(getRandomString(getRandomInteger(4, 14)));
162
+ }
163
+
164
+ var objectExpression = ObjectExpression(
165
+ Array.from(keys).map((key) => {
166
+ return Property(Literal(key), getRandomFalseExpression(), true);
167
+ })
168
+ );
169
+
170
+ // Get string function
171
+ var getStringBody = [];
172
+ var splits = splitIntoChunks(
173
+ encoded,
174
+ Math.floor(encoded.length / getRandomInteger(3, 6))
175
+ );
176
+
177
+ getStringBody.push(
178
+ VariableDeclaration(VariableDeclarator("str", Literal(splits.shift())))
179
+ );
180
+
181
+ getStringBody.push(
182
+ VariableDeclaration(VariableDeclarator("objectToTest", objectExpression))
151
183
  );
152
184
 
185
+ const addIfStatement = (testingFor, literalValueToBeAppended) => {
186
+ getStringBody.push(
187
+ IfStatement(
188
+ BinaryExpression(
189
+ "in",
190
+ Literal(testingFor),
191
+ Identifier("objectToTest")
192
+ ),
193
+ [
194
+ ExpressionStatement(
195
+ AssignmentExpression(
196
+ "+=",
197
+ Identifier("str"),
198
+ Literal(literalValueToBeAppended)
199
+ )
200
+ ),
201
+ ]
202
+ )
203
+ );
204
+ };
205
+
206
+ for (const split of splits) {
207
+ if (chance(50)) {
208
+ var fakeKey;
209
+ do {
210
+ fakeKey = getRandomString(getRandomInteger(4, 14));
211
+ } while (keys.has(fakeKey) || fakeKey in {});
212
+
213
+ addIfStatement(fakeKey, getRandomString(split.length));
214
+ }
215
+
216
+ addIfStatement(choice(Array.from(keys)), split);
217
+ }
218
+
219
+ // Return computed string
220
+ getStringBody.push(ReturnStatement(Identifier("str")));
221
+
222
+ append(tree, FunctionDeclaration(getStringName, [], getStringBody));
223
+
153
224
  append(
154
225
  tree,
155
226
  FunctionDeclaration(
@@ -176,7 +247,8 @@ export default class StringCompression extends Transform {
176
247
  object.value &&
177
248
  object.value.length > 3 &&
178
249
  !isDirective(object, parents) &&
179
- !isModuleSource(object, parents)
250
+ !isModuleSource(object, parents) &&
251
+ !parents.find((x) => x.$multiTransformSkip)
180
252
  );
181
253
  }
182
254
 
@@ -31,7 +31,10 @@ import {
31
31
  hasAllEncodings,
32
32
  } from "./encoding";
33
33
  import { ComputeProbabilityMap } from "../../probability";
34
- import { BufferToStringTemplate } from "../../templates/bufferToString";
34
+ import {
35
+ BufferToStringTemplate,
36
+ createGetGlobalTemplate,
37
+ } from "../../templates/bufferToString";
35
38
  import { criticalFunctionTag, predictableFunctionTag } from "../../constants";
36
39
 
37
40
  interface FunctionObject {
@@ -65,7 +68,7 @@ export default class StringConcealing extends Transform {
65
68
  super.apply(tree);
66
69
 
67
70
  // Pad array with useless strings
68
- var dead = getRandomInteger(5, 15);
71
+ var dead = getRandomInteger(50, 200);
69
72
  for (var i = 0; i < dead; i++) {
70
73
  var str = getRandomString(getRandomInteger(5, 40));
71
74
  var fn = this.transform(Literal(str), [tree]);
@@ -83,6 +86,7 @@ export default class StringConcealing extends Transform {
83
86
  ...BufferToStringTemplate.compile({
84
87
  name: bufferToStringName,
85
88
  getGlobalFnName: this.getPlaceholder() + predictableFunctionTag,
89
+ GetGlobalTemplate: createGetGlobalTemplate(this, tree, []),
86
90
  })
87
91
  );
88
92
 
@@ -104,7 +108,7 @@ export default class StringConcealing extends Transform {
104
108
  })
105
109
  );
106
110
  // All these are fake and never ran
107
- var ifStatements = Template(`if ( z == x ) {
111
+ var ifStatements = new Template(`if ( z == x ) {
108
112
  return y[${cacheName}[z]] = ${getterFnName}(x, y);
109
113
  }
110
114
  if ( y ) {
@@ -132,7 +136,7 @@ export default class StringConcealing extends Transform {
132
136
 
133
137
  // This one is always used
134
138
  ifStatements.push(
135
- Template(`
139
+ new Template(`
136
140
  if ( x !== y ) {
137
141
  return b[x] || (b[x] = a(${this.arrayName}[x]))
138
142
  }
@@ -141,7 +145,7 @@ export default class StringConcealing extends Transform {
141
145
 
142
146
  shuffle(ifStatements);
143
147
 
144
- var varDeclaration = Template(`
148
+ var varDeclaration = new Template(`
145
149
  var ${getterFnName} = (x, y, z, a, b)=>{
146
150
  if(typeof a === "undefined") {
147
151
  a = ${decodeFn}
@@ -173,7 +177,7 @@ export default class StringConcealing extends Transform {
173
177
  object.value.length >= 3 &&
174
178
  !isModuleSource(object, parents) &&
175
179
  !isDirective(object, parents) //&&
176
- /*!parents.find((x) => x.$dispatcherSkip)*/
180
+ /*!parents.find((x) => x.$multiTransformSkip)*/
177
181
  );
178
182
  }
179
183
 
@@ -8,11 +8,12 @@ import {
8
8
  import {
9
9
  alphabeticalGenerator,
10
10
  choice,
11
+ createZeroWidthGenerator,
11
12
  getRandomInteger,
13
+ shuffle,
12
14
  } from "../util/random";
13
15
  import { ok } from "assert";
14
16
  import Obfuscator from "../obfuscator";
15
- import { ObfuscateOptions } from "../options";
16
17
  import { ComputeProbabilityMap } from "../probability";
17
18
  import {
18
19
  placeholderVariablePrefix,
@@ -20,8 +21,9 @@ import {
20
21
  reservedKeywords,
21
22
  } from "../constants";
22
23
  import { ObfuscateOrder } from "../order";
23
- import { ITemplate } from "../templates/template";
24
24
  import { prepend } from "../util/insert";
25
+ import Lock from "./lock/lock";
26
+ import Template from "../templates/template";
25
27
 
26
28
  /**
27
29
  * Base-class for all transformations.
@@ -68,7 +70,7 @@ export default class Transform {
68
70
  /**
69
71
  * The user's options.
70
72
  */
71
- options: ObfuscateOptions;
73
+ options: Obfuscator["options"];
72
74
 
73
75
  /**
74
76
  * Only required for top-level transformations.
@@ -87,6 +89,8 @@ export default class Transform {
87
89
 
88
90
  initVariables = new Map<string, string>();
89
91
 
92
+ zeroWidthGenerator = createZeroWidthGenerator();
93
+
90
94
  constructor(obfuscator, priority: number = -1) {
91
95
  ok(obfuscator instanceof Obfuscator, "obfuscator should be an Obfuscator");
92
96
 
@@ -108,6 +112,32 @@ export default class Transform {
108
112
  );
109
113
  }
110
114
 
115
+ /**
116
+ * Gets the `Lock` transformation.
117
+ */
118
+ get lockTransform(): Lock {
119
+ var transform = this.obfuscator.transforms["Lock"] as Lock;
120
+
121
+ ok(transform, "Lock transform not created");
122
+
123
+ return transform;
124
+ }
125
+
126
+ /**
127
+ * Wraps the given name with the `__JS_CONFUSER_VAR__` function call.
128
+ *
129
+ * If `Rename Variables` is disabled, the name is returned as-is.
130
+ * @param name
131
+ * @returns
132
+ */
133
+ jsConfuserVar(name: string) {
134
+ if (!this.obfuscator.transforms["RenameVariables"]) {
135
+ return `"${name}"`;
136
+ }
137
+
138
+ return `__JS_CONFUSER_VAR__(${name})`;
139
+ }
140
+
111
141
  /**
112
142
  * Run an AST through the transformation (including `pre` and `post` transforms)
113
143
  * @param tree
@@ -286,49 +316,7 @@ export default class Transform {
286
316
  return "var_" + count;
287
317
 
288
318
  case "zeroWidth":
289
- var keyWords = [
290
- "if",
291
- "in",
292
- "for",
293
- "let",
294
- "new",
295
- "try",
296
- "var",
297
- "case",
298
- "else",
299
- "null",
300
- "break",
301
- "catch",
302
- "class",
303
- "const",
304
- "super",
305
- "throw",
306
- "while",
307
- "yield",
308
- "delete",
309
- "export",
310
- "import",
311
- "public",
312
- "return",
313
- "switch",
314
- "default",
315
- "finally",
316
- "private",
317
- "continue",
318
- "debugger",
319
- "function",
320
- "arguments",
321
- "protected",
322
- "instanceof",
323
- "function",
324
- "await",
325
- "async",
326
- ];
327
-
328
- var safe = "\u200C".repeat(count + 1);
329
-
330
- var base = choice(keyWords) + safe;
331
- return base;
319
+ return this.zeroWidthGenerator.generate();
332
320
  }
333
321
 
334
322
  throw new Error("Invalid 'identifierGenerator' mode: " + mode);
@@ -345,7 +333,7 @@ export default class Transform {
345
333
  return identifier;
346
334
  }
347
335
 
348
- createInitVariable = (value: ITemplate, parents: Node[]) => {
336
+ createInitVariable = (value: Template, parents: Node[]) => {
349
337
  var key = value.templates[0];
350
338
  if (this.initVariables.has(key)) {
351
339
  return this.initVariables.get(key);
package/src/types.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import Obfuscator from "./obfuscator";
2
2
  import { ObfuscateOptions } from "./options";
3
+ import Template from "./templates/template";
3
4
  import Transform from "./transforms/transform";
4
5
 
5
6
  /**
@@ -21,6 +22,7 @@ export interface IJsConfuser {
21
22
 
22
23
  Transform: typeof Transform;
23
24
  Obfuscator: typeof Obfuscator;
25
+ Template: typeof Template;
24
26
  }
25
27
 
26
28
  /**
package/src/util/guard.ts CHANGED
@@ -1,3 +1,4 @@
1
+ import { variableFunctionName } from "../constants";
1
2
  import { Node } from "./gen";
2
3
 
3
4
  export function isStringLiteral(node: Node) {
@@ -5,3 +6,12 @@ export function isStringLiteral(node: Node) {
5
6
  node.type === "Literal" && typeof node.value === "string" && !node.regex
6
7
  );
7
8
  }
9
+
10
+ export function isJSConfuserVar(p: Node[]) {
11
+ return p.find(
12
+ (x) =>
13
+ x.type === "CallExpression" &&
14
+ x.callee.type === "Identifier" &&
15
+ x.callee.name == variableFunctionName
16
+ );
17
+ }
@@ -63,7 +63,7 @@ export function splitIntoChunks(str: string, size: number) {
63
63
  ok(Math.floor(size) === size, "size must be integer");
64
64
 
65
65
  const numChunks = Math.ceil(str.length / size);
66
- const chunks = new Array(numChunks);
66
+ const chunks: string[] = new Array(numChunks);
67
67
 
68
68
  for (let i = 0, o = 0; i < numChunks; ++i, o += size) {
69
69
  chunks[i] = str.substr(o, size);
@@ -139,3 +139,83 @@ export function alphabeticalGenerator(index: number) {
139
139
  }
140
140
  return name;
141
141
  }
142
+
143
+ export function createZeroWidthGenerator() {
144
+ var keywords = [
145
+ "if",
146
+ "in",
147
+ "for",
148
+ "let",
149
+ "new",
150
+ "try",
151
+ "var",
152
+ "case",
153
+ "else",
154
+ "null",
155
+ "break",
156
+ "catch",
157
+ "class",
158
+ "const",
159
+ "super",
160
+ "throw",
161
+ "while",
162
+ "yield",
163
+ "delete",
164
+ "export",
165
+ "import",
166
+ "public",
167
+ "return",
168
+ "switch",
169
+ "default",
170
+ "finally",
171
+ "private",
172
+ "continue",
173
+ "debugger",
174
+ "function",
175
+ "arguments",
176
+ "protected",
177
+ "instanceof",
178
+ "await",
179
+ "async",
180
+
181
+ // new key words and other fun stuff :P
182
+ "NaN",
183
+ "undefined",
184
+ "true",
185
+ "false",
186
+ "typeof",
187
+ "this",
188
+ "static",
189
+ "void",
190
+ "of",
191
+ ];
192
+
193
+ var maxSize = 0;
194
+ var currentKeyWordsArray: string[] = [];
195
+
196
+ function generateArray() {
197
+ var result = keywords
198
+ .map(
199
+ (keyWord) =>
200
+ keyWord + "\u200C".repeat(Math.max(maxSize - keyWord.length, 1))
201
+ )
202
+ .filter((craftedVariableName) => craftedVariableName.length == maxSize);
203
+
204
+ if (!result.length) {
205
+ ++maxSize;
206
+ return generateArray();
207
+ }
208
+
209
+ return shuffle(result);
210
+ }
211
+
212
+ function getNextVariable(): string {
213
+ if (!currentKeyWordsArray.length) {
214
+ ++maxSize;
215
+ currentKeyWordsArray = generateArray();
216
+ }
217
+ return currentKeyWordsArray.pop();
218
+ }
219
+
220
+ return { generate: getNextVariable };
221
+ }
@@ -6,7 +6,7 @@ var CASH_JS = readFileSync(join(__dirname, "./Cash.src.js"), "utf-8");
6
6
 
7
7
  test("Variant #1: Cash.js on High Preset (Strict Mode)", async () => {
8
8
  var output = await JsConfuser(CASH_JS, {
9
- target: "browser",
9
+ target: "node",
10
10
  preset: "high",
11
11
  });
12
12
 
@@ -33,6 +33,9 @@ test("Variant #1: Cash.js on High Preset (Strict Mode)", async () => {
33
33
  } as any;
34
34
  window.window = window;
35
35
  global.window = window;
36
+ for (var key in window) {
37
+ global[key] = window[key];
38
+ }
36
39
 
37
40
  try {
38
41
  eval(output);
@@ -47,3 +50,83 @@ test("Variant #1: Cash.js on High Preset (Strict Mode)", async () => {
47
50
 
48
51
  expect(window).toHaveProperty("cash");
49
52
  });
53
+
54
+ test("Variant #2: Cash.js on High Preset + Integrity + Self Defending + RGF + Tamper Protection", async () => {
55
+ // Make the required document variables for initialization
56
+ var document = {
57
+ documentElement: {},
58
+ createElement: () => {
59
+ return { style: {} };
60
+ },
61
+ } as any as Document;
62
+ var window = {
63
+ document,
64
+ Array,
65
+ Object,
66
+ Symbol,
67
+ Number,
68
+ parseInt,
69
+ JSON,
70
+ setTimeout,
71
+ encodeURIComponent,
72
+ RegExp,
73
+ String,
74
+ $: false,
75
+ } as any;
76
+ window.window = window;
77
+ global.window = window;
78
+ for (var key in window) {
79
+ global[key] = window[key];
80
+ }
81
+
82
+ var output = await JsConfuser(CASH_JS, {
83
+ target: "node",
84
+ preset: "high",
85
+ rgf: true,
86
+ lock: {
87
+ integrity: true,
88
+ selfDefending: true,
89
+ tamperProtection: true,
90
+ },
91
+ });
92
+
93
+ try {
94
+ // new Function() runs in non-strict mode
95
+ new Function(output)();
96
+ } catch (e) {
97
+ var helperCode = `var document = {
98
+ documentElement: {},
99
+ createElement: () => {
100
+ return { style: {} };
101
+ },
102
+ };
103
+ var window = {
104
+ document,
105
+ Array,
106
+ Object,
107
+ Symbol,
108
+ Number,
109
+ parseInt,
110
+ JSON,
111
+ setTimeout,
112
+ encodeURIComponent,
113
+ RegExp,
114
+ String,
115
+ $: false,
116
+ };
117
+ window.window = window;
118
+ global.window = window;
119
+ for (var key in window) {
120
+ global[key] = window[key];
121
+ }`;
122
+
123
+ console.error(e);
124
+ writeFileSync("dev.output.js", helperCode + "\n" + output, {
125
+ encoding: "utf-8",
126
+ });
127
+
128
+ expect(true).toStrictEqual(false);
129
+ }
130
+
131
+ expect(window).toHaveProperty("cash");
132
+ });
@@ -46,7 +46,7 @@ describe("isIndependent", () => {
46
46
  it("various cases", () => {
47
47
  expect(
48
48
  isIndependent(
49
- Template(`({
49
+ new Template(`({
50
50
  x: 1,
51
51
  y: 2,
52
52
  z: 3,
@@ -57,7 +57,7 @@ describe("isIndependent", () => {
57
57
 
58
58
  expect(
59
59
  isIndependent(
60
- Template(`({
60
+ new Template(`({
61
61
  x: 1,
62
62
  y: 2,
63
63
  z: [3,4,5,6,7,"My String",undefined,null,NaN],
@@ -68,7 +68,7 @@ describe("isIndependent", () => {
68
68
 
69
69
  expect(
70
70
  isIndependent(
71
- Template(`({
71
+ new Template(`({
72
72
  x: 1,
73
73
  y: 2,
74
74
  z: 3,
@@ -80,7 +80,7 @@ describe("isIndependent", () => {
80
80
 
81
81
  expect(
82
82
  isIndependent(
83
- Template(`({
83
+ new Template(`({
84
84
  x: 1,
85
85
  y: 2,
86
86
  z: 3,
@@ -92,7 +92,7 @@ describe("isIndependent", () => {
92
92
 
93
93
  expect(
94
94
  isIndependent(
95
- Template(`([
95
+ new Template(`([
96
96
  {
97
97
  x: value
98
98
  }
@@ -75,6 +75,24 @@ describe("options", () => {
75
75
 
76
76
  expect(output).not.toContain("TEST_VARIABLE");
77
77
  });
78
+
79
+ test("Variant #7: Error on invalid lock option", async () => {
80
+ expect(
81
+ JsConfuser(`var TEST_VARIABLE;`, {
82
+ target: "node",
83
+ lock: "invalid",
84
+ } as any)
85
+ ).rejects.toThrow();
86
+
87
+ expect(
88
+ JsConfuser(`var TEST_VARIABLE;`, {
89
+ target: "node",
90
+ lock: {
91
+ invalidProperty: true,
92
+ },
93
+ } as any)
94
+ ).rejects.toThrow();
95
+ });
78
96
  });
79
97
 
80
98
  describe("options.preserveFunctionLength", () => {