js-confuser 1.5.8 → 1.6.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 (139) hide show
  1. package/.github/workflows/node.js.yml +2 -2
  2. package/CHANGELOG.md +69 -0
  3. package/README.md +143 -7
  4. package/dist/index.js +33 -4
  5. package/dist/obfuscator.js +30 -31
  6. package/dist/options.js +4 -5
  7. package/dist/order.js +4 -6
  8. package/dist/probability.js +2 -4
  9. package/dist/templates/bufferToString.js +13 -0
  10. package/dist/templates/crash.js +2 -2
  11. package/dist/templates/es5.js +18 -0
  12. package/dist/transforms/antiTooling.js +1 -1
  13. package/dist/transforms/calculator.js +77 -21
  14. package/dist/transforms/controlFlowFlattening/controlFlowFlattening.js +980 -367
  15. package/dist/transforms/controlFlowFlattening/expressionObfuscation.js +8 -3
  16. package/dist/transforms/controlFlowFlattening/switchCaseObfuscation.js +25 -26
  17. package/dist/transforms/deadCode.js +33 -25
  18. package/dist/transforms/dispatcher.js +7 -6
  19. package/dist/transforms/es5/antiClass.js +6 -2
  20. package/dist/transforms/es5/antiDestructuring.js +3 -1
  21. package/dist/transforms/es5/es5.js +31 -34
  22. package/dist/transforms/eval.js +11 -0
  23. package/dist/transforms/extraction/duplicateLiteralsRemoval.js +8 -5
  24. package/dist/transforms/extraction/objectExtraction.js +6 -1
  25. package/dist/transforms/finalizer.js +82 -0
  26. package/dist/transforms/flatten.js +82 -55
  27. package/dist/transforms/hexadecimalNumbers.js +34 -9
  28. package/dist/transforms/identifier/globalAnalysis.js +88 -0
  29. package/dist/transforms/identifier/globalConcealing.js +10 -83
  30. package/dist/transforms/identifier/movedDeclarations.js +2 -8
  31. package/dist/transforms/identifier/renameVariables.js +39 -27
  32. package/dist/transforms/identifier/variableAnalysis.js +58 -62
  33. package/dist/transforms/minify.js +80 -61
  34. package/dist/transforms/opaquePredicates.js +1 -1
  35. package/dist/transforms/preparation/preparation.js +2 -2
  36. package/dist/transforms/preparation.js +231 -0
  37. package/dist/transforms/renameLabels.js +1 -1
  38. package/dist/transforms/rgf.js +4 -5
  39. package/dist/transforms/stack.js +87 -26
  40. package/dist/transforms/string/encoding.js +150 -179
  41. package/dist/transforms/string/stringCompression.js +14 -15
  42. package/dist/transforms/string/stringConcealing.js +25 -8
  43. package/dist/transforms/string/stringEncoding.js +13 -24
  44. package/dist/transforms/transform.js +11 -18
  45. package/dist/traverse.js +24 -18
  46. package/dist/util/compare.js +2 -2
  47. package/dist/util/gen.js +15 -0
  48. package/dist/util/insert.js +31 -7
  49. package/dist/util/random.js +15 -0
  50. package/package.json +5 -5
  51. package/src/index.ts +57 -19
  52. package/src/obfuscator.ts +26 -29
  53. package/src/options.ts +17 -21
  54. package/src/order.ts +4 -8
  55. package/src/probability.ts +2 -3
  56. package/src/templates/bufferToString.ts +68 -0
  57. package/src/templates/crash.ts +5 -9
  58. package/src/templates/es5.ts +131 -0
  59. package/src/transforms/antiTooling.ts +1 -1
  60. package/src/transforms/calculator.ts +122 -59
  61. package/src/transforms/controlFlowFlattening/controlFlowFlattening.ts +1583 -571
  62. package/src/transforms/controlFlowFlattening/expressionObfuscation.ts +18 -3
  63. package/src/transforms/deadCode.ts +383 -26
  64. package/src/transforms/dispatcher.ts +8 -6
  65. package/src/transforms/es5/antiClass.ts +10 -1
  66. package/src/transforms/es5/antiDestructuring.ts +3 -1
  67. package/src/transforms/es5/es5.ts +32 -77
  68. package/src/transforms/eval.ts +18 -0
  69. package/src/transforms/extraction/duplicateLiteralsRemoval.ts +9 -6
  70. package/src/transforms/extraction/objectExtraction.ts +12 -5
  71. package/src/transforms/finalizer.ts +75 -0
  72. package/src/transforms/flatten.ts +194 -151
  73. package/src/transforms/identifier/globalAnalysis.ts +85 -0
  74. package/src/transforms/identifier/globalConcealing.ts +14 -103
  75. package/src/transforms/identifier/movedDeclarations.ts +4 -11
  76. package/src/transforms/identifier/renameVariables.ts +37 -30
  77. package/src/transforms/identifier/variableAnalysis.ts +66 -73
  78. package/src/transforms/minify.ts +116 -77
  79. package/src/transforms/opaquePredicates.ts +2 -2
  80. package/src/transforms/preparation.ts +238 -0
  81. package/src/transforms/renameLabels.ts +2 -2
  82. package/src/transforms/rgf.ts +6 -7
  83. package/src/transforms/stack.ts +97 -37
  84. package/src/transforms/string/encoding.ts +115 -212
  85. package/src/transforms/string/stringCompression.ts +27 -18
  86. package/src/transforms/string/stringConcealing.ts +41 -11
  87. package/src/transforms/string/stringEncoding.ts +18 -18
  88. package/src/transforms/transform.ts +15 -21
  89. package/src/traverse.ts +24 -12
  90. package/src/types.ts +11 -2
  91. package/src/util/compare.ts +2 -2
  92. package/src/util/gen.ts +21 -1
  93. package/src/util/insert.ts +49 -9
  94. package/src/util/random.ts +13 -0
  95. package/test/code/Cash.test.ts +1 -1
  96. package/test/code/Dynamic.test.ts +12 -10
  97. package/test/code/ES6.src.js +136 -0
  98. package/test/code/ES6.test.ts +28 -2
  99. package/test/code/NewFeatures.test.ts +19 -0
  100. package/test/index.test.ts +15 -2
  101. package/test/probability.test.ts +44 -0
  102. package/test/templates/template.test.ts +1 -1
  103. package/test/transforms/antiTooling.test.ts +52 -0
  104. package/test/transforms/calculator.test.ts +40 -0
  105. package/test/transforms/controlFlowFlattening/controlFlowFlattening.test.ts +713 -149
  106. package/test/transforms/controlFlowFlattening/expressionObfuscation.test.ts +173 -0
  107. package/test/transforms/deadCode.test.ts +66 -15
  108. package/test/transforms/dispatcher.test.ts +44 -1
  109. package/test/transforms/es5/antiClass.test.ts +33 -0
  110. package/test/transforms/es5/antiDestructuring.test.ts +16 -0
  111. package/test/transforms/eval.test.ts +53 -0
  112. package/test/transforms/extraction/objectExtraction.test.ts +21 -0
  113. package/test/transforms/flatten.test.ts +195 -3
  114. package/test/transforms/identifier/movedDeclarations.test.ts +27 -0
  115. package/test/transforms/identifier/renameVariables.test.ts +108 -0
  116. package/test/transforms/lock/antiDebug.test.ts +2 -2
  117. package/test/transforms/minify.test.ts +151 -0
  118. package/test/transforms/preparation.test.ts +157 -0
  119. package/test/transforms/rgf.test.ts +56 -29
  120. package/test/transforms/stack.test.ts +91 -21
  121. package/test/transforms/string/stringCompression.test.ts +39 -0
  122. package/test/transforms/string/stringConcealing.test.ts +115 -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/compare.test.ts +23 -1
  127. package/src/transforms/controlFlowFlattening/choiceFlowObfuscation.ts +0 -87
  128. package/src/transforms/controlFlowFlattening/controlFlowObfuscation.ts +0 -203
  129. package/src/transforms/controlFlowFlattening/switchCaseObfuscation.ts +0 -130
  130. package/src/transforms/hexadecimalNumbers.ts +0 -31
  131. package/src/transforms/hideInitializingCode.ts +0 -432
  132. package/src/transforms/label.ts +0 -64
  133. package/src/transforms/preparation/nameConflicts.ts +0 -102
  134. package/src/transforms/preparation/preparation.ts +0 -176
  135. package/test/transforms/controlFlowFlattening/controlFlowObfuscation.test.ts +0 -101
  136. package/test/transforms/controlFlowFlattening/switchCaseObfuscation.test.ts +0 -120
  137. package/test/transforms/hideInitializingCode.test.ts +0 -336
  138. package/test/transforms/preparation/nameConflicts.test.ts +0 -52
  139. package/test/transforms/preparation/preparation.test.ts +0 -62
@@ -13,6 +13,9 @@ var _transform = _interopRequireDefault(require("../transform"));
13
13
 
14
14
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
15
15
 
16
+ /**
17
+ * Expression Obfuscation runs before Control Flow Flattening
18
+ */
16
19
  class ExpressionObfuscation extends _transform.default {
17
20
  constructor(o) {
18
21
  super(o);
@@ -27,10 +30,11 @@ class ExpressionObfuscation extends _transform.default {
27
30
  var exprs = [];
28
31
  var deleteExprs = [];
29
32
  object.body.forEach((stmt, i) => {
30
- if (stmt.type == "ExpressionStatement") {
33
+ if (stmt.type == "ExpressionStatement" && !stmt.directive) {
31
34
  var expr = stmt.expression;
32
35
 
33
- if (expr.type == "UnaryExpression" && exprs.length) {
36
+ if (expr.type == "UnaryExpression" && !(expr.operator === "typeof" && expr.argument.type === "Identifier") && exprs.length // typeof is special
37
+ ) {
34
38
  expr.argument = (0, _gen.SequenceExpression)([...exprs, { ...expr.argument
35
39
  }]);
36
40
  deleteExprs.push(...exprs);
@@ -42,7 +46,8 @@ class ExpressionObfuscation extends _transform.default {
42
46
  if (exprs.length) {
43
47
  if (stmt.type == "IfStatement") {
44
48
  if (stmt.test.type == "BinaryExpression" && stmt.test.operator !== "**") {
45
- if (stmt.test.left.type == "UnaryExpression") {
49
+ if (stmt.test.left.type == "UnaryExpression" && !(stmt.test.left.operator === "typeof" && stmt.test.left.argument.type === "Identifier") // typeof is special
50
+ ) {
46
51
  stmt.test.left.argument = (0, _gen.SequenceExpression)([...exprs, { ...stmt.test.left.argument
47
52
  }]);
48
53
  } else {
@@ -28,22 +28,23 @@ class SwitchCaseObfuscation extends _transform.default {
28
28
  }
29
29
 
30
30
  match(object, parents) {
31
- return object.type == "SwitchStatement" && !object.cases.find(x => !(x.test && typeof x.test === "object" && x.test.type == "Literal" && typeof x.test.value === "number" && Math.abs(x.test.value) < 100000));
31
+ return object.type == "SwitchStatement" && (object.$controlFlowFlattening || !object.cases.find(x => !(x.test && typeof x.test === "object" && x.test.type == "Literal" && typeof x.test.value === "number" && Math.abs(x.test.value) < 100000)));
32
32
  }
33
33
 
34
34
  transform(object, parents) {
35
35
  var types = new Set();
36
36
  (0, _traverse.walk)(object.discriminant, [object, ...parents], (o, p) => {
37
37
  if (o.type) {
38
- if (object.$controlFlowFlattening && o.type == "BinaryExpression" && o.operator === "+") {} else {
39
- types.add(o.type);
40
- }
38
+ types.add(o.type);
41
39
  }
42
40
  });
43
- types.delete("Identifier");
44
41
 
45
- if (types.size) {
46
- return;
42
+ if (!object.$controlFlowFlattening) {
43
+ types.delete("Identifier");
44
+
45
+ if (types.size) {
46
+ return;
47
+ }
47
48
  }
48
49
 
49
50
  var body = parents[0];
@@ -64,33 +65,25 @@ class SwitchCaseObfuscation extends _transform.default {
64
65
  return;
65
66
  }
66
67
 
67
- var factor = (0, _random.getRandomInteger)(-150, 150);
68
-
69
- if (factor == 0) {
70
- factor = 2;
71
- }
72
-
68
+ var factor = (0, _random.getRandomInteger)(2, 100);
73
69
  var offset = (0, _random.getRandomInteger)(-250, 250);
74
70
  var newVar = this.getPlaceholder();
75
71
  var newStates = [];
76
72
  var max;
77
- object.cases.forEach(x => {
78
- var current = x.test.value;
79
- var value = current * factor + offset;
80
- newStates.push(value);
81
-
82
- if (!max || Math.abs(value) > max) {
83
- max = Math.abs(value);
73
+ object.cases.forEach((caseObject, i) => {
74
+ if (caseObject.test && caseObject.test.type === "Literal" && typeof caseObject.test.value === "number") {
75
+ var current = caseObject.test.value;
76
+ var value = current * factor + offset;
77
+ newStates[i] = value;
78
+
79
+ if (!max || Math.abs(value) > max) {
80
+ max = Math.abs(value);
81
+ }
84
82
  }
85
83
  });
86
84
 
87
85
  if (max > 100000) {
88
86
  return;
89
- }
90
-
91
- if (new Set(newStates).size !== newStates.length) {
92
- // not possible because of clashing case test
93
- return;
94
87
  } // State variable declaration
95
88
 
96
89
 
@@ -98,7 +91,13 @@ class SwitchCaseObfuscation extends _transform.default {
98
91
  object.discriminant = (0, _gen.Identifier)(newVar); // possible so override
99
92
 
100
93
  object.cases.forEach((x, i) => {
101
- x.test = (0, _gen.Literal)(newStates[i]);
94
+ if (x.test) {
95
+ if (x.test.type === "Literal" && typeof x.test.value === "number") {
96
+ x.test = (0, _gen.Literal)(newStates[i]);
97
+ } else {
98
+ x.test = (0, _gen.BinaryExpression)("+", (0, _gen.BinaryExpression)("*", x.test, (0, _gen.Literal)(factor)), (0, _gen.Literal)(offset));
99
+ }
100
+ }
102
101
  });
103
102
  }
104
103
 
@@ -25,7 +25,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de
25
25
 
26
26
  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; }
27
27
 
28
- const templates = [(0, _template.default)("\n function curCSS( elem, name, computed ) {\n var ret;\n \n computed = computed || getStyles( elem );\n \n if ( computed ) {\n ret = computed.getPropertyValue( name ) || computed[ name ];\n \n if ( ret === \"\" && !isAttached( elem ) ) {\n ret = redacted.style( elem, name );\n }\n }\n \n return ret !== undefined ?\n \n // Support: IE <=9 - 11+\n // IE returns zIndex value as an integer.\n ret + \"\" :\n ret;\n }"), (0, _template.default)("\n function Example() {\n var state = redacted.useState(false);\n return x(\n ErrorBoundary,\n null,\n x(\n DisplayName,\n null,\n )\n );\n }"), (0, _template.default)("\n const path = require('path');\nconst { version } = require('../../package');\nconst { version: dashboardPluginVersion } = require('@redacted/enterprise-plugin/package');\nconst { version: componentsVersion } = require('@redacted/components/package');\nconst { sdkVersion } = require('@redacted/enterprise-plugin');\nconst isStandaloneExecutable = require('../utils/isStandaloneExecutable');\nconst resolveLocalRedactedPath = require('./resolve-local-redacted-path');\n\nconst redactedPath = path.resolve(__dirname, '../redacted.js');"), (0, _template.default)("\nmodule.exports = async (resolveLocalRedactedPath = ()=>{throw new Error(\"No redacted path provided\")}) => {\n const cliParams = new Set(process.argv.slice(2));\n if (!cliParams.has('--version')) {\n if (cliParams.size !== 1) return false;\n if (!cliParams.has('-v')) return false;\n }\n\n const installationModePostfix = await (async (isStandaloneExecutable, redactedPath) => {\n if (isStandaloneExecutable) return ' (standalone)';\n if (redactedPath === (await resolveLocalRedactedPath())) return ' (local)';\n return '';\n })();\n\n return true;\n};"), (0, _template.default)("\nfunction setCookie(cname, cvalue, exdays) {\n var d = new Date();\n d.setTime(d.getTime() + (exdays*24*60*60*1000));\n var expires = \"expires=\"+ d.toUTCString();\n document.cookie = cname + \"=\" + cvalue + \";\" + expires + \";path=/\";\n}"), (0, _template.default)("function getCookie(cname) {\n var name = cname + \"=\";\n var decodedCookie = decodeURIComponent(document.cookie);\n var ca = decodedCookie.split(';');\n for(var i = 0; i <ca.length; i++) {\n var c = ca[i];\n while (c.charAt(0) == ' ') {\n c = c.substring(1);\n }\n if (c.indexOf(name) == 0) {\n return c.substring(name.length, c.length);\n }\n }\n return \"\";\n}"), (0, _template.default)("function getLocalStorageValue(key, cb){\n if ( typeof key !== \"string\" ) {\n throw new Error(\"Invalid data key provided (not type string)\")\n }\n if ( !key ) {\n throw new Error(\"Invalid data key provided (empty string)\")\n }\n var value = window.localStorage.getItem(key)\n try {\n value = JSON.parse(value)\n } catch ( e ) {\n cb(new Error(\"Serialization error for data '\" + key + \"': \" + e.message))\n }\n\n cb(null, value)\n }"), (0, _template.default)("\n \n var __ = \"(c=ak(<~F$VU'9f)~><&85dBPL-module/from\";\n var s = \"q:function(){var ad=ad=>b(ad-29);if(!T.r[(typeof ab==ad(123)?\";\n var g = \"return U[c[c[d(-199)]-b(205)]]||V[ae(b(166))];case T.o[c[c[c[d(-199)]+d(-174)]-(c[b(119)]-(c[d(-199)]-163))]+ae(b(146))](0)==b(167)?d(-130):-d(-144)\";\n\n __.match(s + g);\n "), (0, _template.default)("\n function vec_pack(vec) {\n return vec[1] * 67108864 + (vec[0] < 0 ? 33554432 | vec[0] : vec[0]);\n }\n \n function vec_unpack(number) {\n switch (((number & 33554432) !== 0) * 1 + (number < 0) * 2) {\n case 0:\n return [number % 33554432, Math.trunc(number / 67108864)];\n case 1:\n return [\n (number % 33554432) - 33554432,\n Math.trunc(number / 67108864) + 1,\n ];\n case 2:\n return [\n (((number + 33554432) % 33554432) + 33554432) % 33554432,\n Math.round(number / 67108864),\n ];\n case 3:\n return [number % 33554432, Math.trunc(number / 67108864)];\n }\n }\n \n let a = vec_pack([2, 4]);\n let b = vec_pack([1, 2]);\n \n let c = a + b; // Vector addition\n let d = c - b; // Vector subtraction\n let e = d * 2; // Scalar multiplication\n let f = e / 2; // Scalar division\n \n console.log(vec_unpack(c)); // [3, 6]\n console.log(vec_unpack(d)); // [2, 4]\n console.log(vec_unpack(e)); // [4, 8]\n console.log(vec_unpack(f)); // [2, 4]\n "), (0, _template.default)("\n function buildCharacterMap(str) {\n const characterMap = {};\n \n for (let char of str.replace(/[^w]/g, \"\").toLowerCase())\n characterMap[char] = characterMap[char] + 1 || 1;\n \n return characterMap;\n }\n \n function isAnagrams(stringA, stringB) {\n const stringAMap = buildCharMap(stringA);\n const stringBMap = buildCharMap(stringB);\n \n for (let char in stringAMap) {\n if (stringAMap[char] !== stringBMap[char]) {\n return false;\n }\n }\n \n if (Object.keys(stringAMap).length !== Object.keys(stringBMap).length) {\n return false;\n }\n \n return true;\n }\n \n /**\n * @param {TreeNode} root\n * @return {boolean}\n */\n function isBalanced(root) {\n const height = getHeightBalanced(root);\n return height !== Infinity;\n }\n \n function getHeightBalanced(node) {\n if (!node) {\n return -1;\n }\n \n const leftTreeHeight = getHeightBalanced(node.left);\n const rightTreeHeight = getHeightBalanced(node.right);\n \n const heightDiff = Math.abs(leftTreeHeight - rightTreeHeight);\n \n if (\n leftTreeHeight === Infinity ||\n rightTreeHeight === Infinity ||\n heightDiff > 1\n ) {\n return Infinity;\n }\n \n const currentHeight = Math.max(leftTreeHeight, rightTreeHeight) + 1;\n return currentHeight;\n }\n \n window[\"__GLOBAL__HELPERS__\"] = {\n buildCharacterMap,\n isAnagrams,\n isBalanced,\n getHeightBalanced,\n };\n ")];
28
+ const templates = [(0, _template.default)("\n function curCSS( elem, name, computed ) {\n var ret;\n \n computed = computed || getStyles( elem );\n \n if ( computed ) {\n ret = computed.getPropertyValue( name ) || computed[ name ];\n \n if ( ret === \"\" && !isAttached( elem ) ) {\n ret = redacted.style( elem, name );\n }\n }\n \n return ret !== undefined ?\n \n // Support: IE <=9 - 11+\n // IE returns zIndex value as an integer.\n ret + \"\" :\n ret;\n }"), (0, _template.default)("\n function Example() {\n var state = redacted.useState(false);\n return x(\n ErrorBoundary,\n null,\n x(\n DisplayName,\n null,\n )\n );\n }"), (0, _template.default)("\n const path = require('path');\nconst { version } = require('../../package');\nconst { version: dashboardPluginVersion } = require('@redacted/enterprise-plugin/package');\nconst { version: componentsVersion } = require('@redacted/components/package');\nconst { sdkVersion } = require('@redacted/enterprise-plugin');\nconst isStandaloneExecutable = require('../utils/isStandaloneExecutable');\nconst resolveLocalRedactedPath = require('./resolve-local-redacted-path');\n\nconst redactedPath = path.resolve(__dirname, '../redacted.js');"), (0, _template.default)("\nmodule.exports = async (resolveLocalRedactedPath = ()=>{throw new Error(\"No redacted path provided\")}) => {\n const cliParams = new Set(process.argv.slice(2));\n if (!cliParams.has('--version')) {\n if (cliParams.size !== 1) return false;\n if (!cliParams.has('-v')) return false;\n }\n\n const installationModePostfix = await (async (isStandaloneExecutable, redactedPath) => {\n if (isStandaloneExecutable) return ' (standalone)';\n if (redactedPath === (await resolveLocalRedactedPath())) return ' (local)';\n return '';\n })();\n\n return true;\n};"), (0, _template.default)("\nfunction setCookie(cname, cvalue, exdays) {\n var d = new Date();\n d.setTime(d.getTime() + (exdays*24*60*60*1000));\n var expires = \"expires=\"+ d.toUTCString();\n document.cookie = cname + \"=\" + cvalue + \";\" + expires + \";path=/\";\n}"), (0, _template.default)("function getCookie(cname) {\n var name = cname + \"=\";\n var decodedCookie = decodeURIComponent(document.cookie);\n var ca = decodedCookie.split(';');\n for(var i = 0; i <ca.length; i++) {\n var c = ca[i];\n while (c.charAt(0) == ' ') {\n c = c.substring(1);\n }\n if (c.indexOf(name) == 0) {\n return c.substring(name.length, c.length);\n }\n }\n return \"\";\n}"), (0, _template.default)("function getLocalStorageValue(key, cb){\n if ( typeof key !== \"string\" ) {\n throw new Error(\"Invalid data key provided (not type string)\")\n }\n if ( !key ) {\n throw new Error(\"Invalid data key provided (empty string)\")\n }\n var value = window.localStorage.getItem(key)\n try {\n value = JSON.parse(value)\n } catch ( e ) {\n cb(new Error(\"Serialization error for data '\" + key + \"': \" + e.message))\n }\n\n cb(null, value)\n }"), (0, _template.default)("\n \n var __ = \"(c=ak(<~F$VU'9f)~><&85dBPL-module/from\";\n var s = \"q:function(){var ad=ad=>b(ad-29);if(!T.r[(typeof ab==ad(123)?\";\n var g = \"return U[c[c[d(-199)]-b(205)]]||V[ae(b(166))];case T.o[c[c[c[d(-199)]+d(-174)]-(c[b(119)]-(c[d(-199)]-163))]+ae(b(146))](0)==b(167)?d(-130):-d(-144)\";\n\n __.match(s + g);\n "), (0, _template.default)("\n function vec_pack(vec) {\n return vec[1] * 67108864 + (vec[0] < 0 ? 33554432 | vec[0] : vec[0]);\n }\n \n function vec_unpack(number) {\n switch (((number & 33554432) !== 0) * 1 + (number < 0) * 2) {\n case 0:\n return [number % 33554432, Math.trunc(number / 67108864)];\n case 1:\n return [\n (number % 33554432) - 33554432,\n Math.trunc(number / 67108864) + 1,\n ];\n case 2:\n return [\n (((number + 33554432) % 33554432) + 33554432) % 33554432,\n Math.round(number / 67108864),\n ];\n case 3:\n return [number % 33554432, Math.trunc(number / 67108864)];\n }\n }\n \n let a = vec_pack([2, 4]);\n let b = vec_pack([1, 2]);\n \n let c = a + b; // Vector addition\n let d = c - b; // Vector subtraction\n let e = d * 2; // Scalar multiplication\n let f = e / 2; // Scalar division\n \n console.log(vec_unpack(c)); // [3, 6]\n console.log(vec_unpack(d)); // [2, 4]\n console.log(vec_unpack(e)); // [4, 8]\n console.log(vec_unpack(f)); // [2, 4]\n "), (0, _template.default)("\n function buildCharacterMap(str) {\n const characterMap = {};\n \n for (let char of str.replace(/[^w]/g, \"\").toLowerCase())\n characterMap[char] = characterMap[char] + 1 || 1;\n \n return characterMap;\n }\n \n function isAnagrams(stringA, stringB) {\n const stringAMap = buildCharMap(stringA);\n const stringBMap = buildCharMap(stringB);\n \n for (let char in stringAMap) {\n if (stringAMap[char] !== stringBMap[char]) {\n return false;\n }\n }\n \n if (Object.keys(stringAMap).length !== Object.keys(stringBMap).length) {\n return false;\n }\n \n return true;\n }\n \n /**\n * @param {TreeNode} root\n * @return {boolean}\n */\n function isBalanced(root) {\n const height = getHeightBalanced(root);\n return height !== Infinity;\n }\n \n function getHeightBalanced(node) {\n if (!node) {\n return -1;\n }\n \n const leftTreeHeight = getHeightBalanced(node.left);\n const rightTreeHeight = getHeightBalanced(node.right);\n \n const heightDiff = Math.abs(leftTreeHeight - rightTreeHeight);\n \n if (\n leftTreeHeight === Infinity ||\n rightTreeHeight === Infinity ||\n heightDiff > 1\n ) {\n return Infinity;\n }\n \n const currentHeight = Math.max(leftTreeHeight, rightTreeHeight) + 1;\n return currentHeight;\n }\n \n window[\"__GLOBAL__HELPERS__\"] = {\n buildCharacterMap,\n isAnagrams,\n isBalanced,\n getHeightBalanced,\n };\n "), (0, _template.default)("\n function ListNode(){}\n var addTwoNumbers = function(l1, l2) {\n var carry = 0;\n var sum = 0;\n var head = new ListNode(0);\n var now = head;\n var a = l1;\n var b = l2;\n while (a !== null || b !== null) {\n sum = (a ? a.val : 0) + (b ? b.val : 0) + carry;\n carry = Math.floor(sum / 10);\n now.next = new ListNode(sum % 10);\n now = now.next;\n a = a ? a.next : null;\n b = b ? b.next : null;\n }\n if (carry) now.next = new ListNode(carry);\n return head.next;\n };\n\n console.log(addTwoNumbers)\n "), (0, _template.default)("\n var threeSum = function(nums) {\n var len = nums.length;\n var res = [];\n var l = 0;\n var r = 0;\n nums.sort((a, b) => (a - b));\n for (var i = 0; i < len; i++) {\n if (i > 0 && nums[i] === nums[i - 1]) continue;\n l = i + 1;\n r = len - 1;\n while (l < r) {\n if (nums[i] + nums[l] + nums[r] < 0) {\n l++;\n } else if (nums[i] + nums[l] + nums[r] > 0) {\n r--;\n } else {\n res.push([nums[i], nums[l], nums[r]]);\n while (l < r && nums[l] === nums[l + 1]) l++;\n while (l < r && nums[r] === nums[r - 1]) r--;\n l++;\n r--;\n }\n }\n }\n return res;\n };\n console.log(threeSum)\n "), (0, _template.default)("\n var combinationSum2 = function(candidates, target) {\n var res = [];\n var len = candidates.length;\n candidates.sort((a, b) => (a - b));\n dfs(res, [], 0, len, candidates, target);\n return res;\n };\n\n var dfs = function (res, stack, index, len, candidates, target) {\n var tmp = null;\n if (target < 0) return;\n if (target === 0) return res.push(stack);\n for (var i = index; i < len; i++) {\n if (candidates[i] > target) break;\n if (i > index && candidates[i] === candidates[i - 1]) continue;\n tmp = Array.from(stack);\n tmp.push(candidates[i]);\n dfs(res, tmp, i + 1, len, candidates, target - candidates[i]);\n }\n };\n\n console.log(combinationSum2);\n "), (0, _template.default)("\n var isScramble = function(s1, s2) {\n return helper({}, s1, s2);\n };\n \n var helper = function (dp, s1, s2) {\n var map = {};\n \n if (dp[s1 + s2] !== undefined) return dp[s1 + s2];\n if (s1 === s2) return true;\n \n for (var j = 0; j < s1.length; j++) {\n if (map[s1[j]] === undefined) map[s1[j]] = 0;\n if (map[s2[j]] === undefined) map[s2[j]] = 0;\n map[s1[j]]++;\n map[s2[j]]--;\n }\n \n for (var key in map) {\n if (map[key] !== 0) {\n dp[s1 + s2] = false;\n return false;\n }\n }\n \n for (var i = 1; i < s1.length; i++) {\n if ((helper(dp, s1.substr(0, i), s2.substr(0, i))\n && helper(dp, s1.substr(i), s2.substr(i))) ||\n (helper(dp, s1.substr(0, i), s2.substr(s2.length - i))\n && helper(dp, s1.substr(i), s2.substr(0, s2.length - i)))) {\n dp[s1 + s2] = true;\n return true;\n }\n }\n \n dp[s1 + s2] = false;\n return false;\n };\n\n console.log(isScramble);\n "), (0, _template.default)("\n var candy = function(ratings) {\n var len = ratings.length;\n var res = [];\n var sum = 0;\n for (var i = 0; i < len; i++) {\n res.push((i !== 0 && ratings[i] > ratings[i - 1]) ? (res[i - 1] + 1) : 1);\n }\n for (var j = len - 1; j >= 0; j--) {\n if (j !== len - 1 && ratings[j] > ratings[j + 1]) res[j] = Math.max(res[j], res[j + 1] + 1);\n sum += res[j];\n }\n return sum;\n };\n \n console.log(candy)\n "), (0, _template.default)("\n var maxPoints = function(points) {\n var max = 0;\n var map = {};\n var localMax = 0;\n var samePoint = 0;\n var k = 0;\n var len = points.length;\n for (var i = 0; i < len; i++) {\n map = {};\n localMax = 0;\n samePoint = 1;\n for (var j = i + 1; j < len; j++) {\n if (points[i].x === points[j].x && points[i].y === points[j].y) {\n samePoint++;\n continue;\n }\n if (points[i].y === points[j].y) k = Number.MAX_SAFE_INTEGER;\n else k = (points[i].x - points[j].x) / (points[i].y - points[j].y);\n if (!map[k]) map[k] = 0;\n map[k]++;\n localMax = Math.max(localMax, map[k]);\n }\n localMax += samePoint;\n max = Math.max(max, localMax);\n }\n return max;\n };\n \n console.log(maxPoints)\n "), (0, _template.default)("\n var maximumGap = function(nums) {\n var len = nums.length;\n if (len < 2) return 0;\n \n var max = Math.max(...nums);\n var min = Math.min(...nums);\n if (max === min) return 0;\n \n var minBuckets = Array(len - 1).fill(Number.MAX_SAFE_INTEGER);\n var maxBuckets = Array(len - 1).fill(Number.MIN_SAFE_INTEGER);\n var gap = Math.ceil((max - min) / (len - 1));\n var index = 0;\n for (var i = 0; i < len; i++) {\n if (nums[i] === min || nums[i] === max) continue;\n index = Math.floor((nums[i] - min) / gap);\n minBuckets[index] = Math.min(minBuckets[index], nums[i]);\n maxBuckets[index] = Math.max(maxBuckets[index], nums[i]);\n }\n \n var maxGap = Number.MIN_SAFE_INTEGER;\n var preVal = min;\n for (var j = 0; j < len - 1; j++) {\n if (minBuckets[j] === Number.MAX_SAFE_INTEGER && maxBuckets[j] === Number.MIN_SAFE_INTEGER) continue;\n maxGap = Math.max(maxGap, minBuckets[j] - preVal);\n preVal = maxBuckets[j];\n }\n maxGap = Math.max(maxGap, max - preVal);\n \n return maxGap;\n };\n\n console.log(maximumGap);\n "), (0, _template.default)("\n /**\n * @param {number} capacity\n */\n var LRUCache = function(capacity) {\n this.capacity = capacity;\n this.length = 0;\n this.map = {};\n this.head = null;\n this.tail = null;\n };\n \n /** \n * @param {number} key\n * @return {number}\n */\n LRUCache.prototype.get = function(key) {\n var node = this.map[key];\n if (node) {\n this.remove(node);\n this.insert(node.key, node.val);\n return node.val;\n } else {\n return -1;\n }\n };\n \n /** \n * @param {number} key \n * @param {number} value\n * @return {void}\n */\n LRUCache.prototype.put = function(key, value) {\n if (this.map[key]) {\n this.remove(this.map[key]);\n this.insert(key, value);\n } else {\n if (this.length === this.capacity) {\n this.remove(this.head);\n this.insert(key, value);\n } else {\n this.insert(key, value);\n this.length++;\n }\n }\n };\n \n /** \n * Your LRUCache object will be instantiated and called as such:\n * var obj = Object.create(LRUCache).createNew(capacity)\n * var param_1 = obj.get(key)\n * obj.put(key,value)\n */\n \n LRUCache.prototype.remove = function (node) {\n var prev = node.prev;\n var next = node.next;\n if (next) next.prev = prev;\n if (prev) prev.next = next;\n if (this.head === node) this.head = next;\n if (this.tail === node) this.tail = prev;\n delete this.map[node.key];\n };\n \n LRUCache.prototype.insert = function (key, val) {\n var node = new List(key, val);\n if (!this.tail) {\n this.tail = node;\n this.head = node;\n } else {\n this.tail.next = node;\n node.prev = this.tail;\n this.tail = node;\n }\n this.map[key] = node;\n };\n\n console.log(LRUCache);\n "), (0, _template.default)("\n var isInterleave = function(s1, s2, s3) {\n var dp = {};\n if (s3.length !== s1.length + s2.length) return false;\n return helper(s1, s2, s3, 0, 0, 0, dp);\n };\n \n var helper = function (s1, s2, s3, i, j, k, dp) {\n var res = false;\n \n if (k >= s3.length) return true;\n if (dp['' + i + j + k] !== undefined) return dp['' + i + j + k];\n \n if (s3[k] === s1[i] && s3[k] === s2[j]) {\n res = helper(s1, s2, s3, i + 1, j, k + 1, dp) || helper(s1, s2, s3, i, j + 1, k + 1, dp);\n } else if (s3[k] === s1[i]) {\n res = helper(s1, s2, s3, i + 1, j, k + 1, dp);\n } else if (s3[k] === s2[j]) {\n res = helper(s1, s2, s3, i, j + 1, k + 1, dp);\n }\n \n dp['' + i + j + k] = res;\n \n return res;\n };\n\n console.log(isInterleave);\n "), (0, _template.default)("\n var solveNQueens = function(n) {\n var res = [];\n if (n === 1 || n >= 4) dfs(res, [], n, 0);\n return res;\n };\n \n var dfs = function (res, points, n, index) {\n for (var i = index; i < n; i++) {\n if (points.length !== i) return;\n for (var j = 0; j < n; j++) {\n if (isValid(points, [i, j])) {\n points.push([i, j]);\n dfs(res, points, n, i + 1);\n if (points.length === n) res.push(buildRes(points));\n points.pop();\n }\n }\n }\n };\n \n var buildRes = function (points) {\n var res = [];\n var n = points.length;\n for (var i = 0; i < n; i++) {\n res[i] = '';\n for (var j = 0; j < n; j++) {\n res[i] += (points[i][1] === j ? 'Q' : '.');\n }\n }\n return res;\n };\n \n var isValid = function (oldPoints, newPoint) {\n var len = oldPoints.length;\n for (var i = 0; i < len; i++) {\n if (oldPoints[i][0] === newPoint[0] || oldPoints[i][1] === newPoint[1]) return false;\n if (Math.abs((oldPoints[i][0] - newPoint[0]) / (oldPoints[i][1] - newPoint[1])) === 1) return false;\n }\n return true;\n };\n\n console.log(solveNQueens);\n ")];
29
29
  /**
30
30
  * Adds dead code to blocks.
31
31
  *
@@ -37,8 +37,6 @@ class DeadCode extends _transform.default {
37
37
  constructor(o) {
38
38
  super(o, _order.ObfuscateOrder.DeadCode);
39
39
 
40
- _defineProperty(this, "usedNames", void 0);
41
-
42
40
  _defineProperty(this, "made", void 0);
43
41
 
44
42
  this.made = 0;
@@ -49,29 +47,39 @@ class DeadCode extends _transform.default {
49
47
  }
50
48
 
51
49
  transform(object, parents) {
52
- if ((0, _probability.ComputeProbabilityMap)(this.options.deadCode)) {
53
- return () => {
54
- this.made++;
55
-
56
- if (this.made > 100) {
57
- return;
58
- }
59
-
60
- var name = this.getPlaceholder();
61
- var variableDeclaration = (0, _gen.VariableDeclaration)((0, _gen.VariableDeclarator)(name, (0, _gen.Literal)(false)));
62
- var body = (0, _insert.getBlockBody)(object);
63
- var index = (0, _random.getRandomInteger)(0, body.length);
64
- var template;
65
-
66
- do {
67
- template = (0, _random.choice)(templates);
68
- } while (this.options.es5 && template.source.includes("async"));
69
-
70
- var ifStatement = (0, _gen.IfStatement)((0, _gen.Identifier)(name), template.compile(), null);
71
- body.splice(index, 0, ifStatement);
72
- (0, _insert.prepend)(object, variableDeclaration);
73
- };
50
+ if (!(0, _probability.ComputeProbabilityMap)(this.options.deadCode)) {
51
+ return;
52
+ } // Hard-coded limit of 100 Dead Code insertions
53
+
54
+
55
+ this.made++;
56
+
57
+ if (this.made > 100) {
58
+ return;
74
59
  }
60
+
61
+ return () => {
62
+ var body = (0, _insert.getBlockBody)(object); // Do not place code before Import statements or 'use strict' directives
63
+
64
+ var safeOffset = 0;
65
+
66
+ for (var node of body) {
67
+ if (node.type === "ImportDeclaration" || node.directive) safeOffset++;else break;
68
+ }
69
+
70
+ var index = (0, _random.getRandomInteger)(safeOffset, body.length);
71
+ var name = this.getPlaceholder();
72
+ var variableDeclaration = (0, _gen.VariableDeclaration)((0, _gen.VariableDeclarator)(name, (0, _gen.Literal)(false)));
73
+ var template;
74
+
75
+ do {
76
+ template = (0, _random.choice)(templates);
77
+ } while (this.options.es5 && template.source.includes("async"));
78
+
79
+ var ifStatement = (0, _gen.IfStatement)((0, _gen.Identifier)(name), template.compile(), null);
80
+ body.splice(index, 0, ifStatement);
81
+ (0, _insert.prepend)(object, variableDeclaration);
82
+ };
75
83
  }
76
84
 
77
85
  }
@@ -80,12 +80,12 @@ class Dispatcher extends _transform.default {
80
80
  } // Map of FunctionDeclarations
81
81
 
82
82
 
83
- var functionDeclarations = {}; // Array of Identifier nodes
83
+ var functionDeclarations = Object.create(null); // Array of Identifier nodes
84
84
 
85
85
  var identifiers = [];
86
86
  var illegalFnNames = new Set(); // New Names for Functions
87
87
 
88
- var newFnNames = {}; // [old name]: randomized name
88
+ var newFnNames = Object.create(null); // [old name]: randomized name
89
89
 
90
90
  var context = (0, _insert.isVarContext)(object) ? object : (0, _insert.getVarContext)(object, parents);
91
91
  (0, _traverse.walk)(object, parents, (o, p) => {
@@ -102,11 +102,12 @@ class Dispatcher extends _transform.default {
102
102
 
103
103
  if (context === c) {
104
104
  if (o.type == "FunctionDeclaration" && o.id.name) {
105
+ var name = o.id.name;
106
+
105
107
  if (o.$requiresEval || o.async || o.generator || p.find(x => x.$dispatcherSkip || x.type == "MethodDefinition") || o.body.type != "BlockStatement") {
106
108
  illegalFnNames.add(name);
107
- }
109
+ } // If dupe, no routing
108
110
 
109
- var name = o.id.name; // If dupe, no routing
110
111
 
111
112
  if (functionDeclarations[name]) {
112
113
  illegalFnNames.add(name);
@@ -163,7 +164,7 @@ class Dispatcher extends _transform.default {
163
164
  var set = new Set(Object.keys(newFnNames)); // Only make a dispatcher function if it caught any functions
164
165
 
165
166
  if (set.size > 0) {
166
- var payloadArg = "$jsc_d".concat(this.count, "_payload");
167
+ var payloadArg = this.getPlaceholder() + "_dispatcher_" + this.count + "_payload";
167
168
  var dispatcherFnName = this.getPlaceholder() + "_dispatcher_" + this.count;
168
169
  this.log(dispatcherFnName, set);
169
170
  this.count++;
@@ -264,7 +265,7 @@ class Dispatcher extends _transform.default {
264
265
 
265
266
  var newName = newFnNames[o.name];
266
267
 
267
- if (!newName) {
268
+ if (!newName || typeof newName !== "string") {
268
269
  return;
269
270
  }
270
271
 
@@ -85,9 +85,13 @@ class AntiClass extends _transform.default {
85
85
  this.replace(o, (0, _gen.Identifier)(superName));
86
86
  }
87
87
  });
88
- }
88
+ } // Support class fields
89
+
89
90
 
90
- if (methodDefinition.kind == "constructor" || methodDefinition.kind == "method") {
91
+ if (methodDefinition.type === "PropertyDefinition") {
92
+ var assignmentExpression = (0, _gen.AssignmentExpression)("=", key, value || (0, _gen.Identifier)("undefined"));
93
+ pushingTo.push((0, _gen.ExpressionStatement)(assignmentExpression));
94
+ } else if (methodDefinition.kind == "constructor" || methodDefinition.kind == "method") {
91
95
  pushingTo.push((0, _gen.ExpressionStatement)((0, _gen.AssignmentExpression)("=", key, value)));
92
96
  } else if (methodDefinition.kind == "get" || methodDefinition.kind == "set") {
93
97
  var id = (0, _gen.Identifier)(methodDefinition.kind == "get" ? "getters" : "setters");
@@ -158,6 +158,8 @@ class AntiDestructuring extends _transform.default {
158
158
  if (x.type == "Identifier") {
159
159
  exprs.push((0, _gen.AssignmentExpression)(operator, (0, _insert.clone)(x), realm));
160
160
  names.add(x.name);
161
+ } else if (x.type == "MemberExpression") {
162
+ exprs.push((0, _gen.AssignmentExpression)(operator, (0, _insert.clone)(x), realm));
161
163
  } else if (x.type == "ObjectPattern") {
162
164
  x.properties.forEach(property => {
163
165
  recursive(property.value, (0, _gen.MemberExpression)(realm, property.key, property.computed));
@@ -189,7 +191,7 @@ class AntiDestructuring extends _transform.default {
189
191
  var seq = (0, _gen.SequenceExpression)([(0, _gen.AssignmentExpression)("=", (0, _gen.Identifier)(temp), (0, _insert.clone)(extracting) || (0, _gen.Identifier)("undefined")), ...exprs]);
190
192
 
191
193
  if (object.type == "VariableDeclarator") {
192
- var i = (0, _insert.getIndexDirect)(object, parents);
194
+ var i = (0, _insert.getIndexDirect)(object, parents[0]);
193
195
  var extra = Array.from(names).map(x => {
194
196
  return {
195
197
  type: "VariableDeclarator",
@@ -13,8 +13,6 @@ var _insert = require("../../util/insert");
13
13
 
14
14
  var _traverse = require("../../traverse");
15
15
 
16
- var _template = _interopRequireDefault(require("../../templates/template"));
17
-
18
16
  var _order = require("../../order");
19
17
 
20
18
  var _assert = require("assert");
@@ -31,6 +29,8 @@ var _antiES6Object = _interopRequireDefault(require("./antiES6Object"));
31
29
 
32
30
  var _antiSpreadOperator = _interopRequireDefault(require("./antiSpreadOperator"));
33
31
 
32
+ var _es = require("../../templates/es5");
33
+
34
34
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
35
35
 
36
36
  /**
@@ -93,24 +93,44 @@ class AntiArrowFunction extends _transform.default {
93
93
  }
94
94
 
95
95
  }
96
+ /**
97
+ * The ES5 options aims to convert ES6 and up features down to ES5-compatible code.
98
+ *
99
+ * The obfuscator regularly adds ES6 code (variable destructuring, spread element, etc.)
100
+ * This transformations goal is undo only these things.
101
+ */
102
+
96
103
 
97
104
  exports.AntiArrowFunction = AntiArrowFunction;
98
105
 
99
- class FixedExpressions extends _transform.default {
106
+ class ES5 extends _transform.default {
100
107
  constructor(o) {
101
- super(o);
108
+ super(o, _order.ObfuscateOrder.ES5);
109
+ this.before.push(new _antiClass.default(o));
110
+ this.before.push(new _antiTemplate.default(o));
111
+ this.before.push(new _antiSpreadOperator.default(o));
112
+ this.before.push(new _antiES6Object.default(o));
113
+ this.before.push(new AntiArrowFunction(o));
114
+ this.before.push(new _antiDestructuring.default(o));
115
+ this.before.push(new AntiConstLet(o));
102
116
  }
103
117
 
118
+ apply(tree) {
119
+ super.apply(tree);
120
+
121
+ var nodesToAdd = _es.ES5Template.compile();
122
+
123
+ (0, _insert.prepend)(tree, ...nodesToAdd);
124
+ } // FixedExpressions
125
+
126
+
104
127
  match(object, parents) {
105
- return true;
128
+ return !!object.type;
106
129
  }
107
130
 
108
131
  transform(object, parents) {
109
132
  return () => {
110
- if (object.type == "ForStatement" && object.init.type == "ExpressionStatement") {
111
- object.init = object.init.expression;
112
- }
113
-
133
+ // Object.keyword -> Object["keyword"]
114
134
  if (object.type == "MemberExpression") {
115
135
  if (!object.computed && object.property.type == "Identifier") {
116
136
  if (_constants.reservedKeywords.has(object.property.name)) {
@@ -118,7 +138,8 @@ class FixedExpressions extends _transform.default {
118
138
  object.computed = true;
119
139
  }
120
140
  }
121
- }
141
+ } // { keyword: ... } -> { "keyword": ... }
142
+
122
143
 
123
144
  if (object.type == "Property") {
124
145
  if (!object.computed && object.key.type == "Identifier") {
@@ -132,28 +153,4 @@ class FixedExpressions extends _transform.default {
132
153
 
133
154
  }
134
155
 
135
- class ES5 extends _transform.default {
136
- constructor(o) {
137
- super(o, _order.ObfuscateOrder.ES5);
138
- this.before.push(new _antiClass.default(o));
139
- this.before.push(new _antiTemplate.default(o));
140
- this.before.push(new _antiSpreadOperator.default(o));
141
- this.before.push(new _antiES6Object.default(o));
142
- this.before.push(new AntiArrowFunction(o));
143
- this.before.push(new _antiDestructuring.default(o));
144
- this.before.push(new AntiConstLet(o));
145
- this.concurrent.push(new FixedExpressions(o));
146
- }
147
-
148
- match(object, parents) {
149
- return object.type == "Program";
150
- }
151
-
152
- transform(object, parents) {
153
- var block = (0, _traverse.getBlock)(object, parents);
154
- (0, _insert.getBlockBody)(block).splice(0, 0, ...(0, _template.default)("\n !Array.prototype.forEach ? Array.prototype.forEach = function (callback, thisArg) {\n thisArg = thisArg;\n for (var i = 0; i < this.length; i++) {\n callback.call(thisArg, this[i], i, this);\n }\n } : 0;\n \n !Array.prototype.map ? Array.prototype.map = function (callback, thisArg) {\n thisArg = thisArg;\n var array=[];\n for (var i = 0; i < this.length; i++) {\n array.push( callback.call(thisArg, this[i], i, this) );\n }\n return array;\n } : 0;\n\n !Array.prototype.reduce ? Array.prototype.reduce = function(fn, initial) {\n var values = this;\n if ( typeof initial === \"undefined\" ) {\n initial = 0;\n }\n\n values.forEach(function(item, index){\n initial = fn(initial, item, index, this);\n });\n\n return initial;\n } : 0;\n ").compile());
155
- }
156
-
157
- }
158
-
159
156
  exports.default = ES5;
@@ -31,6 +31,17 @@ class Eval extends _transform.default {
31
31
  }
32
32
 
33
33
  transform(object, parents) {
34
+ // Don't apply to getter/setters or class methods
35
+ if (parents[0]) {
36
+ if (parents[0].type === "MethodDefinition" && parents[0].value === object) {
37
+ return;
38
+ }
39
+
40
+ if (parents[0].type === "Property" && parents[0].value === object && (parents[0].kind !== "init" || parents[0].method)) {
41
+ return;
42
+ }
43
+ }
44
+
34
45
  if (!(0, _probability.ComputeProbabilityMap)(this.options.eval, x => x, object.id && object.id.name)) {
35
46
  return;
36
47
  }
@@ -113,7 +113,7 @@ class DuplicateLiteralsRemoval extends _transform.default {
113
113
  var body = [];
114
114
  var thisShift = (0, _random.getRandomInteger)(-250, 250); // the name of the getter
115
115
 
116
- getterName = this.getPlaceholder();
116
+ getterName = this.getPlaceholder() + "_dLR_" + this.fnGetters.size;
117
117
 
118
118
  if (basedOn) {
119
119
  var shift = this.fnShifts.get(basedOn);
@@ -144,7 +144,10 @@ class DuplicateLiteralsRemoval extends _transform.default {
144
144
 
145
145
  if (!(0, _probability.ComputeProbabilityMap)(this.options.duplicateLiteralsRemoval)) {
146
146
  return;
147
- }
147
+ } // HARD CODED LIMIT of 10,000 (after 1,000 elements)
148
+
149
+
150
+ if (this.map.size > 1000 && !(0, _random.chance)(this.map.size / 100)) return;
148
151
 
149
152
  if (this.arrayName && parents[0].object && parents[0].object.name == this.arrayName) {
150
153
  return;
@@ -179,17 +182,17 @@ class DuplicateLiteralsRemoval extends _transform.default {
179
182
  this.arrayExpression = (0, _gen.ArrayExpression)([]);
180
183
  }
181
184
 
182
- var first = this.first.get(value);
185
+ var firstLocation = this.first.get(value);
183
186
 
184
- if (first) {
187
+ if (firstLocation) {
185
188
  this.first.set(value, null);
186
189
  var index = this.map.size;
187
190
  (0, _assert.ok)(!this.map.has(value));
188
191
  this.map.set(value, index);
189
- this.toCaller(first[0], first[1], index);
190
192
  var pushing = (0, _insert.clone)(object);
191
193
  this.arrayExpression.elements.push(pushing);
192
194
  (0, _assert.ok)(this.arrayExpression.elements[index] === pushing);
195
+ this.toCaller(firstLocation[0], firstLocation[1], index);
193
196
  }
194
197
 
195
198
  var index = this.map.get(value);
@@ -97,7 +97,12 @@ class ObjectExtraction extends _transform.default {
97
97
  var nonInitOrComputed = object.properties.find(x => x.kind !== "init" || x.computed);
98
98
 
99
99
  if (nonInitOrComputed) {
100
- this.log(name + " has non-init/computed property: " + nonInitOrComputed.key.name || nonInitOrComputed.key.value);
100
+ if (nonInitOrComputed.key) {
101
+ this.log(name + " has non-init/computed property: " + nonInitOrComputed.key.name || nonInitOrComputed.key.value);
102
+ } else {
103
+ this.log(name + " has spread-element or other type of property");
104
+ }
105
+
101
106
  illegal.add(name);
102
107
  return;
103
108
  } else {
@@ -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;