js-confuser 1.5.9 → 1.7.0

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 (143) hide show
  1. package/.github/workflows/node.js.yml +2 -2
  2. package/CHANGELOG.md +55 -0
  3. package/README.md +346 -165
  4. package/dist/constants.js +6 -2
  5. package/dist/index.js +9 -21
  6. package/dist/obfuscator.js +19 -31
  7. package/dist/options.js +5 -5
  8. package/dist/order.js +1 -3
  9. package/dist/presets.js +6 -7
  10. package/dist/probability.js +2 -4
  11. package/dist/templates/bufferToString.js +13 -0
  12. package/dist/templates/crash.js +3 -3
  13. package/dist/templates/es5.js +18 -0
  14. package/dist/templates/functionLength.js +16 -0
  15. package/dist/transforms/calculator.js +77 -21
  16. package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +980 -367
  17. package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +4 -1
  18. package/dist/transforms/controlFlowFlattening/switchCaseObfuscation.js +25 -26
  19. package/dist/transforms/deadCode.js +33 -25
  20. package/dist/transforms/dispatcher.js +8 -4
  21. package/dist/transforms/es5/antiDestructuring.js +2 -0
  22. package/dist/transforms/es5/es5.js +31 -34
  23. package/dist/transforms/extraction/duplicateLiteralsRemoval.js +92 -58
  24. package/dist/transforms/finalizer.js +82 -0
  25. package/dist/transforms/flatten.js +229 -148
  26. package/dist/transforms/identifier/globalAnalysis.js +88 -0
  27. package/dist/transforms/identifier/globalConcealing.js +10 -83
  28. package/dist/transforms/identifier/movedDeclarations.js +35 -88
  29. package/dist/transforms/identifier/renameVariables.js +124 -59
  30. package/dist/transforms/identifier/variableAnalysis.js +58 -62
  31. package/dist/transforms/lock/lock.js +0 -37
  32. package/dist/transforms/minify.js +60 -57
  33. package/dist/transforms/opaquePredicates.js +1 -1
  34. package/dist/transforms/preparation/preparation.js +2 -2
  35. package/dist/transforms/preparation.js +231 -0
  36. package/dist/transforms/renameLabels.js +1 -1
  37. package/dist/transforms/rgf.js +139 -247
  38. package/dist/transforms/stack.js +128 -26
  39. package/dist/transforms/string/encoding.js +150 -179
  40. package/dist/transforms/string/stringCompression.js +14 -15
  41. package/dist/transforms/string/stringConcealing.js +25 -8
  42. package/dist/transforms/string/stringEncoding.js +13 -24
  43. package/dist/transforms/transform.js +12 -19
  44. package/dist/traverse.js +24 -10
  45. package/dist/util/gen.js +17 -1
  46. package/dist/util/identifiers.js +37 -3
  47. package/dist/util/insert.js +35 -4
  48. package/dist/util/random.js +15 -0
  49. package/docs/ControlFlowFlattening.md +595 -0
  50. package/{Countermeasures.md → docs/Countermeasures.md} +1 -15
  51. package/{Integrity.md → docs/Integrity.md} +2 -2
  52. package/docs/RGF.md +419 -0
  53. package/package.json +5 -5
  54. package/src/constants.ts +3 -0
  55. package/src/index.ts +2 -2
  56. package/src/obfuscator.ts +19 -31
  57. package/src/options.ts +14 -103
  58. package/src/order.ts +1 -5
  59. package/src/presets.ts +6 -7
  60. package/src/probability.ts +2 -3
  61. package/src/templates/bufferToString.ts +68 -0
  62. package/src/templates/crash.ts +15 -19
  63. package/src/templates/es5.ts +131 -0
  64. package/src/templates/functionLength.ts +14 -0
  65. package/src/transforms/calculator.ts +122 -59
  66. package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +1583 -571
  67. package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +4 -1
  68. package/src/transforms/deadCode.ts +383 -26
  69. package/src/transforms/dispatcher.ts +9 -4
  70. package/src/transforms/es5/antiDestructuring.ts +2 -0
  71. package/src/transforms/es5/es5.ts +32 -77
  72. package/src/transforms/extraction/duplicateLiteralsRemoval.ts +133 -129
  73. package/src/transforms/{hexadecimalNumbers.ts → finalizer.ts} +29 -13
  74. package/src/transforms/flatten.ts +357 -300
  75. package/src/transforms/identifier/globalAnalysis.ts +85 -0
  76. package/src/transforms/identifier/globalConcealing.ts +14 -103
  77. package/src/transforms/identifier/movedDeclarations.ts +49 -102
  78. package/src/transforms/identifier/renameVariables.ts +149 -78
  79. package/src/transforms/identifier/variableAnalysis.ts +66 -73
  80. package/src/transforms/lock/lock.ts +1 -42
  81. package/src/transforms/minify.ts +91 -75
  82. package/src/transforms/opaquePredicates.ts +2 -2
  83. package/src/transforms/preparation.ts +238 -0
  84. package/src/transforms/renameLabels.ts +2 -2
  85. package/src/transforms/rgf.ts +213 -405
  86. package/src/transforms/stack.ts +156 -36
  87. package/src/transforms/string/encoding.ts +115 -212
  88. package/src/transforms/string/stringCompression.ts +27 -18
  89. package/src/transforms/string/stringConcealing.ts +39 -9
  90. package/src/transforms/string/stringEncoding.ts +18 -18
  91. package/src/transforms/transform.ts +21 -23
  92. package/src/traverse.ts +23 -4
  93. package/src/types.ts +2 -1
  94. package/src/util/gen.ts +28 -3
  95. package/src/util/identifiers.ts +43 -2
  96. package/src/util/insert.ts +38 -3
  97. package/src/util/random.ts +13 -0
  98. package/test/code/Cash.test.ts +1 -1
  99. package/test/code/Dynamic.test.ts +12 -10
  100. package/test/code/ES6.src.js +146 -0
  101. package/test/code/ES6.test.ts +28 -2
  102. package/test/index.test.ts +2 -1
  103. package/test/probability.test.ts +44 -0
  104. package/test/templates/template.test.ts +1 -1
  105. package/test/transforms/antiTooling.test.ts +22 -0
  106. package/test/transforms/calculator.test.ts +40 -0
  107. package/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts +702 -160
  108. package/test/transforms/controlFlowFlattening/expressionObfuscation.test.ts +173 -0
  109. package/test/transforms/deadCode.test.ts +66 -15
  110. package/test/transforms/dispatcher.test.ts +20 -1
  111. package/test/transforms/es5/antiDestructuring.test.ts +16 -0
  112. package/test/transforms/flatten.test.ts +399 -86
  113. package/test/transforms/identifier/movedDeclarations.test.ts +63 -8
  114. package/test/transforms/identifier/renameVariables.test.ts +119 -0
  115. package/test/transforms/lock/antiDebug.test.ts +2 -2
  116. package/test/transforms/lock/lock.test.ts +1 -48
  117. package/test/transforms/minify.test.ts +104 -0
  118. package/test/transforms/preparation.test.ts +157 -0
  119. package/test/transforms/rgf.test.ts +261 -381
  120. package/test/transforms/stack.test.ts +143 -21
  121. package/test/transforms/string/stringCompression.test.ts +39 -0
  122. package/test/transforms/string/stringConcealing.test.ts +82 -0
  123. package/test/transforms/string/stringEncoding.test.ts +53 -2
  124. package/test/transforms/transform.test.ts +66 -0
  125. package/test/traverse.test.ts +139 -0
  126. package/test/util/identifiers.test.ts +113 -1
  127. package/test/util/insert.test.ts +57 -3
  128. package/src/transforms/controlFlowFlattening/choiceFlowObfuscation.ts +0 -87
  129. package/src/transforms/controlFlowFlattening/controlFlowObfuscation.ts +0 -203
  130. package/src/transforms/controlFlowFlattening/switchCaseObfuscation.ts +0 -130
  131. package/src/transforms/eval.ts +0 -89
  132. package/src/transforms/hideInitializingCode.ts +0 -432
  133. package/src/transforms/identifier/nameRecycling.ts +0 -280
  134. package/src/transforms/label.ts +0 -64
  135. package/src/transforms/preparation/nameConflicts.ts +0 -102
  136. package/src/transforms/preparation/preparation.ts +0 -176
  137. package/test/transforms/controlFlowFlattening/controlFlowObfuscation.test.ts +0 -101
  138. package/test/transforms/controlFlowFlattening/switchCaseObfuscation.test.ts +0 -120
  139. package/test/transforms/eval.test.ts +0 -131
  140. package/test/transforms/hideInitializingCode.test.ts +0 -336
  141. package/test/transforms/identifier/nameRecycling.test.ts +0 -205
  142. package/test/transforms/preparation/nameConflicts.test.ts +0 -52
  143. package/test/transforms/preparation/preparation.test.ts +0 -62
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ var _order = require("../order");
9
+
10
+ var _gen = require("../util/gen");
11
+
12
+ var _stringEncoding = _interopRequireDefault(require("./string/stringEncoding"));
13
+
14
+ var _transform = _interopRequireDefault(require("./transform"));
15
+
16
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
17
+
18
+ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
19
+
20
+ /**
21
+ * The Finalizer is the last transformation before the code is ready to be generated.
22
+ *
23
+ * Hexadecimal numbers:
24
+ * - Convert integer literals into `Identifier` nodes with the name being a hexadecimal number
25
+ *
26
+ * BigInt support:
27
+ * - Convert BigInt literals into `Identifier` nodes with the name being the raw BigInt string value + "n"
28
+ *
29
+ * String Encoding:
30
+ * - Convert String literals into `Identifier` nodes with the name being a unicode escaped string
31
+ */
32
+ class Finalizer extends _transform.default {
33
+ constructor(o) {
34
+ super(o, _order.ObfuscateOrder.Finalizer);
35
+
36
+ _defineProperty(this, "stringEncoding", void 0);
37
+
38
+ this.stringEncoding = new _stringEncoding.default(o);
39
+ }
40
+
41
+ isNumberLiteral(object) {
42
+ return object.type === "Literal" && typeof object.value === "number" && Math.floor(object.value) === object.value;
43
+ }
44
+
45
+ isBigIntLiteral(object) {
46
+ return object.type === "Literal" && typeof object.value === "bigint";
47
+ }
48
+
49
+ match(object, parents) {
50
+ return object.type === "Literal";
51
+ }
52
+
53
+ transform(object, parents) {
54
+ // Hexadecimal Numbers
55
+ if (this.options.hexadecimalNumbers && this.isNumberLiteral(object)) {
56
+ return () => {
57
+ // Technically, a Literal will never be negative because it's supposed to be inside a UnaryExpression with a "-" operator.
58
+ // This code handles it regardless
59
+ var isNegative = object.value < 0;
60
+ var hex = Math.abs(object.value).toString(16);
61
+ var newStr = (isNegative ? "-" : "") + "0x" + hex;
62
+ this.replace(object, (0, _gen.Identifier)(newStr));
63
+ };
64
+ } // BigInt support
65
+
66
+
67
+ if (this.isBigIntLiteral(object)) {
68
+ // https://github.com/MichaelXF/js-confuser/issues/79
69
+ return () => {
70
+ // Use an Identifier with the raw string
71
+ this.replace(object, (0, _gen.Identifier)(object.raw));
72
+ };
73
+ }
74
+
75
+ if (this.options.stringEncoding && this.stringEncoding.match(object, parents)) {
76
+ return this.stringEncoding.transform(object, parents);
77
+ }
78
+ }
79
+
80
+ }
81
+
82
+ exports.default = Finalizer;
@@ -11,7 +11,7 @@ var _constants = require("../constants");
11
11
 
12
12
  var _order = require("../order");
13
13
 
14
- var _traverse = _interopRequireWildcard(require("../traverse"));
14
+ var _traverse = require("../traverse");
15
15
 
16
16
  var _gen = require("../util/gen");
17
17
 
@@ -23,71 +23,87 @@ var _random = require("../util/random");
23
23
 
24
24
  var _transform = _interopRequireDefault(require("./transform"));
25
25
 
26
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
27
-
28
- function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
26
+ var _functionLength = require("../templates/functionLength");
29
27
 
30
- function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
28
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
31
29
 
32
30
  function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
33
31
 
34
32
  /**
35
- * Brings every function to the global level.
33
+ * Flatten takes functions and isolates them from their original scope, and brings it to the top level of the program.
34
+ *
35
+ * An additional `flatObject` parameter is passed in, giving access to the original scoped variables.
36
36
  *
37
- * Functions take parameters, input, have a return value and return modified changes to the scoped variables.
37
+ * The `flatObject` uses `get` and `set` properties to allow easy an AST transformation:
38
38
  *
39
39
  * ```js
40
- * function topLevel(ref1, ref2, refN, param1, param2, paramN){
41
- * return [ref1, ref2, refN, returnValue];
40
+ * // Input
41
+ * function myFunction(myParam){
42
+ * modified = true;
43
+ * if(reference) {
44
+ *
45
+ * }
46
+ * ...
47
+ * console.log(myParam);
48
+ * }
49
+ *
50
+ * // Output
51
+ * function myFunction_flat([myParam], flatObject){
52
+ * flatObject["set_modified"] = true;
53
+ * if(flatObject["get_reference"]) {
54
+ *
55
+ * }
56
+ * ...
57
+ * console.log(myParam)
58
+ * }
59
+ *
60
+ * function myFunction(){
61
+ * var flatObject = {
62
+ * set set_modified(v) { modified = v }
63
+ * get get_reference() { return reference }
64
+ * }
65
+ * return myFunction_flat([...arguments], flatObject)
42
66
  * }
43
67
  * ```
44
68
  *
45
69
  * Flatten is used to make functions eligible for the RGF transformation.
70
+ *
71
+ * - `myFunction_flat` is now eligible because it does not rely on outside scoped variables
46
72
  */
47
73
  class Flatten extends _transform.default {
74
+ // Array of FunctionDeclaration nodes
48
75
  constructor(o) {
49
76
  super(o, _order.ObfuscateOrder.Flatten);
50
77
 
78
+ _defineProperty(this, "isDebug", false);
79
+
51
80
  _defineProperty(this, "definedNames", void 0);
52
81
 
53
82
  _defineProperty(this, "flattenedFns", void 0);
54
83
 
55
84
  _defineProperty(this, "gen", void 0);
56
85
 
86
+ _defineProperty(this, "functionLengthName", void 0);
87
+
57
88
  this.definedNames = new Map();
58
89
  this.flattenedFns = [];
59
- this.gen = this.getGenerator();
90
+ this.gen = this.getGenerator("mangled");
91
+
92
+ if (this.isDebug) {
93
+ console.warn("Flatten debug mode");
94
+ }
60
95
  }
61
96
 
62
97
  apply(tree) {
63
- (0, _traverse.default)(tree, (o, p) => {
64
- if (o.type == "Identifier" && !_constants.reservedIdentifiers.has(o.name) && !this.options.globalVariables.has(o.name)) {
65
- var info = (0, _identifiers.getIdentifierInfo)(o, p);
66
-
67
- if (info.spec.isReferenced) {
68
- if (info.spec.isDefined) {
69
- var c = (0, _insert.getVarContext)(o, p);
70
-
71
- if (c) {
72
- if (!this.definedNames.has(c)) {
73
- this.definedNames.set(c, new Set([o.name]));
74
- } else {
75
- this.definedNames.get(c).add(o.name);
76
- }
77
- }
78
- }
79
- }
80
- }
81
- });
82
98
  super.apply(tree);
83
99
 
84
100
  if (this.flattenedFns.length) {
85
- (0, _insert.prepend)(tree, (0, _gen.VariableDeclaration)(this.flattenedFns));
101
+ (0, _insert.prepend)(tree, ...this.flattenedFns);
86
102
  }
87
103
  }
88
104
 
89
105
  match(object, parents) {
90
- return (object.type == "FunctionDeclaration" || object.type === "FunctionExpression") && object.body.type == "BlockStatement" && !object.generator && !object.params.find(x => x.type !== "Identifier");
106
+ return (object.type == "FunctionDeclaration" || object.type === "FunctionExpression") && object.body.type == "BlockStatement" && !object.$requiresEval && !object.generator && !object.params.find(x => x.type !== "Identifier");
91
107
  }
92
108
 
93
109
  transform(object, parents) {
@@ -101,7 +117,7 @@ class Flatten extends _transform.default {
101
117
  } // Don't change getter/setter methods
102
118
 
103
119
 
104
- if (parents[0].type === "Property" && parents[0].value === object && parents[0].kind !== "init") {
120
+ if (parents[0].type === "Property" && parents[0].value === object && (parents[0].kind !== "init" || parents[0].method)) {
105
121
  return;
106
122
  }
107
123
  }
@@ -111,76 +127,54 @@ class Flatten extends _transform.default {
111
127
  var currentFnName = object.type === "FunctionDeclaration" ? (_object$id = object.id) === null || _object$id === void 0 ? void 0 : _object$id.name : ((_parents$ = parents[0]) === null || _parents$ === void 0 ? void 0 : _parents$.type) === "VariableDeclarator" && ((_parents$0$id = parents[0].id) === null || _parents$0$id === void 0 ? void 0 : _parents$0$id.type) === "Identifier" && ((_parents$0$id2 = parents[0].id) === null || _parents$0$id2 === void 0 ? void 0 : _parents$0$id2.name);
112
128
 
113
129
  if (((_parents$2 = parents[0]) === null || _parents$2 === void 0 ? void 0 : _parents$2.type) === "Property" && (_parents$3 = parents[0]) !== null && _parents$3 !== void 0 && _parents$3.key) {
114
- var _parents$4, _parents$4$key, _parents$5, _parents$5$key;
130
+ var _parents$4, _parents$4$key;
115
131
 
116
- currentFnName = currentFnName || String(((_parents$4 = parents[0]) === null || _parents$4 === void 0 ? void 0 : (_parents$4$key = _parents$4.key) === null || _parents$4$key === void 0 ? void 0 : _parents$4$key.name) || ((_parents$5 = parents[0]) === null || _parents$5 === void 0 ? void 0 : (_parents$5$key = _parents$5.key) === null || _parents$5$key === void 0 ? void 0 : _parents$5$key.value));
132
+ currentFnName = currentFnName || String((_parents$4 = parents[0]) === null || _parents$4 === void 0 ? void 0 : (_parents$4$key = _parents$4.key) === null || _parents$4$key === void 0 ? void 0 : _parents$4$key.name);
117
133
  }
118
134
 
119
135
  if (!currentFnName) currentFnName = "unnamed";
120
- var defined = new Set();
121
- var references = new Set();
122
- var modified = new Set();
136
+ var definedMap = new Map();
123
137
  var illegal = new Set();
124
138
  var isIllegal = false;
125
- var definedAbove = new Set(this.options.globalVariables);
126
- parents.forEach(x => {
127
- var set = this.definedNames.get(x);
128
-
129
- if (set) {
130
- set.forEach(name => definedAbove.add(name));
131
- }
132
- });
139
+ var identifierNodes = [];
133
140
  (0, _traverse.walk)(object, parents, (o, p) => {
134
- if (object.id && o === object.id) {
135
- return;
141
+ if (o.type === "Identifier" && o.name === "arguments" || o.type === "UnaryExpression" && o.operator === "delete" || o.type == "ThisExpression" || o.type == "Super" || o.type == "MetaProperty") {
142
+ isIllegal = true;
143
+ return "EXIT";
136
144
  }
137
145
 
138
- if (o.type == "Identifier" && !this.options.globalVariables.has(o.name) && !_constants.reservedIdentifiers.has(o.name)) {
146
+ if (o.type == "Identifier" && o !== object.id && !this.options.globalVariables.has(o.name) && !_constants.reservedIdentifiers.has(o.name)) {
139
147
  var info = (0, _identifiers.getIdentifierInfo)(o, p);
140
148
 
141
149
  if (!info.spec.isReferenced) {
142
150
  return;
143
151
  }
144
152
 
145
- if (o.hidden) {
153
+ if (info.spec.isExported || o.name.startsWith(_constants.noRenameVariablePrefix)) {
146
154
  illegal.add(o.name);
147
- } else if (info.spec.isDefined) {
148
- defined.add(o.name);
149
- } else if (info.spec.isModified) {
150
- modified.add(o.name);
151
- } else {
152
- references.add(o.name);
155
+ return;
153
156
  }
154
- }
155
157
 
156
- if (o.type == "TryStatement") {
157
- isIllegal = true;
158
- return "EXIT";
159
- }
158
+ if (info.spec.isDefined) {
159
+ var definingContext = (0, _insert.getDefiningContext)(o, p);
160
160
 
161
- if (o.type == "Identifier") {
162
- if (o.name == "arguments") {
163
- isIllegal = true;
164
- return "EXIT";
165
- }
166
- }
161
+ if (!definedMap.has(definingContext)) {
162
+ definedMap.set(definingContext, new Set([o.name]));
163
+ } else {
164
+ definedMap.get(definingContext).add(o.name);
165
+ }
167
166
 
168
- if (o.type == "ThisExpression") {
169
- isIllegal = true;
170
- return "EXIT";
171
- }
167
+ return;
168
+ }
172
169
 
173
- if (o.type == "Super") {
174
- isIllegal = true;
175
- return "EXIT";
176
- }
170
+ var isDefined = p.find(x => definedMap.has(x) && definedMap.get(x).has(o.name));
177
171
 
178
- if (o.type == "MetaProperty") {
179
- isIllegal = true;
180
- return "EXIT";
172
+ if (!isDefined) {
173
+ identifierNodes.push([o, p, info]);
174
+ }
181
175
  }
182
176
 
183
- if (o.type == "VariableDeclaration" && o.kind !== "var") {
177
+ if (o.type == "TryStatement") {
184
178
  isIllegal = true;
185
179
  return "EXIT";
186
180
  }
@@ -194,82 +188,169 @@ class Flatten extends _transform.default {
194
188
  return;
195
189
  }
196
190
 
197
- defined.forEach(name => {
198
- references.delete(name);
199
- modified.delete(name);
200
- }); // console.log(object.id.name, illegal, references);
191
+ var newFnName = this.getPlaceholder() + "_flat_" + currentFnName;
192
+ var flatObjectName = this.getPlaceholder() + "_flat_object";
201
193
 
202
- var input = Array.from(new Set([...modified, ...references]));
194
+ const getFlatObjectMember = propertyName => {
195
+ return (0, _gen.MemberExpression)((0, _gen.Identifier)(flatObjectName), (0, _gen.Literal)(propertyName), true);
196
+ };
203
197
 
204
- if (Array.from(input).find(x => !definedAbove.has(x))) {
205
- return;
198
+ var getterPropNames = Object.create(null);
199
+ var setterPropNames = Object.create(null);
200
+ var typeofPropNames = Object.create(null);
201
+ var callPropNames = Object.create(null);
202
+
203
+ for (var [o, p, info] of identifierNodes) {
204
+ var identifierName = o.name;
205
+ if (p.find(x => definedMap.has(x) && definedMap.get(x).has(identifierName))) continue;
206
+ (0, _assert.ok)(!info.spec.isDefined);
207
+ var type = info.spec.isModified ? "setter" : "getter";
208
+
209
+ switch (type) {
210
+ case "setter":
211
+ var setterPropName = setterPropNames[identifierName];
212
+
213
+ if (typeof setterPropName === "undefined") {
214
+ // No getter function made yet, make it (Try to re-use getter name if available)
215
+ setterPropName = getterPropNames[identifierName] || (this.isDebug ? "set_" + identifierName : this.gen.generate());
216
+ setterPropNames[identifierName] = setterPropName;
217
+ } // If an update expression, ensure a getter function is also available. Ex: a++
218
+
219
+
220
+ if (p[0].type === "UpdateExpression") {
221
+ getterPropNames[identifierName] = setterPropName;
222
+ } else {
223
+ // If assignment on member expression, ensure a getter function is also available: Ex. myObject.property = ...
224
+ var assignmentIndex = p.findIndex(x => x.type === "AssignmentExpression");
225
+
226
+ if (assignmentIndex !== -1 && p[assignmentIndex].left.type !== "Identifier") {
227
+ getterPropNames[identifierName] = setterPropName;
228
+ }
229
+ } // calls flatObject.set_identifier_value(newValue)
230
+
231
+
232
+ this.replace(o, getFlatObjectMember(setterPropName));
233
+ break;
234
+
235
+ case "getter":
236
+ var getterPropName = getterPropNames[identifierName];
237
+
238
+ if (typeof getterPropName === "undefined") {
239
+ // No getter function made yet, make it (Try to re-use setter name if available)
240
+ getterPropName = setterPropNames[identifierName] || (this.isDebug ? "get_" + identifierName : this.gen.generate());
241
+ getterPropNames[identifierName] = getterPropName;
242
+ } // Typeof expression check
243
+
244
+
245
+ if (p[0].type === "UnaryExpression" && p[0].operator === "typeof" && p[0].argument === o) {
246
+ var typeofPropName = typeofPropNames[identifierName];
247
+
248
+ if (typeof typeofPropName === "undefined") {
249
+ // No typeof getter function made yet, make it (Don't re-use getter/setter names)
250
+ typeofPropName = this.isDebug ? "get_typeof_" + identifierName : this.gen.generate();
251
+ typeofPropNames[identifierName] = typeofPropName;
252
+ } // Replace the entire unary expression not just the identifier node
253
+ // calls flatObject.get_typeof_identifier()
254
+
255
+
256
+ this.replace(p[0], getFlatObjectMember(typeofPropName));
257
+ break;
258
+ } // Bound call-expression check
259
+
260
+
261
+ if (p[0].type === "CallExpression" && p[0].callee === o) {
262
+ var callPropName = callPropNames[identifierName];
263
+
264
+ if (typeof callPropName === "undefined") {
265
+ callPropName = this.isDebug ? "call_" + identifierName : this.gen.generate();
266
+ callPropNames[identifierName] = callPropName;
267
+ } // Replace the entire call expression not just the identifier node
268
+ // calls flatObject.call_identifier(...arguments)
269
+
270
+
271
+ this.replace(p[0], (0, _gen.CallExpression)(getFlatObjectMember(callPropName), p[0].arguments));
272
+ break;
273
+ } // calls flatObject.get_identifier_value()
274
+
275
+
276
+ this.replace(o, getFlatObjectMember(getterPropName));
277
+ break;
278
+ }
279
+ } // Create the getter and setter functions
280
+
281
+
282
+ var flatObjectProperties = []; // Getter functions
283
+
284
+ for (var identifierName in getterPropNames) {
285
+ var getterPropName = getterPropNames[identifierName];
286
+ flatObjectProperties.push((0, _gen.Property)((0, _gen.Literal)(getterPropName), (0, _gen.FunctionExpression)([], [(0, _gen.ReturnStatement)((0, _gen.Identifier)(identifierName))]), true, "get"));
287
+ } // Get typeof functions
288
+
289
+
290
+ for (var identifierName in typeofPropNames) {
291
+ var typeofPropName = typeofPropNames[identifierName];
292
+ flatObjectProperties.push((0, _gen.Property)((0, _gen.Literal)(typeofPropName), (0, _gen.FunctionExpression)([], [(0, _gen.ReturnStatement)((0, _gen.UnaryExpression)("typeof", (0, _gen.Identifier)(identifierName)))]), true, "get"));
293
+ } // Call functions
294
+
295
+
296
+ for (var identifierName in callPropNames) {
297
+ var callPropName = callPropNames[identifierName];
298
+ var argumentsName = this.getPlaceholder();
299
+ flatObjectProperties.push((0, _gen.Property)((0, _gen.Literal)(callPropName), (0, _gen.FunctionExpression)([(0, _gen.RestElement)((0, _gen.Identifier)(argumentsName))], [(0, _gen.ReturnStatement)((0, _gen.CallExpression)((0, _gen.Identifier)(identifierName), [(0, _gen.SpreadElement)((0, _gen.Identifier)(argumentsName))]))]), true));
300
+ } // Setter functions
301
+
302
+
303
+ for (var identifierName in setterPropNames) {
304
+ var setterPropName = setterPropNames[identifierName];
305
+ var newValueParameterName = this.getPlaceholder();
306
+ flatObjectProperties.push((0, _gen.Property)((0, _gen.Literal)(setterPropName), (0, _gen.FunctionExpression)([(0, _gen.Identifier)(newValueParameterName)], [(0, _gen.ExpressionStatement)((0, _gen.AssignmentExpression)("=", (0, _gen.Identifier)(identifierName), (0, _gen.Identifier)(newValueParameterName)))]), true, "set"));
206
307
  }
207
308
 
208
- var output = Array.from(modified);
209
- var newName = this.getPlaceholder() + "_flat_" + currentFnName;
210
- var resultName = this.getPlaceholder();
211
- var propName = this.gen.generate();
212
- var newOutputNames = Object.create(null);
213
- output.forEach(name => {
214
- newOutputNames[name] = this.gen.generate();
215
- });
216
- var returnOutputName = this.gen.generate();
217
- (0, _insert.getBlockBody)(object.body).push((0, _gen.ReturnStatement)());
218
- (0, _traverse.walk)(object.body, [object, ...parents], (o, p) => {
219
- return () => {
220
- // Change return statements from
221
- // return (argument)
222
- // to
223
- // return [ [modifiedRefs], ]
224
- if (o.type == "ReturnStatement" && (0, _insert.getVarContext)(o, p) === object) {
225
- var returnObject = (0, _gen.ObjectExpression)(output.map(outputName => (0, _gen.Property)((0, _gen.Literal)(newOutputNames[outputName]), (0, _gen.Identifier)(outputName), true)));
226
-
227
- if (o.argument && !(o.argument.type == "Identifier" && o.argument.name == "undefined")) {
228
- returnObject.properties.push((0, _gen.Property)((0, _gen.Literal)(returnOutputName), (0, _insert.clone)(o.argument), true));
229
- }
309
+ if (!this.isDebug) {
310
+ (0, _random.shuffle)(flatObjectProperties);
311
+ }
312
+
313
+ var newBody = (0, _insert.getBlockBody)(object.body); // Remove 'use strict' directive
314
+
315
+ if (newBody.length > 0 && newBody[0].directive) {
316
+ newBody.shift();
317
+ }
230
318
 
231
- o.argument = (0, _gen.AssignmentExpression)("=", (0, _gen.MemberExpression)((0, _gen.Identifier)(resultName), (0, _gen.Identifier)(propName), false), returnObject);
319
+ var newFunctionDeclaration = (0, _gen.FunctionDeclaration)(newFnName, [(0, _gen.ArrayPattern)((0, _insert.clone)(object.params)), (0, _gen.Identifier)(flatObjectName)], newBody);
320
+ newFunctionDeclaration.async = !!object.async;
321
+ newFunctionDeclaration.generator = false;
322
+ this.flattenedFns.push(newFunctionDeclaration);
323
+ var argumentsName = this.getPlaceholder(); // newFn.call([...arguments], flatObject)
324
+
325
+ var callExpression = (0, _gen.CallExpression)((0, _gen.Identifier)(newFnName), [(0, _gen.Identifier)(argumentsName), (0, _gen.Identifier)(flatObjectName)]);
326
+ var newObjectBody = [// var flatObject = { get(), set() };
327
+ (0, _gen.VariableDeclaration)([(0, _gen.VariableDeclarator)(flatObjectName, (0, _gen.ObjectExpression)(flatObjectProperties))]), (0, _gen.ReturnStatement)(newFunctionDeclaration.async ? (0, _gen.AwaitExpression)(callExpression) : callExpression)];
328
+ object.body = (0, _gen.BlockStatement)(newObjectBody); // Preserve function.length property
329
+
330
+ var originalFunctionLength = (0, _insert.computeFunctionLength)(object.params);
331
+ object.params = [(0, _gen.SpreadElement)((0, _gen.Identifier)(argumentsName))];
332
+
333
+ if (originalFunctionLength !== 0) {
334
+ if (!this.functionLengthName) {
335
+ this.functionLengthName = this.getPlaceholder();
336
+ (0, _insert.prepend)(parents[parents.length - 1] || object, _functionLength.FunctionLengthTemplate.single({
337
+ name: this.functionLengthName
338
+ }));
339
+ }
340
+
341
+ if (object.type === "FunctionDeclaration") {
342
+ var body = parents[0];
343
+
344
+ if (Array.isArray(body)) {
345
+ var index = body.indexOf(object);
346
+ body.splice(index + 1, 0, (0, _gen.ExpressionStatement)((0, _gen.CallExpression)((0, _gen.Identifier)(this.functionLengthName), [(0, _gen.Identifier)(object.id.name), (0, _gen.Literal)(originalFunctionLength)])));
232
347
  }
233
- };
234
- });
235
- var newBody = (0, _insert.getBlockBody)(object.body);
236
- var newFunctionExpression = (0, _gen.FunctionExpression)([(0, _gen.ArrayPattern)(input.map(_gen.Identifier)), (0, _gen.ArrayPattern)((0, _insert.clone)(object.params)), (0, _gen.Identifier)(resultName)], newBody);
237
- newFunctionExpression.async = !!object.async;
238
- newFunctionExpression.generator = !!object.generator;
239
- var property = (0, _gen.Property)((0, _gen.Identifier)(newName), newFunctionExpression, false);
240
- property.kind = "set";
241
- this.flattenedFns.push((0, _gen.VariableDeclarator)(newName, newFunctionExpression));
242
- var newParamNodes = object.params.map(() => (0, _gen.Identifier)(this.getPlaceholder())); // result.pop()
243
-
244
- var getOutputMemberExpression = outputName => (0, _gen.MemberExpression)((0, _gen.MemberExpression)((0, _gen.Identifier)(resultName), (0, _gen.Literal)(propName), true), (0, _gen.Literal)(outputName), true); // newFn.call([...refs], ...arguments, resultObject)
245
-
246
-
247
- var callExpression = (0, _gen.CallExpression)((0, _gen.Identifier)(newName), [(0, _gen.ArrayExpression)(input.map(_gen.Identifier)), (0, _gen.ArrayExpression)([...newParamNodes]), (0, _gen.Identifier)(resultName)]);
248
- var newObjectBody = [// var resultObject = {};
249
- (0, _gen.VariableDeclaration)([(0, _gen.VariableDeclarator)(resultName, (0, _gen.ObjectExpression)([]))]), (0, _gen.ExpressionStatement)(newFunctionExpression.async ? (0, _gen.AwaitExpression)(callExpression) : callExpression)];
250
- var outputReversed = [...output].reverse(); // realVar
251
-
252
- outputReversed.forEach(outputName => {
253
- newObjectBody.push((0, _gen.ExpressionStatement)((0, _gen.AssignmentExpression)("=", (0, _gen.Identifier)(outputName), getOutputMemberExpression(newOutputNames[outputName]))));
254
- }); // DECOY STATEMENTS
255
-
256
- var decoyKey = this.gen.generate();
257
- var decoyNodes = [// if (result.random) throw result.prop.random
258
- (0, _gen.IfStatement)((0, _gen.MemberExpression)((0, _gen.Identifier)(resultName), (0, _gen.Literal)(this.gen.generate()), true), [(0, _gen.ThrowStatement)((0, _gen.NewExpression)((0, _gen.Identifier)("Error"), [getOutputMemberExpression(this.gen.generate())]))]), // if (result.random) return true;
259
- (0, _gen.IfStatement)((0, _gen.MemberExpression)((0, _gen.Identifier)(resultName), (0, _gen.Literal)(this.gen.generate()), true), [(0, _gen.ReturnStatement)((0, _gen.Literal)(true))]), // if (result.random) return result;
260
- (0, _gen.IfStatement)((0, _gen.MemberExpression)((0, _gen.Identifier)(resultName), (0, _gen.Literal)(this.gen.generate()), true), [(0, _gen.ReturnStatement)((0, _gen.Identifier)(resultName))]), // if (result.random) return result.random;
261
- (0, _gen.IfStatement)((0, _gen.MemberExpression)((0, _gen.Identifier)(resultName), (0, _gen.Literal)(decoyKey), true), [(0, _gen.ReturnStatement)((0, _gen.MemberExpression)((0, _gen.Identifier)(resultName), (0, _gen.Literal)(decoyKey), true))]), // if(result.random1) return result.random2;
262
- (0, _gen.IfStatement)((0, _gen.MemberExpression)((0, _gen.Identifier)(resultName), (0, _gen.Literal)(this.gen.generate()), true), [(0, _gen.ReturnStatement)((0, _gen.MemberExpression)((0, _gen.Identifier)(resultName), (0, _gen.Literal)(this.gen.generate()), true))]), // if(result.random) return flatFn;
263
- (0, _gen.IfStatement)((0, _gen.MemberExpression)((0, _gen.Identifier)(resultName), (0, _gen.Literal)(this.gen.generate()), true), [(0, _gen.ReturnStatement)((0, _gen.Identifier)(newName))]), // if(result.random) flatFn = undefined;
264
- (0, _gen.IfStatement)((0, _gen.MemberExpression)((0, _gen.Identifier)(resultName), (0, _gen.Literal)(this.gen.generate()), true), [(0, _gen.ExpressionStatement)((0, _gen.AssignmentExpression)("=", (0, _gen.Identifier)(newName), (0, _gen.Identifier)("undefined")))]), // if(!result) return;
265
- (0, _gen.IfStatement)((0, _gen.UnaryExpression)("!", (0, _gen.Identifier)(resultName)), [(0, _gen.ReturnStatement)()])].filter(() => Math.random() > 0.25); // if (result.output) return result.output.returnValue;
266
- // this is the real return statement, it is always added
267
-
268
- decoyNodes.push((0, _gen.IfStatement)((0, _gen.MemberExpression)((0, _gen.Identifier)(resultName), (0, _gen.Literal)(propName), true), [(0, _gen.ReturnStatement)(getOutputMemberExpression(returnOutputName))]));
269
- (0, _random.shuffle)(decoyNodes);
270
- newObjectBody.push(...decoyNodes);
271
- object.body = (0, _gen.BlockStatement)(newObjectBody);
272
- object.params = newParamNodes;
348
+ } else {
349
+ (0, _assert.ok)(object.type === "FunctionExpression");
350
+ this.replace(object, (0, _gen.CallExpression)((0, _gen.Identifier)(this.functionLengthName), [{ ...object
351
+ }, (0, _gen.Literal)(originalFunctionLength)]));
352
+ }
353
+ }
273
354
  };
274
355
  }
275
356
 
@@ -0,0 +1,88 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+
8
+ var _constants = require("../../constants");
9
+
10
+ var _identifiers = require("../../util/identifiers");
11
+
12
+ var _transform = _interopRequireDefault(require("../transform"));
13
+
14
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
15
+
16
+ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
17
+
18
+ /**
19
+ * Global Analysis is responsible for finding all the global variables used in the code.
20
+ *
21
+ * A 'global variable' is one that is:
22
+ * - Referenced
23
+ * - Never defined or overridden
24
+ */
25
+ class GlobalAnalysis extends _transform.default {
26
+ constructor(o) {
27
+ super(o);
28
+
29
+ _defineProperty(this, "notGlobals", void 0);
30
+
31
+ _defineProperty(this, "globals", void 0);
32
+
33
+ this.globals = Object.create(null);
34
+ this.notGlobals = new Set();
35
+ }
36
+
37
+ match(object, parents) {
38
+ return object.type == "Identifier" && !_constants.reservedKeywords.has(object.name);
39
+ }
40
+
41
+ transform(object, parents) {
42
+ // no touching `import()` or `import x from ...`
43
+ var importIndex = parents.findIndex(x => x.type == "ImportExpression" || x.type == "ImportDeclaration");
44
+
45
+ if (importIndex !== -1) {
46
+ if (parents[importIndex].source === (parents[importIndex - 1] || object)) {
47
+ return;
48
+ }
49
+ }
50
+
51
+ var info = (0, _identifiers.getIdentifierInfo)(object, parents);
52
+
53
+ if (!info.spec.isReferenced) {
54
+ return;
55
+ } // Cannot be defined or overridden
56
+
57
+
58
+ if (info.spec.isDefined || info.spec.isModified) {
59
+ delete this.globals[object.name];
60
+ this.notGlobals.add(object.name);
61
+ return;
62
+ } // Add to globals
63
+
64
+
65
+ if (!this.notGlobals.has(object.name)) {
66
+ if (!this.globals[object.name]) {
67
+ this.globals[object.name] = [];
68
+ }
69
+
70
+ this.globals[object.name].push([object, parents]);
71
+ }
72
+
73
+ var assignmentIndex = parents.findIndex(x => x.type == "AssignmentExpression");
74
+ var updateIndex = parents.findIndex(x => x.type == "UpdateExpression");
75
+
76
+ if (assignmentIndex != -1 && parents[assignmentIndex].left === (parents[assignmentIndex - 1] || object) || updateIndex != -1) {
77
+ var memberIndex = parents.findIndex(x => x.type == "MemberExpression");
78
+
79
+ if (memberIndex == -1 || memberIndex > (assignmentIndex == -1 ? assignmentIndex : updateIndex)) {
80
+ delete this.globals[object.name];
81
+ this.notGlobals.add(object.name);
82
+ }
83
+ }
84
+ }
85
+
86
+ }
87
+
88
+ exports.default = GlobalAnalysis;