UNPKG

js-confuser

Version:

JavaScript Obfuscation Tool.

192 lines (180 loc) 8.87 kB
"use strict"; function _typeof(o) { "@babel/helpers - typeof"; return _typeof = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (o) { return typeof o; } : function (o) { return o && "function" == typeof Symbol && o.constructor === Symbol && o !== Symbol.prototype ? "symbol" : typeof o; }, _typeof(o); } Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = void 0; var _order = require("../../order"); var _constants = require("../../constants"); var t = _interopRequireWildcard(require("@babel/types")); var _staticUtils = require("../../utils/static-utils"); var _astUtils = require("../../utils/ast-utils"); var _template = _interopRequireDefault(require("../../templates/template")); function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; } function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(e) { return e ? t : r; })(e); } function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != _typeof(e) && "function" != typeof e) return { "default": e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n["default"] = e, t && t.set(e, n), n; } /** * Moved Declarations moves variables in two ways: * * 1) Move variables to top of the current block * 2) Move variables as unused function parameters */ var _default = exports["default"] = function _default(_ref) { var Plugin = _ref.Plugin; var me = Plugin(_order.Order.MovedDeclarations, { changeData: { variableDeclarations: 0, functionParameters: 0 } }); function isFunctionEligibleForParameterPacking(functionPath, proposedParameterName) { // Getter/setter functions must have zero or one formal parameter // We cannot add extra parameters to them if (functionPath.isObjectMethod() || functionPath.isClassMethod()) { if (functionPath.node.kind !== "method") { return false; } } // Rest params check if (functionPath.get("params").find(function (p) { return p.isRestElement(); })) return false; // Max 1,000 parameters if (functionPath.get("params").length > 1000) return false; // Check for duplicate parameter names var bindingIdentifiers = (0, _astUtils.getPatternIdentifierNames)(functionPath.get("params")); // Duplicate parameter name not allowed if (bindingIdentifiers.has(proposedParameterName)) return false; return true; } return { visitor: { FunctionDeclaration: { exit: function exit(path) { var functionPath = path.findParent(function (path) { return path.isFunction(); }); if (!functionPath || !functionPath.node[_constants.PREDICTABLE]) return; var fnBody = functionPath.get("body"); if (!fnBody.isBlockStatement()) return; // Must be direct child of the function if (path.parentPath !== fnBody) return; var functionName = path.node.id.name; // Must be eligible for parameter packing if (!isFunctionEligibleForParameterPacking(functionPath, functionName)) return; var strictMode = (0, _astUtils.isStrictMode)(functionPath); // Default parameters are not allowed when 'use strict' is declared if (strictMode) return; var functionExpression = path.node; functionExpression.type = "FunctionExpression"; functionExpression.id = null; var identifier = t.identifier(functionName); functionPath.node.params.push(identifier); var paramPath = functionPath.get("params").at(-1); // Update binding to point to new path var binding = functionPath.scope.getBinding(functionName); if (binding) { binding.kind = "param"; binding.path = paramPath; binding.identifier = identifier; } (0, _astUtils.prepend)(fnBody, new _template["default"]("\n if(!".concat(functionName, ") {\n ").concat(functionName, " = {functionExpression};\n }\n ")).single({ functionExpression: functionExpression })); path.remove(); me.changeData.functionParameters++; } }, VariableDeclaration: { exit: function exit(path) { if (me.isSkipped(path)) return; if (path.node.kind !== "var") return; if (path.node.declarations.length !== 1) return; var insertionMethod = "variableDeclaration"; var functionPath = path.findParent(function (path) { return path.isFunction(); }); var declaration = path.node.declarations[0]; if (!t.isIdentifier(declaration.id)) return; var varName = declaration.id.name; var allowDefaultParamValue = true; if (functionPath && functionPath.node[_constants.PREDICTABLE]) { // Check for "use strict" directive // Strict mode disallows non-simple parameters // So we can't move the declaration to the function parameters var strictMode = (0, _astUtils.isStrictMode)(functionPath); if (strictMode) { allowDefaultParamValue = false; } // Cannot add variables after rest element // Cannot add over 1,000 parameters if (isFunctionEligibleForParameterPacking(functionPath, varName)) { insertionMethod = "functionParameter"; } } var name = declaration.id.name; var value = declaration.init || t.identifier("undefined"); var isStatic = (0, _staticUtils.isStaticValue)(value); var isDefinedAtTop = false; var parentPath = path.parentPath; if (parentPath.isBlock()) { isDefinedAtTop = parentPath.get("body").filter(function (x) { return x.type !== "ImportDeclaration"; }).indexOf(path) === 0; } // Already at the top - nothing will change if (insertionMethod === "variableDeclaration" && isDefinedAtTop) { return; } var defaultParamValue; if (insertionMethod === "functionParameter" && isStatic && isDefinedAtTop && allowDefaultParamValue) { defaultParamValue = value; path.remove(); } else { // For-in / For-of can only reference the variable name if (parentPath.isForInStatement() || parentPath.isForOfStatement()) { path.replaceWith(t.identifier(name)); } else { path.replaceWith(t.assignmentExpression("=", t.identifier(name), declaration.init || t.identifier("undefined"))); } } switch (insertionMethod) { case "functionParameter": var identifier = t.identifier(name); var param = identifier; if (allowDefaultParamValue && defaultParamValue) { param = t.assignmentPattern(param, defaultParamValue); } functionPath.node.params.push(param); var paramPath = functionPath.get("params").at(-1); // Update binding to point to new path var binding = functionPath.scope.getBinding(name); if (binding) { binding.kind = "param"; binding.path = paramPath; binding.identifier = identifier; } me.changeData.functionParameters++; break; case "variableDeclaration": var block = path.findParent(function (path) { return path.isBlock(); }); var topNode = block.node.body.filter(function (x) { return x.type !== "ImportDeclaration"; })[0]; var variableDeclarator = t.variableDeclarator(t.identifier(name)); if (t.isVariableDeclaration(topNode) && topNode.kind === "var") { topNode.declarations.push(variableDeclarator); break; } else { (0, _astUtils.prepend)(block, me.skip(t.variableDeclaration("var", [variableDeclarator]))); } me.changeData.variableDeclarations++; break; } } } } }; };