js-confuser 2.0.0-alpha.5 → 2.0.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.
- package/.github/ISSUE_TEMPLATE/bug_report.md +43 -43
- package/.github/ISSUE_TEMPLATE/feature_request.md +20 -20
- package/.github/workflows/node.js.yml +28 -28
- package/.prettierrc +4 -4
- package/CHANGELOG.md +1015 -989
- package/CODE_OF_CONDUCT.md +131 -131
- package/CONTRIBUTING.md +52 -52
- package/LICENSE +21 -21
- package/Migration.md +72 -71
- package/README.md +86 -78
- package/dist/constants.js +43 -43
- package/dist/index.js +14 -23
- package/dist/obfuscator.js +31 -25
- package/dist/order.js +4 -4
- package/dist/presets.js +31 -31
- package/dist/templates/integrityTemplate.js +4 -4
- package/dist/templates/template.js +1 -2
- package/dist/transforms/astScrambler.js +1 -2
- package/dist/transforms/calculator.js +1 -2
- package/dist/transforms/controlFlowFlattening.js +93 -63
- package/dist/transforms/deadCode.js +1 -2
- package/dist/transforms/dispatcher.js +4 -5
- package/dist/transforms/extraction/duplicateLiteralsRemoval.js +1 -2
- package/dist/transforms/extraction/objectExtraction.js +1 -2
- package/dist/transforms/finalizer.js +1 -2
- package/dist/transforms/flatten.js +1 -2
- package/dist/transforms/identifier/globalConcealing.js +15 -2
- package/dist/transforms/identifier/movedDeclarations.js +8 -7
- package/dist/transforms/identifier/renameVariables.js +7 -7
- package/dist/transforms/lock/integrity.js +11 -10
- package/dist/transforms/lock/lock.js +2 -3
- package/dist/transforms/minify.js +11 -29
- package/dist/transforms/opaquePredicates.js +1 -2
- package/dist/transforms/pack.js +5 -2
- package/dist/transforms/plugin.js +18 -19
- package/dist/transforms/preparation.js +16 -16
- package/dist/transforms/renameLabels.js +1 -2
- package/dist/transforms/rgf.js +8 -9
- package/dist/transforms/shuffle.js +1 -2
- package/dist/transforms/string/encoding.js +1 -2
- package/dist/transforms/string/stringCompression.js +3 -4
- package/dist/transforms/string/stringConcealing.js +8 -3
- package/dist/transforms/string/stringEncoding.js +1 -2
- package/dist/transforms/variableMasking.js +1 -2
- package/dist/utils/NameGen.js +2 -2
- package/dist/utils/PredicateGen.js +1 -2
- package/dist/utils/ast-utils.js +87 -88
- package/dist/utils/function-utils.js +8 -8
- package/dist/utils/node.js +5 -6
- package/dist/utils/object-utils.js +4 -4
- package/dist/utils/random-utils.js +20 -20
- package/dist/utils/static-utils.js +1 -2
- package/dist/validateOptions.js +4 -7
- package/index.d.ts +17 -17
- package/package.json +61 -59
- package/src/constants.ts +168 -168
- package/src/index.ts +118 -118
- package/src/obfuscationResult.ts +49 -49
- package/src/obfuscator.ts +501 -497
- package/src/options.ts +407 -407
- package/src/order.ts +54 -54
- package/src/presets.ts +125 -125
- package/src/templates/bufferToStringTemplate.ts +57 -57
- package/src/templates/deadCodeTemplates.ts +1185 -1185
- package/src/templates/getGlobalTemplate.ts +76 -76
- package/src/templates/integrityTemplate.ts +64 -64
- package/src/templates/setFunctionLengthTemplate.ts +11 -11
- package/src/templates/stringCompressionTemplate.ts +20 -20
- package/src/templates/tamperProtectionTemplates.ts +120 -120
- package/src/templates/template.ts +224 -224
- package/src/transforms/astScrambler.ts +99 -99
- package/src/transforms/calculator.ts +99 -99
- package/src/transforms/controlFlowFlattening.ts +1716 -1664
- package/src/transforms/deadCode.ts +82 -82
- package/src/transforms/dispatcher.ts +450 -450
- package/src/transforms/extraction/duplicateLiteralsRemoval.ts +156 -158
- package/src/transforms/extraction/objectExtraction.ts +186 -186
- package/src/transforms/finalizer.ts +74 -74
- package/src/transforms/flatten.ts +421 -420
- package/src/transforms/identifier/globalConcealing.ts +315 -295
- package/src/transforms/identifier/movedDeclarations.ts +252 -251
- package/src/transforms/identifier/renameVariables.ts +328 -321
- package/src/transforms/lock/integrity.ts +117 -114
- package/src/transforms/lock/lock.ts +418 -425
- package/src/transforms/minify.ts +615 -629
- package/src/transforms/opaquePredicates.ts +100 -100
- package/src/transforms/pack.ts +239 -231
- package/src/transforms/plugin.ts +173 -173
- package/src/transforms/preparation.ts +349 -347
- package/src/transforms/renameLabels.ts +175 -175
- package/src/transforms/rgf.ts +322 -322
- package/src/transforms/shuffle.ts +82 -82
- package/src/transforms/string/encoding.ts +144 -144
- package/src/transforms/string/stringCompression.ts +128 -128
- package/src/transforms/string/stringConcealing.ts +312 -298
- package/src/transforms/string/stringEncoding.ts +80 -80
- package/src/transforms/string/stringSplitting.ts +77 -77
- package/src/transforms/variableMasking.ts +257 -257
- package/src/utils/IntGen.ts +33 -33
- package/src/utils/NameGen.ts +116 -116
- package/src/utils/PredicateGen.ts +61 -61
- package/src/utils/ast-utils.ts +663 -663
- package/src/utils/function-utils.ts +50 -50
- package/src/utils/gen-utils.ts +48 -48
- package/src/utils/node.ts +78 -78
- package/src/utils/object-utils.ts +21 -21
- package/src/utils/random-utils.ts +93 -93
- package/src/utils/static-utils.ts +66 -66
- package/src/validateOptions.ts +256 -259
- package/tsconfig.json +13 -14
- package/dist/probability.js +0 -1
- package/dist/transforms/functionOutlining.js +0 -230
- package/dist/utils/ControlObject.js +0 -125
|
@@ -1,347 +1,349 @@
|
|
|
1
|
-
import { NodePath } from "@babel/traverse";
|
|
2
|
-
import { PluginArg, PluginObject } from "./plugin";
|
|
3
|
-
import * as t from "@babel/types";
|
|
4
|
-
import { Order } from "../order";
|
|
5
|
-
import {
|
|
6
|
-
NodeSymbol,
|
|
7
|
-
PREDICTABLE,
|
|
8
|
-
UNSAFE,
|
|
9
|
-
variableFunctionName,
|
|
10
|
-
} from "../constants";
|
|
11
|
-
import { ok } from "assert";
|
|
12
|
-
import {
|
|
13
|
-
getParentFunctionOrProgram,
|
|
14
|
-
getPatternIdentifierNames,
|
|
15
|
-
isVariableIdentifier,
|
|
16
|
-
} from "../utils/ast-utils";
|
|
17
|
-
import { isVariableFunctionIdentifier } from "../utils/function-utils";
|
|
18
|
-
import Template from "../templates/template";
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* Preparation arranges the user's code into an AST the obfuscator can easily transform.
|
|
22
|
-
*
|
|
23
|
-
* ExplicitIdentifiers
|
|
24
|
-
* - `object.IDENTIFIER` -> `object['IDENTIFIER']` // Now String Concealing can apply on it
|
|
25
|
-
* - `{ IDENTIFIER: ... }` -> `{ "IDENTIFIER": ... }`
|
|
26
|
-
*
|
|
27
|
-
* ExplicitDeclarations
|
|
28
|
-
* - `var a,b,c` -> `var a; var b; var c;` // Now Stack can apply on it
|
|
29
|
-
*
|
|
30
|
-
* Block
|
|
31
|
-
* - `x => x * 2` -> `x => { return x * 2 }` // Change into Block Statements
|
|
32
|
-
* - `if(true) return` -> `if (true) { return }`
|
|
33
|
-
* - `while(a) a--;` -> `while(a) { a-- }`
|
|
34
|
-
*/
|
|
35
|
-
export default ({ Plugin }: PluginArg): PluginObject => {
|
|
36
|
-
const me = Plugin(Order.Preparation);
|
|
37
|
-
|
|
38
|
-
const markFunctionUnsafe = (path: NodePath<t.Node>) => {
|
|
39
|
-
const functionPath = path.findParent(
|
|
40
|
-
(path) => path.isFunction() || path.isProgram()
|
|
41
|
-
);
|
|
42
|
-
if (!functionPath) return;
|
|
43
|
-
|
|
44
|
-
const functionNode = functionPath.node;
|
|
45
|
-
|
|
46
|
-
(functionNode as NodeSymbol)[UNSAFE] = true;
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
return {
|
|
50
|
-
visitor: {
|
|
51
|
-
"ThisExpression|Super": {
|
|
52
|
-
exit(path) {
|
|
53
|
-
markFunctionUnsafe(path);
|
|
54
|
-
},
|
|
55
|
-
},
|
|
56
|
-
|
|
57
|
-
// @js-confuser-var "myVar" -> __JS_CONFUSER_VAR__(myVar)
|
|
58
|
-
StringLiteral: {
|
|
59
|
-
exit(path) {
|
|
60
|
-
// Check for @js-confuser-var comment
|
|
61
|
-
if (
|
|
62
|
-
path.node.leadingComments?.find((comment) =>
|
|
63
|
-
comment.value.includes("@js-confuser-var")
|
|
64
|
-
)
|
|
65
|
-
) {
|
|
66
|
-
var identifierName = path.node.value;
|
|
67
|
-
ok(
|
|
68
|
-
t.isValidIdentifier(identifierName),
|
|
69
|
-
"Invalid identifier name: " + identifierName
|
|
70
|
-
);
|
|
71
|
-
|
|
72
|
-
// Create a new __JS_CONFUSER_VAR__ call with the identifier
|
|
73
|
-
var newExpression = new Template(
|
|
74
|
-
`__JS_CONFUSER_VAR__({identifier})`
|
|
75
|
-
).expression({
|
|
76
|
-
identifier: t.identifier(identifierName),
|
|
77
|
-
});
|
|
78
|
-
|
|
79
|
-
path.replaceWith(newExpression);
|
|
80
|
-
|
|
81
|
-
// Remove comment and skip further processing
|
|
82
|
-
path.node.leadingComments = [];
|
|
83
|
-
path.skip();
|
|
84
|
-
}
|
|
85
|
-
},
|
|
86
|
-
},
|
|
87
|
-
|
|
88
|
-
// `Hello ${username}` -> "Hello " + username
|
|
89
|
-
TemplateLiteral: {
|
|
90
|
-
exit(path) {
|
|
91
|
-
// Check if this is a tagged template literal, if yes, skip it
|
|
92
|
-
if (t.isTaggedTemplateExpression(path.parent)) {
|
|
93
|
-
return;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const { quasis, expressions } = path.node;
|
|
97
|
-
|
|
98
|
-
// Start with the first quasi (template string part)
|
|
99
|
-
let binaryExpression: t.Expression = t.stringLiteral(
|
|
100
|
-
quasis[0].value.cooked
|
|
101
|
-
);
|
|
102
|
-
|
|
103
|
-
// Loop over the remaining quasis and expressions, concatenating them
|
|
104
|
-
for (let i = 0; i < expressions.length; i++) {
|
|
105
|
-
// Add the expression as part of the binary concatenation
|
|
106
|
-
binaryExpression = t.binaryExpression(
|
|
107
|
-
"+",
|
|
108
|
-
binaryExpression,
|
|
109
|
-
expressions[i] as t.Expression
|
|
110
|
-
);
|
|
111
|
-
|
|
112
|
-
// Add the next quasi (template string part)
|
|
113
|
-
if (quasis[i + 1].value.cooked !== "") {
|
|
114
|
-
binaryExpression = t.binaryExpression(
|
|
115
|
-
"+",
|
|
116
|
-
binaryExpression,
|
|
117
|
-
t.stringLiteral(quasis[i + 1].value.cooked)
|
|
118
|
-
);
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// Replace the template literal with the constructed binary expression
|
|
123
|
-
path.replaceWith(binaryExpression);
|
|
124
|
-
},
|
|
125
|
-
},
|
|
126
|
-
|
|
127
|
-
// /Hello World/g -> new RegExp("Hello World", "g")
|
|
128
|
-
RegExpLiteral: {
|
|
129
|
-
exit(path) {
|
|
130
|
-
const { pattern, flags } = path.node;
|
|
131
|
-
|
|
132
|
-
// Create a new RegExp() expression using the pattern and flags
|
|
133
|
-
const newRegExpCall = t.newExpression(
|
|
134
|
-
t.identifier("RegExp"), // Identifier for RegExp constructor
|
|
135
|
-
[
|
|
136
|
-
t.stringLiteral(pattern), // First argument: the pattern (no extra escaping needed)
|
|
137
|
-
flags ? t.stringLiteral(flags) : t.stringLiteral(""), // Second argument: the flags (if any)
|
|
138
|
-
]
|
|
139
|
-
);
|
|
140
|
-
|
|
141
|
-
// Replace the literal regex with the new RegExp() call
|
|
142
|
-
path.replaceWith(newRegExpCall);
|
|
143
|
-
},
|
|
144
|
-
},
|
|
145
|
-
|
|
146
|
-
ReferencedIdentifier: {
|
|
147
|
-
exit(path) {
|
|
148
|
-
const { name } = path.node;
|
|
149
|
-
if (["arguments", "eval"].includes(name)) {
|
|
150
|
-
markFunctionUnsafe(path);
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
// When Rename Variables is disabled, __JS_CONFUSER_VAR__ must still be removed
|
|
154
|
-
if (
|
|
155
|
-
!me.obfuscator.hasPlugin(Order.RenameVariables) &&
|
|
156
|
-
isVariableFunctionIdentifier(path)
|
|
157
|
-
) {
|
|
158
|
-
ok(
|
|
159
|
-
path.parentPath.isCallExpression(),
|
|
160
|
-
variableFunctionName + " must be directly called"
|
|
161
|
-
);
|
|
162
|
-
|
|
163
|
-
var argument = path.parentPath.node.arguments[0];
|
|
164
|
-
t.assertIdentifier(argument);
|
|
165
|
-
|
|
166
|
-
// Remove the variableFunctionName call
|
|
167
|
-
path.parentPath.replaceWith(t.stringLiteral(argument.name));
|
|
168
|
-
}
|
|
169
|
-
},
|
|
170
|
-
},
|
|
171
|
-
|
|
172
|
-
FunctionDeclaration: {
|
|
173
|
-
exit(path) {
|
|
174
|
-
// A function is 'predictable' if the parameter lengths are guaranteed to be known
|
|
175
|
-
// a(true) -> predictable
|
|
176
|
-
// (a || b)(true) -> unpredictable (Must be directly in a Call Expression)
|
|
177
|
-
// a(...args) -> unpredictable (Cannot use SpreadElement)
|
|
178
|
-
|
|
179
|
-
const { name } = path.node.id;
|
|
180
|
-
|
|
181
|
-
var binding = path.scope.getBinding(name);
|
|
182
|
-
var predictable = true;
|
|
183
|
-
var maxArgLength = 0;
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
if (
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
path.node.
|
|
249
|
-
|
|
250
|
-
path.
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
)
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
functionOrProgram
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
path.node.alternate
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
//
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
| t.
|
|
336
|
-
| t.
|
|
337
|
-
| t.
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
}
|
|
1
|
+
import { NodePath } from "@babel/traverse";
|
|
2
|
+
import { PluginArg, PluginObject } from "./plugin";
|
|
3
|
+
import * as t from "@babel/types";
|
|
4
|
+
import { Order } from "../order";
|
|
5
|
+
import {
|
|
6
|
+
NodeSymbol,
|
|
7
|
+
PREDICTABLE,
|
|
8
|
+
UNSAFE,
|
|
9
|
+
variableFunctionName,
|
|
10
|
+
} from "../constants";
|
|
11
|
+
import { ok } from "assert";
|
|
12
|
+
import {
|
|
13
|
+
getParentFunctionOrProgram,
|
|
14
|
+
getPatternIdentifierNames,
|
|
15
|
+
isVariableIdentifier,
|
|
16
|
+
} from "../utils/ast-utils";
|
|
17
|
+
import { isVariableFunctionIdentifier } from "../utils/function-utils";
|
|
18
|
+
import Template from "../templates/template";
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Preparation arranges the user's code into an AST the obfuscator can easily transform.
|
|
22
|
+
*
|
|
23
|
+
* ExplicitIdentifiers
|
|
24
|
+
* - `object.IDENTIFIER` -> `object['IDENTIFIER']` // Now String Concealing can apply on it
|
|
25
|
+
* - `{ IDENTIFIER: ... }` -> `{ "IDENTIFIER": ... }`
|
|
26
|
+
*
|
|
27
|
+
* ExplicitDeclarations
|
|
28
|
+
* - `var a,b,c` -> `var a; var b; var c;` // Now Stack can apply on it
|
|
29
|
+
*
|
|
30
|
+
* Block
|
|
31
|
+
* - `x => x * 2` -> `x => { return x * 2 }` // Change into Block Statements
|
|
32
|
+
* - `if(true) return` -> `if (true) { return }`
|
|
33
|
+
* - `while(a) a--;` -> `while(a) { a-- }`
|
|
34
|
+
*/
|
|
35
|
+
export default ({ Plugin }: PluginArg): PluginObject => {
|
|
36
|
+
const me = Plugin(Order.Preparation);
|
|
37
|
+
|
|
38
|
+
const markFunctionUnsafe = (path: NodePath<t.Node>) => {
|
|
39
|
+
const functionPath = path.findParent(
|
|
40
|
+
(path) => path.isFunction() || path.isProgram()
|
|
41
|
+
);
|
|
42
|
+
if (!functionPath) return;
|
|
43
|
+
|
|
44
|
+
const functionNode = functionPath.node;
|
|
45
|
+
|
|
46
|
+
(functionNode as NodeSymbol)[UNSAFE] = true;
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
visitor: {
|
|
51
|
+
"ThisExpression|Super": {
|
|
52
|
+
exit(path) {
|
|
53
|
+
markFunctionUnsafe(path);
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
// @js-confuser-var "myVar" -> __JS_CONFUSER_VAR__(myVar)
|
|
58
|
+
StringLiteral: {
|
|
59
|
+
exit(path) {
|
|
60
|
+
// Check for @js-confuser-var comment
|
|
61
|
+
if (
|
|
62
|
+
path.node.leadingComments?.find((comment) =>
|
|
63
|
+
comment.value.includes("@js-confuser-var")
|
|
64
|
+
)
|
|
65
|
+
) {
|
|
66
|
+
var identifierName = path.node.value;
|
|
67
|
+
ok(
|
|
68
|
+
t.isValidIdentifier(identifierName),
|
|
69
|
+
"Invalid identifier name: " + identifierName
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
// Create a new __JS_CONFUSER_VAR__ call with the identifier
|
|
73
|
+
var newExpression = new Template(
|
|
74
|
+
`__JS_CONFUSER_VAR__({identifier})`
|
|
75
|
+
).expression({
|
|
76
|
+
identifier: t.identifier(identifierName),
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
path.replaceWith(newExpression);
|
|
80
|
+
|
|
81
|
+
// Remove comment and skip further processing
|
|
82
|
+
path.node.leadingComments = [];
|
|
83
|
+
path.skip();
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
},
|
|
87
|
+
|
|
88
|
+
// `Hello ${username}` -> "Hello " + username
|
|
89
|
+
TemplateLiteral: {
|
|
90
|
+
exit(path) {
|
|
91
|
+
// Check if this is a tagged template literal, if yes, skip it
|
|
92
|
+
if (t.isTaggedTemplateExpression(path.parent)) {
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const { quasis, expressions } = path.node;
|
|
97
|
+
|
|
98
|
+
// Start with the first quasi (template string part)
|
|
99
|
+
let binaryExpression: t.Expression = t.stringLiteral(
|
|
100
|
+
quasis[0].value.cooked
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
// Loop over the remaining quasis and expressions, concatenating them
|
|
104
|
+
for (let i = 0; i < expressions.length; i++) {
|
|
105
|
+
// Add the expression as part of the binary concatenation
|
|
106
|
+
binaryExpression = t.binaryExpression(
|
|
107
|
+
"+",
|
|
108
|
+
binaryExpression,
|
|
109
|
+
expressions[i] as t.Expression
|
|
110
|
+
);
|
|
111
|
+
|
|
112
|
+
// Add the next quasi (template string part)
|
|
113
|
+
if (quasis[i + 1].value.cooked !== "") {
|
|
114
|
+
binaryExpression = t.binaryExpression(
|
|
115
|
+
"+",
|
|
116
|
+
binaryExpression,
|
|
117
|
+
t.stringLiteral(quasis[i + 1].value.cooked)
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Replace the template literal with the constructed binary expression
|
|
123
|
+
path.replaceWith(binaryExpression);
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
|
|
127
|
+
// /Hello World/g -> new RegExp("Hello World", "g")
|
|
128
|
+
RegExpLiteral: {
|
|
129
|
+
exit(path) {
|
|
130
|
+
const { pattern, flags } = path.node;
|
|
131
|
+
|
|
132
|
+
// Create a new RegExp() expression using the pattern and flags
|
|
133
|
+
const newRegExpCall = t.newExpression(
|
|
134
|
+
t.identifier("RegExp"), // Identifier for RegExp constructor
|
|
135
|
+
[
|
|
136
|
+
t.stringLiteral(pattern), // First argument: the pattern (no extra escaping needed)
|
|
137
|
+
flags ? t.stringLiteral(flags) : t.stringLiteral(""), // Second argument: the flags (if any)
|
|
138
|
+
]
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
// Replace the literal regex with the new RegExp() call
|
|
142
|
+
path.replaceWith(newRegExpCall);
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
|
|
146
|
+
ReferencedIdentifier: {
|
|
147
|
+
exit(path) {
|
|
148
|
+
const { name } = path.node;
|
|
149
|
+
if (["arguments", "eval"].includes(name)) {
|
|
150
|
+
markFunctionUnsafe(path);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// When Rename Variables is disabled, __JS_CONFUSER_VAR__ must still be removed
|
|
154
|
+
if (
|
|
155
|
+
!me.obfuscator.hasPlugin(Order.RenameVariables) &&
|
|
156
|
+
isVariableFunctionIdentifier(path)
|
|
157
|
+
) {
|
|
158
|
+
ok(
|
|
159
|
+
path.parentPath.isCallExpression(),
|
|
160
|
+
variableFunctionName + " must be directly called"
|
|
161
|
+
);
|
|
162
|
+
|
|
163
|
+
var argument = path.parentPath.node.arguments[0];
|
|
164
|
+
t.assertIdentifier(argument);
|
|
165
|
+
|
|
166
|
+
// Remove the variableFunctionName call
|
|
167
|
+
path.parentPath.replaceWith(t.stringLiteral(argument.name));
|
|
168
|
+
}
|
|
169
|
+
},
|
|
170
|
+
},
|
|
171
|
+
|
|
172
|
+
FunctionDeclaration: {
|
|
173
|
+
exit(path) {
|
|
174
|
+
// A function is 'predictable' if the parameter lengths are guaranteed to be known
|
|
175
|
+
// a(true) -> predictable
|
|
176
|
+
// (a || b)(true) -> unpredictable (Must be directly in a Call Expression)
|
|
177
|
+
// a(...args) -> unpredictable (Cannot use SpreadElement)
|
|
178
|
+
|
|
179
|
+
const { name } = path.node.id;
|
|
180
|
+
|
|
181
|
+
var binding = path.scope.getBinding(name);
|
|
182
|
+
var predictable = true;
|
|
183
|
+
var maxArgLength = 0;
|
|
184
|
+
|
|
185
|
+
if (!binding) return;
|
|
186
|
+
|
|
187
|
+
for (var referencePath of binding.referencePaths) {
|
|
188
|
+
if (!referencePath.parentPath.isCallExpression()) {
|
|
189
|
+
predictable = false;
|
|
190
|
+
break;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
var argsPath = referencePath.parentPath.get("arguments");
|
|
194
|
+
for (var arg of argsPath) {
|
|
195
|
+
if (arg.isSpreadElement()) {
|
|
196
|
+
predictable = false;
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
if (argsPath.length > maxArgLength) {
|
|
202
|
+
maxArgLength = argsPath.length;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
var definedArgLength = path.get("params").length;
|
|
207
|
+
if (predictable && definedArgLength >= maxArgLength) {
|
|
208
|
+
(path.node as NodeSymbol)[PREDICTABLE] = true;
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
|
|
213
|
+
// console.log() -> console["log"]();
|
|
214
|
+
MemberExpression: {
|
|
215
|
+
exit(path) {
|
|
216
|
+
if (!path.node.computed && path.node.property.type === "Identifier") {
|
|
217
|
+
path.node.property = t.stringLiteral(path.node.property.name);
|
|
218
|
+
path.node.computed = true;
|
|
219
|
+
}
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
|
|
223
|
+
// { key: true } -> { "key": true }
|
|
224
|
+
"Property|Method": {
|
|
225
|
+
exit(_path) {
|
|
226
|
+
let path = _path as NodePath<t.Property | t.Method>;
|
|
227
|
+
|
|
228
|
+
if (t.isClassPrivateProperty(path.node)) return;
|
|
229
|
+
|
|
230
|
+
if (!path.node.computed && path.node.key.type === "Identifier") {
|
|
231
|
+
// Don't change constructor key
|
|
232
|
+
if (t.isClassMethod(path.node) && path.node.kind === "constructor")
|
|
233
|
+
return;
|
|
234
|
+
|
|
235
|
+
path.node.key = t.stringLiteral(path.node.key.name);
|
|
236
|
+
path.node.computed = true;
|
|
237
|
+
}
|
|
238
|
+
},
|
|
239
|
+
},
|
|
240
|
+
|
|
241
|
+
// var a,b,c -> var a; var b; var c;
|
|
242
|
+
VariableDeclaration: {
|
|
243
|
+
exit(path) {
|
|
244
|
+
if (path.node.declarations.length > 1) {
|
|
245
|
+
// E.g. for (var i = 0, j = 1;;)
|
|
246
|
+
if (path.key === "init" && path.parentPath.isForStatement()) {
|
|
247
|
+
if (
|
|
248
|
+
!path.parentPath.node.test &&
|
|
249
|
+
!path.parentPath.node.update &&
|
|
250
|
+
path.node.kind === "var"
|
|
251
|
+
) {
|
|
252
|
+
path.parentPath.insertBefore(
|
|
253
|
+
path.node.declarations.map((declaration) =>
|
|
254
|
+
t.variableDeclaration(path.node.kind, [declaration])
|
|
255
|
+
)
|
|
256
|
+
);
|
|
257
|
+
path.remove();
|
|
258
|
+
}
|
|
259
|
+
} else {
|
|
260
|
+
if (path.parentPath.isExportNamedDeclaration()) {
|
|
261
|
+
path.parentPath.replaceWithMultiple(
|
|
262
|
+
path.node.declarations.map((declaration) =>
|
|
263
|
+
t.exportNamedDeclaration(
|
|
264
|
+
t.variableDeclaration(path.node.kind, [declaration])
|
|
265
|
+
)
|
|
266
|
+
)
|
|
267
|
+
);
|
|
268
|
+
} else {
|
|
269
|
+
path
|
|
270
|
+
.replaceWithMultiple(
|
|
271
|
+
path.node.declarations.map((declaration, i) => {
|
|
272
|
+
var names = Array.from(
|
|
273
|
+
getPatternIdentifierNames(path.get("declarations")[i])
|
|
274
|
+
);
|
|
275
|
+
names.forEach((name) => {
|
|
276
|
+
path.scope.removeBinding(name);
|
|
277
|
+
});
|
|
278
|
+
|
|
279
|
+
var newNode = t.variableDeclaration(path.node.kind, [
|
|
280
|
+
declaration,
|
|
281
|
+
]);
|
|
282
|
+
return newNode;
|
|
283
|
+
})
|
|
284
|
+
)
|
|
285
|
+
.forEach((newPath) => {
|
|
286
|
+
if (newPath.node.kind === "var") {
|
|
287
|
+
var functionOrProgram =
|
|
288
|
+
getParentFunctionOrProgram(newPath);
|
|
289
|
+
functionOrProgram.scope.registerDeclaration(newPath);
|
|
290
|
+
}
|
|
291
|
+
newPath.scope.registerDeclaration(newPath);
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
|
|
299
|
+
// () => a() -> () => { return a(); }
|
|
300
|
+
ArrowFunctionExpression: {
|
|
301
|
+
exit(path: NodePath<t.ArrowFunctionExpression>) {
|
|
302
|
+
if (path.node.body.type !== "BlockStatement") {
|
|
303
|
+
path.node.expression = false;
|
|
304
|
+
path.node.body = t.blockStatement([
|
|
305
|
+
t.returnStatement(path.node.body),
|
|
306
|
+
]);
|
|
307
|
+
}
|
|
308
|
+
},
|
|
309
|
+
},
|
|
310
|
+
|
|
311
|
+
// if (a) b() -> if (a) { b(); }
|
|
312
|
+
// if (a) {b()} else c() -> if (a) { b(); } else { c(); }
|
|
313
|
+
IfStatement: {
|
|
314
|
+
exit(path) {
|
|
315
|
+
if (path.node.consequent.type !== "BlockStatement") {
|
|
316
|
+
path.node.consequent = t.blockStatement([path.node.consequent]);
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
if (
|
|
320
|
+
path.node.alternate &&
|
|
321
|
+
path.node.alternate.type !== "BlockStatement"
|
|
322
|
+
) {
|
|
323
|
+
path.node.alternate = t.blockStatement([path.node.alternate]);
|
|
324
|
+
}
|
|
325
|
+
},
|
|
326
|
+
},
|
|
327
|
+
|
|
328
|
+
// for() d() -> for() { d(); }
|
|
329
|
+
// while(a) b() -> while(a) { b(); }
|
|
330
|
+
// with(a) b() -> with(a) { b(); }
|
|
331
|
+
"ForStatement|ForInStatement|ForOfStatement|WhileStatement|WithStatement":
|
|
332
|
+
{
|
|
333
|
+
exit(_path) {
|
|
334
|
+
var path = _path as NodePath<
|
|
335
|
+
| t.ForStatement
|
|
336
|
+
| t.ForInStatement
|
|
337
|
+
| t.ForOfStatement
|
|
338
|
+
| t.WhileStatement
|
|
339
|
+
| t.WithStatement
|
|
340
|
+
>;
|
|
341
|
+
|
|
342
|
+
if (path.node.body.type !== "BlockStatement") {
|
|
343
|
+
path.node.body = t.blockStatement([path.node.body]);
|
|
344
|
+
}
|
|
345
|
+
},
|
|
346
|
+
},
|
|
347
|
+
},
|
|
348
|
+
};
|
|
349
|
+
};
|