js-confuser 2.0.0 → 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.
Files changed (113) hide show
  1. package/.github/ISSUE_TEMPLATE/bug_report.md +43 -43
  2. package/.github/ISSUE_TEMPLATE/feature_request.md +20 -20
  3. package/.github/workflows/node.js.yml +28 -28
  4. package/.prettierrc +4 -4
  5. package/CHANGELOG.md +1015 -987
  6. package/CODE_OF_CONDUCT.md +131 -131
  7. package/CONTRIBUTING.md +52 -52
  8. package/LICENSE +21 -21
  9. package/Migration.md +72 -72
  10. package/README.md +86 -86
  11. package/dist/constants.js +43 -43
  12. package/dist/index.js +14 -23
  13. package/dist/obfuscator.js +31 -25
  14. package/dist/order.js +4 -4
  15. package/dist/presets.js +31 -31
  16. package/dist/templates/integrityTemplate.js +4 -4
  17. package/dist/templates/template.js +1 -2
  18. package/dist/transforms/astScrambler.js +1 -2
  19. package/dist/transforms/calculator.js +1 -2
  20. package/dist/transforms/controlFlowFlattening.js +60 -41
  21. package/dist/transforms/deadCode.js +1 -2
  22. package/dist/transforms/dispatcher.js +4 -5
  23. package/dist/transforms/extraction/duplicateLiteralsRemoval.js +1 -2
  24. package/dist/transforms/extraction/objectExtraction.js +1 -2
  25. package/dist/transforms/finalizer.js +1 -2
  26. package/dist/transforms/flatten.js +1 -2
  27. package/dist/transforms/identifier/globalConcealing.js +15 -2
  28. package/dist/transforms/identifier/movedDeclarations.js +8 -7
  29. package/dist/transforms/identifier/renameVariables.js +7 -7
  30. package/dist/transforms/lock/integrity.js +8 -9
  31. package/dist/transforms/lock/lock.js +1 -2
  32. package/dist/transforms/minify.js +11 -29
  33. package/dist/transforms/opaquePredicates.js +1 -2
  34. package/dist/transforms/pack.js +1 -2
  35. package/dist/transforms/plugin.js +18 -19
  36. package/dist/transforms/preparation.js +16 -16
  37. package/dist/transforms/renameLabels.js +1 -2
  38. package/dist/transforms/rgf.js +8 -9
  39. package/dist/transforms/shuffle.js +1 -2
  40. package/dist/transforms/string/encoding.js +1 -2
  41. package/dist/transforms/string/stringCompression.js +3 -4
  42. package/dist/transforms/string/stringConcealing.js +1 -2
  43. package/dist/transforms/string/stringEncoding.js +1 -2
  44. package/dist/transforms/variableMasking.js +1 -2
  45. package/dist/utils/NameGen.js +2 -2
  46. package/dist/utils/PredicateGen.js +1 -2
  47. package/dist/utils/ast-utils.js +87 -88
  48. package/dist/utils/function-utils.js +8 -8
  49. package/dist/utils/node.js +5 -6
  50. package/dist/utils/object-utils.js +4 -4
  51. package/dist/utils/random-utils.js +20 -20
  52. package/dist/utils/static-utils.js +1 -2
  53. package/dist/validateOptions.js +4 -7
  54. package/index.d.ts +17 -17
  55. package/package.json +61 -59
  56. package/src/constants.ts +168 -168
  57. package/src/index.ts +118 -118
  58. package/src/obfuscationResult.ts +49 -49
  59. package/src/obfuscator.ts +501 -497
  60. package/src/options.ts +407 -407
  61. package/src/order.ts +54 -54
  62. package/src/presets.ts +125 -125
  63. package/src/templates/bufferToStringTemplate.ts +57 -57
  64. package/src/templates/deadCodeTemplates.ts +1185 -1185
  65. package/src/templates/getGlobalTemplate.ts +76 -76
  66. package/src/templates/integrityTemplate.ts +64 -64
  67. package/src/templates/setFunctionLengthTemplate.ts +11 -11
  68. package/src/templates/stringCompressionTemplate.ts +20 -20
  69. package/src/templates/tamperProtectionTemplates.ts +120 -120
  70. package/src/templates/template.ts +224 -224
  71. package/src/transforms/astScrambler.ts +99 -99
  72. package/src/transforms/calculator.ts +99 -99
  73. package/src/transforms/controlFlowFlattening.ts +1716 -1680
  74. package/src/transforms/deadCode.ts +82 -82
  75. package/src/transforms/dispatcher.ts +450 -450
  76. package/src/transforms/extraction/duplicateLiteralsRemoval.ts +156 -158
  77. package/src/transforms/extraction/objectExtraction.ts +186 -186
  78. package/src/transforms/finalizer.ts +74 -74
  79. package/src/transforms/flatten.ts +421 -418
  80. package/src/transforms/identifier/globalConcealing.ts +315 -295
  81. package/src/transforms/identifier/movedDeclarations.ts +252 -251
  82. package/src/transforms/identifier/renameVariables.ts +328 -321
  83. package/src/transforms/lock/integrity.ts +117 -117
  84. package/src/transforms/lock/lock.ts +418 -418
  85. package/src/transforms/minify.ts +615 -629
  86. package/src/transforms/opaquePredicates.ts +100 -100
  87. package/src/transforms/pack.ts +239 -239
  88. package/src/transforms/plugin.ts +173 -173
  89. package/src/transforms/preparation.ts +349 -347
  90. package/src/transforms/renameLabels.ts +175 -175
  91. package/src/transforms/rgf.ts +322 -322
  92. package/src/transforms/shuffle.ts +82 -82
  93. package/src/transforms/string/encoding.ts +144 -144
  94. package/src/transforms/string/stringCompression.ts +128 -128
  95. package/src/transforms/string/stringConcealing.ts +312 -312
  96. package/src/transforms/string/stringEncoding.ts +80 -80
  97. package/src/transforms/string/stringSplitting.ts +77 -77
  98. package/src/transforms/variableMasking.ts +257 -257
  99. package/src/utils/IntGen.ts +33 -33
  100. package/src/utils/NameGen.ts +116 -116
  101. package/src/utils/PredicateGen.ts +61 -61
  102. package/src/utils/ast-utils.ts +663 -663
  103. package/src/utils/function-utils.ts +50 -50
  104. package/src/utils/gen-utils.ts +48 -48
  105. package/src/utils/node.ts +78 -78
  106. package/src/utils/object-utils.ts +21 -21
  107. package/src/utils/random-utils.ts +93 -93
  108. package/src/utils/static-utils.ts +66 -66
  109. package/src/validateOptions.ts +256 -259
  110. package/tsconfig.json +13 -14
  111. package/dist/probability.js +0 -1
  112. package/dist/transforms/functionOutlining.js +0 -230
  113. package/dist/utils/ControlObject.js +0 -125
@@ -1,100 +1,100 @@
1
- import { PluginArg, PluginObject } from "./plugin";
2
- import { Order } from "../order";
3
- import { NodePath } from "@babel/traverse";
4
- import * as t from "@babel/types";
5
- import { chance, getRandomString } from "../utils/random-utils";
6
- import PredicateGen from "../utils/PredicateGen";
7
-
8
- export default ({ Plugin }: PluginArg): PluginObject => {
9
- const me = Plugin(Order.OpaquePredicates, {
10
- changeData: {
11
- opaquePredicates: 0,
12
- },
13
- });
14
-
15
- const predicateGen = new PredicateGen(me);
16
-
17
- function createTruePredicate(path: NodePath) {
18
- return predicateGen.generateTrueExpression(path);
19
- }
20
-
21
- let active = true;
22
- let transformCount = 0;
23
- function shouldTransform(path: NodePath) {
24
- if (!active) return false;
25
- if (path.find((p) => me.isSkipped(p))) return false;
26
-
27
- if (!me.computeProbabilityMap(me.options.opaquePredicates)) return false;
28
-
29
- transformCount++;
30
-
31
- const depth = path.getAncestry().length;
32
-
33
- return chance(500 - transformCount - depth * 100);
34
- }
35
-
36
- function wrapWithPredicate(path: NodePath) {
37
- let newExpression = t.logicalExpression(
38
- "&&",
39
- createTruePredicate(path),
40
- path.node as t.Expression
41
- );
42
-
43
- me.changeData.opaquePredicates++;
44
-
45
- path.replaceWith(me.skip(newExpression));
46
- }
47
-
48
- return {
49
- visitor: {
50
- // if (test) -> if (PREDICATE() && test) {}
51
- IfStatement: {
52
- exit(path) {
53
- if (!shouldTransform(path)) return;
54
- wrapWithPredicate(path.get("test"));
55
- },
56
- },
57
-
58
- // test ? a : b -> PREDICATE() && test ? a : b
59
- ConditionalExpression: {
60
- exit(path) {
61
- if (!shouldTransform(path)) return;
62
-
63
- wrapWithPredicate(path.get("test"));
64
- },
65
- },
66
-
67
- // case test: -> case PREDICATE() && test:
68
- SwitchCase: {
69
- exit(path) {
70
- if (!path.node.test) return;
71
- if (!shouldTransform(path)) return;
72
-
73
- wrapWithPredicate(path.get("test"));
74
- },
75
- },
76
-
77
- // return test -> if (predicate()) { return test } else { return fake }
78
- ReturnStatement: {
79
- exit(path) {
80
- if (!path.node.argument) return;
81
- if (!shouldTransform(path)) return;
82
-
83
- me.changeData.opaquePredicates++;
84
-
85
- path.replaceWith(
86
- t.ifStatement(
87
- createTruePredicate(path),
88
- t.blockStatement([t.returnStatement(path.node.argument)]),
89
- t.blockStatement([
90
- t.returnStatement(t.stringLiteral(getRandomString(6))),
91
- ])
92
- )
93
- );
94
-
95
- me.skip(path);
96
- },
97
- },
98
- },
99
- };
100
- };
1
+ import { PluginArg, PluginObject } from "./plugin";
2
+ import { Order } from "../order";
3
+ import { NodePath } from "@babel/traverse";
4
+ import * as t from "@babel/types";
5
+ import { chance, getRandomString } from "../utils/random-utils";
6
+ import PredicateGen from "../utils/PredicateGen";
7
+
8
+ export default ({ Plugin }: PluginArg): PluginObject => {
9
+ const me = Plugin(Order.OpaquePredicates, {
10
+ changeData: {
11
+ opaquePredicates: 0,
12
+ },
13
+ });
14
+
15
+ const predicateGen = new PredicateGen(me);
16
+
17
+ function createTruePredicate(path: NodePath) {
18
+ return predicateGen.generateTrueExpression(path);
19
+ }
20
+
21
+ let active = true;
22
+ let transformCount = 0;
23
+ function shouldTransform(path: NodePath) {
24
+ if (!active) return false;
25
+ if (path.find((p) => me.isSkipped(p))) return false;
26
+
27
+ if (!me.computeProbabilityMap(me.options.opaquePredicates)) return false;
28
+
29
+ transformCount++;
30
+
31
+ const depth = path.getAncestry().length;
32
+
33
+ return chance(500 - transformCount - depth * 100);
34
+ }
35
+
36
+ function wrapWithPredicate(path: NodePath) {
37
+ let newExpression = t.logicalExpression(
38
+ "&&",
39
+ createTruePredicate(path),
40
+ path.node as t.Expression
41
+ );
42
+
43
+ me.changeData.opaquePredicates++;
44
+
45
+ path.replaceWith(me.skip(newExpression));
46
+ }
47
+
48
+ return {
49
+ visitor: {
50
+ // if (test) -> if (PREDICATE() && test) {}
51
+ IfStatement: {
52
+ exit(path) {
53
+ if (!shouldTransform(path)) return;
54
+ wrapWithPredicate(path.get("test"));
55
+ },
56
+ },
57
+
58
+ // test ? a : b -> PREDICATE() && test ? a : b
59
+ ConditionalExpression: {
60
+ exit(path) {
61
+ if (!shouldTransform(path)) return;
62
+
63
+ wrapWithPredicate(path.get("test"));
64
+ },
65
+ },
66
+
67
+ // case test: -> case PREDICATE() && test:
68
+ SwitchCase: {
69
+ exit(path) {
70
+ if (!path.node.test) return;
71
+ if (!shouldTransform(path)) return;
72
+
73
+ wrapWithPredicate(path.get("test"));
74
+ },
75
+ },
76
+
77
+ // return test -> if (predicate()) { return test } else { return fake }
78
+ ReturnStatement: {
79
+ exit(path) {
80
+ if (!path.node.argument) return;
81
+ if (!shouldTransform(path)) return;
82
+
83
+ me.changeData.opaquePredicates++;
84
+
85
+ path.replaceWith(
86
+ t.ifStatement(
87
+ createTruePredicate(path),
88
+ t.blockStatement([t.returnStatement(path.node.argument)]),
89
+ t.blockStatement([
90
+ t.returnStatement(t.stringLiteral(getRandomString(6))),
91
+ ])
92
+ )
93
+ );
94
+
95
+ me.skip(path);
96
+ },
97
+ },
98
+ },
99
+ };
100
+ };
@@ -1,239 +1,239 @@
1
- import * as t from "@babel/types";
2
- import Obfuscator from "../obfuscator";
3
- import Template from "../templates/template";
4
- import {
5
- isDefiningIdentifier,
6
- isModifiedIdentifier,
7
- isVariableIdentifier,
8
- } from "../utils/ast-utils";
9
- import {
10
- GEN_NODE,
11
- NodeSymbol,
12
- reservedIdentifiers,
13
- reservedNodeModuleIdentifiers,
14
- variableFunctionName,
15
- WITH_STATEMENT,
16
- } from "../constants";
17
- import { PluginArg, PluginObject } from "./plugin";
18
- import { Order } from "../order";
19
-
20
- export interface PackInterface {
21
- objectName: string;
22
- mappings: Map<string, string>;
23
- setterPropsNeeded: Set<string>;
24
- typeofMappings: Map<string, string>;
25
- }
26
-
27
- export default function pack({ Plugin }: PluginArg): PluginObject {
28
- const me = Plugin(Order.Pack, {
29
- changeData: {
30
- globals: 0,
31
- },
32
- });
33
-
34
- // RGF functions will re-use parent Pack Interface
35
- let packInterface = me.obfuscator.parentObfuscator?.packInterface;
36
-
37
- // Create new Pack Interface (root)
38
- if (!packInterface) {
39
- packInterface = {
40
- objectName: me.obfuscator.nameGen.generate(),
41
- mappings: new Map<string, string>(),
42
- setterPropsNeeded: new Set<string>(),
43
- typeofMappings: new Map<string, string>(),
44
- };
45
- me.obfuscator.packInterface = packInterface;
46
- }
47
-
48
- const { objectName, mappings, setterPropsNeeded, typeofMappings } =
49
- packInterface;
50
-
51
- const prependNodes: t.Statement[] = [];
52
-
53
- return {
54
- // Transform identifiers, preserve import statements
55
- visitor: {
56
- ImportDeclaration(path) {
57
- prependNodes.push(path.node);
58
- path.remove();
59
-
60
- // Ensure bindings are removed -> variable becomes a global -> added to mappings object
61
- path.scope.crawl();
62
- },
63
-
64
- // TODO: Add support for export statements
65
- "ExportNamedDeclaration|ExportDefaultDeclaration|ExportAllDeclaration"(
66
- path
67
- ) {
68
- me.error("Export statements are not supported in packed code.");
69
- },
70
-
71
- Program(path) {
72
- path.scope.crawl();
73
- },
74
-
75
- Identifier: {
76
- exit(path) {
77
- if (!isVariableIdentifier(path)) return;
78
-
79
- if (isDefiningIdentifier(path)) return;
80
- if ((path.node as NodeSymbol)[GEN_NODE]) return;
81
- if ((path.node as NodeSymbol)[WITH_STATEMENT]) return;
82
-
83
- const identifierName = path.node.name;
84
- if (reservedIdentifiers.has(identifierName)) return;
85
- if (
86
- me.options.target === "node" &&
87
- reservedNodeModuleIdentifiers.has(identifierName)
88
- ) {
89
- // Allow module.exports and require
90
- } else {
91
- if (me.options.globalVariables.has(identifierName)) return;
92
- }
93
- if (identifierName === variableFunctionName) return;
94
- if (identifierName === objectName) return;
95
-
96
- if (!path.scope.hasGlobal(identifierName)) return;
97
- if (path.scope.hasBinding(identifierName)) return;
98
-
99
- // Check user's custom implementation
100
- if (!me.computeProbabilityMap(me.options.pack, identifierName))
101
- return;
102
-
103
- if (
104
- path.key === "argument" &&
105
- path.parentPath.isUnaryExpression({ operator: "typeof" })
106
- ) {
107
- const unaryExpression = path.parentPath;
108
-
109
- let propertyName = typeofMappings.get(identifierName);
110
- if (!propertyName) {
111
- propertyName = me.obfuscator.nameGen.generate();
112
- typeofMappings.set(identifierName, propertyName);
113
- }
114
-
115
- unaryExpression.replaceWith(
116
- t.memberExpression(
117
- t.identifier(objectName),
118
- t.stringLiteral(propertyName),
119
- true
120
- )
121
- );
122
- return;
123
- }
124
-
125
- let propertyName = mappings.get(identifierName);
126
- if (!propertyName) {
127
- propertyName = me.obfuscator.nameGen.generate();
128
- mappings.set(identifierName, propertyName);
129
- }
130
-
131
- // Only add setter if the identifier is modified
132
- if (isModifiedIdentifier(path)) {
133
- setterPropsNeeded.add(identifierName);
134
- }
135
-
136
- path.replaceWith(
137
- t.memberExpression(
138
- t.identifier(objectName),
139
- t.stringLiteral(propertyName),
140
- true
141
- )
142
- );
143
- },
144
- },
145
- },
146
-
147
- // Final AST handler
148
- // Very last step in the obfuscation process
149
- finalASTHandler(ast) {
150
- if (me.obfuscator.parentObfuscator) return ast; // Only for root obfuscator
151
-
152
- // Create object expression
153
- // Very similar to flatten, maybe refactor to use the same code
154
- const objectProperties: t.ObjectMethod[] = [];
155
-
156
- me.changeData.globals = mappings.size;
157
-
158
- for (const [identifierName, propertyName] of mappings) {
159
- // get identifier() { return identifier; }
160
- objectProperties.push(
161
- t.objectMethod(
162
- "get",
163
- t.stringLiteral(propertyName),
164
- [],
165
- t.blockStatement([t.returnStatement(t.identifier(identifierName))])
166
- )
167
- );
168
-
169
- // Only add setter if the identifier is modified
170
- if (setterPropsNeeded.has(identifierName)) {
171
- // set identifier(value) { return identifier = value; }
172
- objectProperties.push(
173
- t.objectMethod(
174
- "set",
175
- t.stringLiteral(propertyName),
176
- [t.identifier(objectName)],
177
- t.blockStatement([
178
- t.returnStatement(
179
- t.assignmentExpression(
180
- "=",
181
- t.identifier(identifierName),
182
- t.identifier(objectName)
183
- )
184
- ),
185
- ])
186
- )
187
- );
188
- }
189
- }
190
-
191
- // Add typeof mappings
192
- for (const [identifierName, propertyName] of typeofMappings) {
193
- // get typeof identifier() { return typeof identifier; }
194
- objectProperties.push(
195
- t.objectMethod(
196
- "get",
197
- t.stringLiteral(propertyName),
198
- [],
199
- t.blockStatement([
200
- t.returnStatement(
201
- t.unaryExpression("typeof", t.identifier(identifierName))
202
- ),
203
- ])
204
- )
205
- );
206
- }
207
-
208
- const objectExpression = t.objectExpression(objectProperties);
209
-
210
- // Convert last expression to return statement
211
- // This preserves the last expression in the packed code
212
- var lastStatement = ast.program.body.at(-1);
213
- if (lastStatement && t.isExpressionStatement(lastStatement)) {
214
- Object.assign(
215
- lastStatement,
216
-
217
- t.returnStatement(lastStatement.expression)
218
- );
219
- }
220
-
221
- const outputCode = Obfuscator.generateCode(ast, {
222
- ...me.obfuscator.options,
223
- compact: true,
224
- });
225
-
226
- var newAST = new Template(`
227
- {prependNodes}
228
- Function({objectName}, {outputCode})({objectExpression});
229
- `).file({
230
- objectName: () => t.stringLiteral(objectName),
231
- outputCode: () => t.stringLiteral(outputCode),
232
- objectExpression: objectExpression,
233
- prependNodes: prependNodes,
234
- });
235
-
236
- return newAST;
237
- },
238
- };
239
- }
1
+ import * as t from "@babel/types";
2
+ import Obfuscator from "../obfuscator";
3
+ import Template from "../templates/template";
4
+ import {
5
+ isDefiningIdentifier,
6
+ isModifiedIdentifier,
7
+ isVariableIdentifier,
8
+ } from "../utils/ast-utils";
9
+ import {
10
+ GEN_NODE,
11
+ NodeSymbol,
12
+ reservedIdentifiers,
13
+ reservedNodeModuleIdentifiers,
14
+ variableFunctionName,
15
+ WITH_STATEMENT,
16
+ } from "../constants";
17
+ import { PluginArg, PluginObject } from "./plugin";
18
+ import { Order } from "../order";
19
+
20
+ export interface PackInterface {
21
+ objectName: string;
22
+ mappings: Map<string, string>;
23
+ setterPropsNeeded: Set<string>;
24
+ typeofMappings: Map<string, string>;
25
+ }
26
+
27
+ export default function pack({ Plugin }: PluginArg): PluginObject {
28
+ const me = Plugin(Order.Pack, {
29
+ changeData: {
30
+ globals: 0,
31
+ },
32
+ });
33
+
34
+ // RGF functions will re-use parent Pack Interface
35
+ let packInterface = me.obfuscator.parentObfuscator?.packInterface;
36
+
37
+ // Create new Pack Interface (root)
38
+ if (!packInterface) {
39
+ packInterface = {
40
+ objectName: me.obfuscator.nameGen.generate(),
41
+ mappings: new Map<string, string>(),
42
+ setterPropsNeeded: new Set<string>(),
43
+ typeofMappings: new Map<string, string>(),
44
+ };
45
+ me.obfuscator.packInterface = packInterface;
46
+ }
47
+
48
+ const { objectName, mappings, setterPropsNeeded, typeofMappings } =
49
+ packInterface;
50
+
51
+ const prependNodes: t.Statement[] = [];
52
+
53
+ return {
54
+ // Transform identifiers, preserve import statements
55
+ visitor: {
56
+ ImportDeclaration(path) {
57
+ prependNodes.push(path.node);
58
+ path.remove();
59
+
60
+ // Ensure bindings are removed -> variable becomes a global -> added to mappings object
61
+ path.scope.crawl();
62
+ },
63
+
64
+ // TODO: Add support for export statements
65
+ "ExportNamedDeclaration|ExportDefaultDeclaration|ExportAllDeclaration"(
66
+ path
67
+ ) {
68
+ me.error("Export statements are not supported in packed code.");
69
+ },
70
+
71
+ Program(path) {
72
+ path.scope.crawl();
73
+ },
74
+
75
+ Identifier: {
76
+ exit(path) {
77
+ if (!isVariableIdentifier(path)) return;
78
+
79
+ if (isDefiningIdentifier(path)) return;
80
+ if ((path.node as NodeSymbol)[GEN_NODE]) return;
81
+ if ((path.node as NodeSymbol)[WITH_STATEMENT]) return;
82
+
83
+ const identifierName = path.node.name;
84
+ if (reservedIdentifiers.has(identifierName)) return;
85
+ if (
86
+ me.options.target === "node" &&
87
+ reservedNodeModuleIdentifiers.has(identifierName)
88
+ ) {
89
+ // Allow module.exports and require
90
+ } else {
91
+ if (me.options.globalVariables.has(identifierName)) return;
92
+ }
93
+ if (identifierName === variableFunctionName) return;
94
+ if (identifierName === objectName) return;
95
+
96
+ if (!path.scope.hasGlobal(identifierName)) return;
97
+ if (path.scope.hasBinding(identifierName)) return;
98
+
99
+ // Check user's custom implementation
100
+ if (!me.computeProbabilityMap(me.options.pack, identifierName))
101
+ return;
102
+
103
+ if (
104
+ path.key === "argument" &&
105
+ path.parentPath.isUnaryExpression({ operator: "typeof" })
106
+ ) {
107
+ const unaryExpression = path.parentPath;
108
+
109
+ let propertyName = typeofMappings.get(identifierName);
110
+ if (!propertyName) {
111
+ propertyName = me.obfuscator.nameGen.generate();
112
+ typeofMappings.set(identifierName, propertyName);
113
+ }
114
+
115
+ unaryExpression.replaceWith(
116
+ t.memberExpression(
117
+ t.identifier(objectName),
118
+ t.stringLiteral(propertyName),
119
+ true
120
+ )
121
+ );
122
+ return;
123
+ }
124
+
125
+ let propertyName = mappings.get(identifierName);
126
+ if (!propertyName) {
127
+ propertyName = me.obfuscator.nameGen.generate();
128
+ mappings.set(identifierName, propertyName);
129
+ }
130
+
131
+ // Only add setter if the identifier is modified
132
+ if (isModifiedIdentifier(path)) {
133
+ setterPropsNeeded.add(identifierName);
134
+ }
135
+
136
+ path.replaceWith(
137
+ t.memberExpression(
138
+ t.identifier(objectName),
139
+ t.stringLiteral(propertyName),
140
+ true
141
+ )
142
+ );
143
+ },
144
+ },
145
+ },
146
+
147
+ // Final AST handler
148
+ // Very last step in the obfuscation process
149
+ finalASTHandler(ast) {
150
+ if (me.obfuscator.parentObfuscator) return ast; // Only for root obfuscator
151
+
152
+ // Create object expression
153
+ // Very similar to flatten, maybe refactor to use the same code
154
+ const objectProperties: t.ObjectMethod[] = [];
155
+
156
+ me.changeData.globals = mappings.size;
157
+
158
+ for (const [identifierName, propertyName] of mappings) {
159
+ // get identifier() { return identifier; }
160
+ objectProperties.push(
161
+ t.objectMethod(
162
+ "get",
163
+ t.stringLiteral(propertyName),
164
+ [],
165
+ t.blockStatement([t.returnStatement(t.identifier(identifierName))])
166
+ )
167
+ );
168
+
169
+ // Only add setter if the identifier is modified
170
+ if (setterPropsNeeded.has(identifierName)) {
171
+ // set identifier(value) { return identifier = value; }
172
+ objectProperties.push(
173
+ t.objectMethod(
174
+ "set",
175
+ t.stringLiteral(propertyName),
176
+ [t.identifier(objectName)],
177
+ t.blockStatement([
178
+ t.returnStatement(
179
+ t.assignmentExpression(
180
+ "=",
181
+ t.identifier(identifierName),
182
+ t.identifier(objectName)
183
+ )
184
+ ),
185
+ ])
186
+ )
187
+ );
188
+ }
189
+ }
190
+
191
+ // Add typeof mappings
192
+ for (const [identifierName, propertyName] of typeofMappings) {
193
+ // get typeof identifier() { return typeof identifier; }
194
+ objectProperties.push(
195
+ t.objectMethod(
196
+ "get",
197
+ t.stringLiteral(propertyName),
198
+ [],
199
+ t.blockStatement([
200
+ t.returnStatement(
201
+ t.unaryExpression("typeof", t.identifier(identifierName))
202
+ ),
203
+ ])
204
+ )
205
+ );
206
+ }
207
+
208
+ const objectExpression = t.objectExpression(objectProperties);
209
+
210
+ // Convert last expression to return statement
211
+ // This preserves the last expression in the packed code
212
+ var lastStatement = ast.program.body.at(-1);
213
+ if (lastStatement && t.isExpressionStatement(lastStatement)) {
214
+ Object.assign(
215
+ lastStatement,
216
+
217
+ t.returnStatement(lastStatement.expression)
218
+ );
219
+ }
220
+
221
+ const outputCode = Obfuscator.generateCode(ast, {
222
+ ...me.obfuscator.options,
223
+ compact: true,
224
+ });
225
+
226
+ var newAST = new Template(`
227
+ {prependNodes}
228
+ Function({objectName}, {outputCode})({objectExpression});
229
+ `).file({
230
+ objectName: () => t.stringLiteral(objectName),
231
+ outputCode: () => t.stringLiteral(outputCode),
232
+ objectExpression: objectExpression,
233
+ prependNodes: prependNodes,
234
+ });
235
+
236
+ return newAST;
237
+ },
238
+ };
239
+ }