diff --git a/dist/index.js b/dist/index.js index 8515a6f5..d446ed99 100644 --- a/dist/index.js +++ b/dist/index.js @@ -1,2 +1,2 @@ -require("source-map-support").install(),module.exports=function(e){function t(n){if(r[n])return r[n].exports;var o=r[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var r={};return t.m=e,t.c=r,t.i=function(e){return e},t.d=function(e,r,n){t.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:n})},t.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(r,"a",r),r},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=39)}([function(e,t){e.exports=require("inversify")},function(e,t){e.exports=require("tslib")},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.ServiceIdentifiers={Factory__ICalleeDataExtractor:Symbol("Factory"),Factory__IControlFlowReplacer:Symbol("Factory"),Factory__ICustomNode:Symbol("Factory"),Factory__ICustomNodeGroup:Symbol("Factory"),Factory__IIdentifierObfuscatingReplacer:Symbol("Factory"),Factory__INodeTransformer:Symbol("Factory"),Factory__IObfuscationResult:Symbol("Factory"),Factory__IObfuscatingReplacer:Symbol("Factory"),Factory__TControlFlowStorage:Symbol("Factory"),ICalleeDataExtractor:Symbol("ICalleeDataExtractor"),ICustomNodeGroup:Symbol("ICustomNodeGroup"),IControlFlowReplacer:Symbol("IControlFlowReplacer"),IDeadCodeInjectionReplacer:Symbol("IDeadCodeInjectionReplacer"),IIdentifierObfuscatingReplacer:Symbol("IIdentifierObfuscatingReplacer"),IJavaScriptObfuscator:Symbol("IJavaScriptObfuscator"),INodeTransformer:Symbol("INodeTransformer"),IObfuscationEventEmitter:Symbol("IObfuscationEventEmitter"),IObfuscationResult:Symbol("IObfuscationResult"),IObfuscator:Symbol("IObfuscator"),IOptions:Symbol("IOptions"),IObfuscatingReplacer:Symbol("IObfuscatingReplacer"),ISourceMapCorrector:Symbol("ISourceMapCorrector"),IStackTraceAnalyzer:Symbol("IStackTraceAnalyzer"),Newable__ICustomNode:Symbol("Newable"),Newable__TControlFlowStorage:Symbol("Newable"),TCustomNodeGroupStorage:Symbol("TCustomNodeGroupStorage"),TStringArrayStorage:Symbol("TStringArrayStorage")}},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},a=function(){function e(e,t){for(var r=0;r1&&void 0!==arguments[1]?arguments[1]:0;if(l.Node.isNodeHasBlockStatement(e)){if(void 0===e.body[t])throw new ReferenceError("Wrong index `"+t+"`. Block-statement body length is `"+e.body.length+"`");return e.body[t]}throw new TypeError("The specified node have no a block-statement")}},{key:"getBlockScopesOfNode",value:function(t){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=t.parentNode;if(!n)throw new ReferenceError("`parentNode` property of given node is `undefined`");if(l.Node.isBlockStatementNode(n)){if(!n.parentNode)throw new ReferenceError("`parentNode` property of `parentNode` of given node is `undefined`");-1!==e.nodesWithBlockScope.indexOf(n.parentNode.type)&&r.push(n)}return l.Node.isProgramNode(n)?(r.push(n),r):e.getBlockScopesOfNode(n,r)}},{key:"getNodeBlockScopeDepth",value:function(t){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=t.parentNode;if(!n)throw new ReferenceError("`parentNode` property of given node is `undefined`");return l.Node.isProgramNode(n)?r:l.Node.isBlockStatementNode(t)&&-1!==e.nodesWithBlockScope.indexOf(n.type)?e.getNodeBlockScopeDepth(n,++r):e.getNodeBlockScopeDepth(n,r)}},{key:"getUnaryExpressionArgumentNode",value:function(t){return l.Node.isUnaryExpressionNode(t.argument)?e.getUnaryExpressionArgumentNode(t.argument):t.argument}},{key:"parentize",value:function(e){var t=!0;return s.traverse(e,{enter:function(e,r){var n=void 0;t?(e.type===u.NodeType.Program?n=e:(n=f.Nodes.getProgramNode([e]),n.parentNode=n),t=!1):n=r||e,e.parentNode=n,e.obfuscatedNode=!1}}),e}},{key:"typedReplace",value:function(t,r,n){e.typedTraverse(t,r,n,"replace")}},{key:"typedTraverse",value:function(e,t,r){var n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"traverse";s[n](e,{enter:function(e,n){if(e.type===t&&r.enter)return r.enter(e,n)},leave:function(e,n){if(e.type===t&&r.leave)return r.leave(e,n)}})}}]),e}();d.nodesWithBlockScope=[u.NodeType.ArrowFunctionExpression,u.NodeType.FunctionDeclaration,u.NodeType.FunctionExpression,u.NodeType.MethodDefinition,u.NodeType.Program],t.NodeUtils=d},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var o=function(){function e(e,t){for(var r=0;r1&&void 0!==arguments[1]?arguments[1]:e.randomGeneratorPool;return e.getRandomGenerator().string({length:t,pool:r})}},{key:"getRandomVariableName",value:function(t){var r="_"+i.Utils.hexadecimalPrefix,n=""+r+i.Utils.decToHex(e.getRandomInteger(1e4,99999999)).substr(0,t);return e.randomVariableNameSet.has(n)?e.getRandomVariableName(t):(e.randomVariableNameSet.add(n),n)}}]),e}();c.randomGeneratorPool="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",c.randomGeneratorPoolNumbers="0123456789",c.randomGeneratorPoolHexadecimal="abcdef"+c.randomGeneratorPoolNumbers,c.randomGeneratorPoolWithNumbers=""+c.randomGeneratorPool+c.randomGeneratorPoolNumbers,c.randomVariableNameSet=new Set,t.RandomGeneratorUtils=c},function(e,t,r){"use strict";function n(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"initialize",t=Object.keys(this)[0];return function(r,n){var o={configurable:!0,enumerable:!0},a=r[e];if(!a||"function"!=typeof a)throw new Error("`"+e+"` method with initialization logic not found. `@"+t+"` decorator requires `"+e+"` method");var i="_"+n,c=Object.getOwnPropertyDescriptor(r,i)||o,s=Object.getOwnPropertyDescriptor(r,e)||o,u=s.value;return Object.defineProperty(r,n,Object.assign({},c,{get:function(){if(void 0===this[i])throw new Error("Property `"+n+"` is not initialized! Initialize it first!");return this[i]},set:function(e){this[i]=e}})),Object.defineProperty(r,e,Object.assign({},s,{value:function(){u.apply(this,arguments),this[n]}})),c}}Object.defineProperty(t,"__esModule",{value:!0}),t.initializable=n},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var o=function(){function e(e,t){for(var r=0;r0&&void 0!==arguments[0]?arguments[0]:[];return{type:i.NodeType.Program,body:e,sourceType:"script",obfuscatedNode:!1}}},{key:"getArrayExpressionNode",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];return{type:i.NodeType.ArrayExpression,elements:e}}},{key:"getAssignmentExpressionNode",value:function(e,t,r){return{type:i.NodeType.AssignmentExpression,operator:e,left:t,right:r,obfuscatedNode:!1}}},{key:"getBinaryExpressionNode",value:function(e,t,r){return{type:i.NodeType.BinaryExpression,operator:e,left:t,right:r,obfuscatedNode:!1}}},{key:"getBlockStatementNode",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];return{type:i.NodeType.BlockStatement,body:e,obfuscatedNode:!1}}},{key:"getBreakStatement",value:function(e){var t={type:i.NodeType.BreakStatement,obfuscatedNode:!1};return e&&(t.label=e),t}},{key:"getCatchClauseNode",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];return{type:i.NodeType.CatchClause,param:e.getIdentifierNode("err"),body:e.getBlockStatementNode(t),obfuscatedNode:!1}}},{key:"getCallExpressionNode",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[];return{type:i.NodeType.CallExpression,callee:e,arguments:t,obfuscatedNode:!1}}},{key:"getContinueStatement",value:function(e){var t={type:i.NodeType.ContinueStatement,obfuscatedNode:!1};return e&&(t.label=e),t}},{key:"getExpressionStatementNode",value:function(e){return{type:i.NodeType.ExpressionStatement,expression:e,obfuscatedNode:!1}}},{key:"getFunctionDeclarationNode",value:function(t,r,n){return{type:i.NodeType.FunctionDeclaration,id:e.getIdentifierNode(t),params:r,body:n,generator:!1,obfuscatedNode:!1}}},{key:"getFunctionExpressionNode",value:function(e,t){return{type:i.NodeType.FunctionExpression,params:e,body:t,generator:!1,obfuscatedNode:!1}}},{key:"getIfStatementNode",value:function(e,t,r){return Object.assign({type:i.NodeType.IfStatement,test:e,consequent:t},r&&{alternate:r},{obfuscatedNode:!1})}},{key:"getIdentifierNode",value:function(e){return{type:i.NodeType.Identifier,name:e,obfuscatedNode:!1}}},{key:"getLabeledStatement",value:function(e,t){return{type:i.NodeType.LabeledStatement,label:e,body:t,obfuscatedNode:!1}}},{key:"getLiteralNode",value:function(e,t){return t=void 0!==t?t:"'"+e+"'",{type:i.NodeType.Literal,value:e,raw:t,"x-verbatim-property":{content:t,precedence:a.Precedence.Primary},obfuscatedNode:!1}}},{key:"getLogicalExpressionNode",value:function(e,t,r){return{type:i.NodeType.LogicalExpression,operator:e,left:t,right:r,obfuscatedNode:!1}}},{key:"getMemberExpressionNode",value:function(e,t){var r=arguments.length>2&&void 0!==arguments[2]&&arguments[2];return{type:i.NodeType.MemberExpression,computed:r,object:e,property:t,obfuscatedNode:!1}}},{key:"getObjectExpressionNode",value:function(e){return{type:i.NodeType.ObjectExpression,properties:e,obfuscatedNode:!1}}},{key:"getPropertyNode",value:function(e,t){var r=arguments.length>2&&void 0!==arguments[2]&&arguments[2];return{type:i.NodeType.Property,key:e,value:t,kind:"init",method:!1,shorthand:!1,computed:r,obfuscatedNode:!1}}},{key:"getUnaryExpressionNode",value:function(e,t){var r=!(arguments.length>2&&void 0!==arguments[2])||arguments[2];return{type:i.NodeType.UnaryExpression,operator:e,argument:t,prefix:r,obfuscatedNode:!1}}},{key:"getReturnStatementNode",value:function(e){return{type:i.NodeType.ReturnStatement,argument:e,obfuscatedNode:!1}}},{key:"getSwitchStatementNode",value:function(e,t){return{type:i.NodeType.SwitchStatement,discriminant:e,cases:t,obfuscatedNode:!1}}},{key:"getSwitchCaseNode",value:function(e,t){return{type:i.NodeType.SwitchCase,test:e,consequent:t,obfuscatedNode:!1}}},{key:"getUpdateExpressionNode",value:function(e,t){return{type:i.NodeType.UpdateExpression,operator:e,argument:t,prefix:!1,obfuscatedNode:!1}}},{key:"getVariableDeclarationNode",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"var";return{type:i.NodeType.VariableDeclaration,declarations:e,kind:t,obfuscatedNode:!1}}},{key:"getVariableDeclaratorNode",value:function(e,t){return{type:i.NodeType.VariableDeclarator,id:e,init:t,obfuscatedNode:!1}}},{key:"getWhileStatementNode",value:function(e,t){return{type:i.NodeType.WhileStatement,test:e,body:t,obfuscatedNode:!1}}}]),e}();t.Nodes=c},function(e,t,r){"use strict";function n(e){if(Array.isArray(e)){for(var t=0,r=Array(e.length);t-1||0===e.indexOf("//")?e.split("/")[2]:e.split("/")[0],t=t.split(":")[0]}},{key:"isCeilNumber",value:function(e){return e%1==0}},{key:"strEnumify",value:function(e){return e}},{key:"stringRotate",value:function(e,t){if(!e)throw new ReferenceError("Cannot rotate empty string.");for(var r=0;r1&&void 0!==arguments[1]&&arguments[1],n=t+"-"+String(r);if(e.stringToUnicodeEscapeSequenceCache.has(n))return e.stringToUnicodeEscapeSequenceCache.get(n);var o=new RegExp("[\\s\\S]","g"),a=new RegExp("[^a-zA-Z0-9]"),i=new RegExp("[\\x00-\\x7F]"),c=void 0,s=void 0,u=t.replace(o,function(e){return r&&!a.exec(e)?e:(i.exec(e)?(c="\\x",s="00"):(c="\\u",s="0000"),""+c+(s+e.charCodeAt(0).toString(16)).slice(-s.length))});return e.stringToUnicodeEscapeSequenceCache.set(n,u),u}}]),e}();s.hexadecimalPrefix="0x",s.stringToUnicodeEscapeSequenceCache=new Map,t.Utils=s},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});!function(e){e[e.BinaryExpressionFunctionNode=0]="BinaryExpressionFunctionNode",e[e.BlockStatementControlFlowFlatteningNode=1]="BlockStatementControlFlowFlatteningNode",e[e.CallExpressionControlFlowStorageCallNode=2]="CallExpressionControlFlowStorageCallNode",e[e.CallExpressionFunctionNode=3]="CallExpressionFunctionNode",e[e.ControlFlowStorageNode=4]="ControlFlowStorageNode",e[e.ConsoleOutputDisableExpressionNode=5]="ConsoleOutputDisableExpressionNode",e[e.DebugProtectionFunctionCallNode=6]="DebugProtectionFunctionCallNode",e[e.DebugProtectionFunctionIntervalNode=7]="DebugProtectionFunctionIntervalNode",e[e.DebugProtectionFunctionNode=8]="DebugProtectionFunctionNode",e[e.DomainLockNode=9]="DomainLockNode",e[e.ExpressionWithOperatorControlFlowStorageCallNode=10]="ExpressionWithOperatorControlFlowStorageCallNode",e[e.LogicalExpressionFunctionNode=11]="LogicalExpressionFunctionNode",e[e.NodeCallsControllerFunctionNode=12]="NodeCallsControllerFunctionNode",e[e.SelfDefendingUnicodeNode=13]="SelfDefendingUnicodeNode",e[e.StringArrayCallsWrapper=14]="StringArrayCallsWrapper",e[e.StringArrayNode=15]="StringArrayNode",e[e.StringArrayRotateFunctionNode=16]="StringArrayRotateFunctionNode",e[e.StringLiteralControlFlowStorageCallNode=17]="StringLiteralControlFlowStorageCallNode",e[e.StringLiteralNode=18]="StringLiteralNode"}(t.CustomNode||(t.CustomNode={}))},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var o=r(1),a=r(0),i=r(2),c=r(4),s=function e(t){n(this,e),this.nodeIdentifier=c.RandomGeneratorUtils.getRandomInteger(0,1e4),this.options=t};s=o.__decorate([a.injectable(),o.__param(0,a.inject(i.ServiceIdentifiers.IOptions)),o.__metadata("design:paramtypes",[Object])],s),t.AbstractNodeTransformer=s},function(e,t){e.exports=require("estraverse")},function(e,t){e.exports=require("string-template")},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(9);t.NodeType=n.Utils.strEnumify({ArrayExpression:"ArrayExpression",ArrowFunctionExpression:"ArrowFunctionExpression",AssignmentExpression:"AssignmentExpression",AssignmentPattern:"AssignmentPattern",BinaryExpression:"BinaryExpression",BlockStatement:"BlockStatement",BreakStatement:"BreakStatement",CallExpression:"CallExpression",CatchClause:"CatchClause",ClassDeclaration:"ClassDeclaration",ContinueStatement:"ContinueStatement",ExpressionStatement:"ExpressionStatement",FunctionDeclaration:"FunctionDeclaration",FunctionExpression:"FunctionExpression",Identifier:"Identifier",IfStatement:"IfStatement",LabeledStatement:"LabeledStatement",Literal:"Literal",LogicalExpression:"LogicalExpression",MemberExpression:"MemberExpression",MethodDefinition:"MethodDefinition",ObjectExpression:"ObjectExpression",ObjectPattern:"ObjectPattern",Program:"Program",Property:"Property",ReturnStatement:"ReturnStatement",SwitchCase:"SwitchCase",SwitchStatement:"SwitchStatement",TemplateLiteral:"TemplateLiteral",TryStatement:"TryStatement",UnaryExpression:"UnaryExpression",UpdateExpression:"UpdateExpression",VariableDeclaration:"VariableDeclaration",VariableDeclarator:"VariableDeclarator",WhileStatement:"WhileStatement"})},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.ObfuscationEvent={AfterObfuscation:"afterObfuscation",BeforeObfuscation:"beforeObfuscation"}},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var o=function(){function e(e,t){for(var r=0;r1&&void 0!==arguments[1]?arguments[1]:{},r=new i.InversifyContainerFacade(t),n=r.get(a.ServiceIdentifiers.IOptions);s.RandomGeneratorUtils.initializeRandomGenerator(n.seed);var o=r.get(a.ServiceIdentifiers.IJavaScriptObfuscator),c=o.obfuscate(e);return s.RandomGeneratorUtils.clearRandomGenerator(),c}},{key:"runCLI",value:function(e){new c.JavaScriptObfuscatorCLI(e).run()}}]),e}();t.JavaScriptObfuscator=u},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var o=function(){function e(e,t){for(var r=0;r3&&void 0!==arguments[3]?arguments[3]:0,a=void 0;a=t.length?e.getOptimalBlockScope(t,o):r,e.prependNode(a,n)}},{key:"getOptimalBlockScope",value:function(t,r){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1/0,o=t[r];if(n<=0)throw new Error("Invalid `deep` argument value. Value should be bigger then 0.");return n>1&&o.stackTrace.length?e.getOptimalBlockScope(o.stackTrace,0,--n):o.callee}},{key:"getRandomStackTraceIndex",value:function(e){return i.RandomGeneratorUtils.getRandomInteger(0,Math.max(0,Math.round(e-1)))}},{key:"insertNodeAtIndex",value:function(t,r,o){e.validateBodyStatements(r)||(r=[]),r=e.parentizeBodyStatementsBeforeAppend(t,r),t.body=[].concat(n(t.body.slice(0,o)),n(r),n(t.body.slice(o)))}},{key:"prependNode",value:function(t,r){e.validateBodyStatements(r)||(r=[]),r=e.parentizeBodyStatementsBeforeAppend(t,r),t.body=[].concat(n(r),n(t.body))}},{key:"parentizeBodyStatementsBeforeAppend",value:function(e,t){return t.forEach(function(t){t.parentNode=e}),t}},{key:"validateBodyStatements",value:function(e){return e.every(function(e){return!!e&&e.hasOwnProperty("type")})}}]),e}();t.NodeAppender=c},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var o=function(){function e(e,t){for(var r=0;r>8-o%1*8)){if((n=e.charCodeAt(o+=.75))>255)throw new Error("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.");r=r<<8|n}return t}},{key:"hideString",value:function(e,t){var r=a.RandomGeneratorUtils.getRandomGenerator().string({length:t,pool:a.RandomGeneratorUtils.randomGeneratorPool}),n=r.replace(new RegExp("["+function(e){return e.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}(e)+"]","g"),""),o=n.split("");return a.RandomGeneratorUtils.getRandomGenerator().shuffle(o),n=o.join(""),[function(e,t){for(var r=-1,n=-1,o="";r1&&void 0!==arguments[1]&&arguments[1];this.storage=new Map([].concat(n(this.storage),n(e.getStorage()))),t&&(this.storageId=e.getStorageId())}},{key:"set",value:function(e,t){this.storage.set(e,t)}}]),e}();c.__decorate([u.initializable(),c.__metadata("design:type",String)],f.prototype,"storageId",void 0),c.__decorate([u.initializable(),c.__metadata("design:type",Map)],f.prototype,"storage",void 0),f=c.__decorate([s.injectable()],f),t.MapStorage=f},function(e,t){e.exports=require("esprima")},function(e,t){e.exports=require("path")},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(16);e.exports=n.JavaScriptObfuscator},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var o=function(){function e(e,t){for(var r=0;r1&&void 0!==arguments[1]?arguments[1]:"";return t&&(e=e.substring(0,e.lastIndexOf("/"))+"/"+t),/\.js\.map$/.test(e)?/\.js$/.test(e)&&(e+=".map"):e=e.split(".")[0]+".js.map",e}},{key:"getPackageConfig",value:function(){return JSON.parse(a.readFileSync(c.join(c.dirname(a.realpathSync(process.argv[1])),"../package.json"),e.encoding))}},{key:"isFilePath",value:function(e){try{return a.statSync(e).isFile()}catch(e){return!1}}},{key:"readFile",value:function(t){return a.readFileSync(t,e.encoding)}},{key:"validateInputPath",value:function(t){if(!e.isFilePath(t))throw new ReferenceError("Given input path must be a valid file path");if(-1===e.availableInputExtensions.indexOf(c.extname(t)))throw new ReferenceError("Input file must have .js extension")}},{key:"writeFile",value:function(t,r){i.sync(c.dirname(t)),a.writeFileSync(t,r,{encoding:e.encoding})}}]),e}();s.availableInputExtensions=[".js"],s.encoding="utf8",t.CLIUtils=s},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var o=function(){function e(e,t){for(var r=0;r [options]").option("-o, --output ","Output path for obfuscated code").option("--compact ","Disable one line output code compacting",s.BooleanSanitizer).option("--controlFlowFlattening ","Enables control flow flattening",s.BooleanSanitizer).option("--controlFlowFlatteningThreshold ","The probability that the control flow flattening transformation will be applied to the node",parseFloat).option("--deadCodeInjection ","Enables dead code injection",s.BooleanSanitizer).option("--deadCodeInjectionThreshold ","The probability that the dead code injection transformation will be applied to the node",parseFloat).option("--debugProtection ","Disable browser Debug panel (can cause DevTools enabled browser freeze)",s.BooleanSanitizer).option("--debugProtectionInterval ","Disable browser Debug panel even after page was loaded (can cause DevTools enabled browser freeze)",s.BooleanSanitizer).option("--disableConsoleOutput ","Allow console.log, console.info, console.error and console.warn messages output into browser console",s.BooleanSanitizer).option("--domainLock ","Blocks the execution of the code in domains that do not match the passed RegExp patterns (comma separated)",function(e){return e.split(",")}).option("--mangle ","Enables mangling of variable names",s.BooleanSanitizer).option("--reservedNames ","Disable obfuscation of variable names, function names and names of function parameters that match the passed RegExp patterns (comma separated)",function(e){return e.split(",")}).option("--rotateStringArray ","Disable rotation of unicode array values during obfuscation",s.BooleanSanitizer).option("--seed ","Sets seed for random generator. This is useful for creating repeatable results.",parseFloat).option("--selfDefending ","Disables self-defending for obfuscated code",s.BooleanSanitizer).option("--sourceMap ","Enables source map generation",s.BooleanSanitizer).option("--sourceMapBaseUrl ","Sets base url to the source map import url when `--sourceMapMode=separate`").option("--sourceMapFileName ","Sets file name for output source map when `--sourceMapMode=separate`").option("--sourceMapMode [inline, separate]","Specify source map output mode",u.SourceMapModeSanitizer).option("--stringArray ","Disables gathering of all literal strings into an array and replacing every literal string with an array call",s.BooleanSanitizer).option("--stringArrayEncoding [true, false, base64, rc4]","Encodes all strings in strings array using base64 or rc4 (this option can slow down your code speed",l.StringArrayEncodingSanitizer).option("--stringArrayThreshold ","The probability that the literal string will be inserted into stringArray (Default: 0.8, Min: 0, Max: 1)",parseFloat).option("--unicodeEscapeSequence ","Allows to enable/disable string conversion to unicode escape sequence",s.BooleanSanitizer).parse(this.rawArguments),this.commands.on("--help",function(){console.log(" Examples:\n"),console.log(" %> javascript-obfuscator in.js --compact true --selfDefending false"),console.log(" %> javascript-obfuscator in.js --output out.js --compact true --selfDefending false"),console.log("")})}},{key:"getData",value:function(){this.data=f.CLIUtils.readFile(this.inputPath)}},{key:"processData",value:function(){var e=this.buildOptions(),t=f.CLIUtils.getOutputCodePath(this.commands.output,this.inputPath);e.sourceMap?this.processDataWithSourceMap(t,e):this.processDataWithoutSourceMap(t,e)}},{key:"processDataWithoutSourceMap",value:function(e,t){var r=d.JavaScriptObfuscator.obfuscate(this.data,t).getObfuscatedCode();f.CLIUtils.writeFile(e,r)}},{key:"processDataWithSourceMap",value:function(e,t){var r=f.CLIUtils.getOutputSourceMapPath(e,t.sourceMapFileName||"");t=Object.assign({},t,{sourceMapFileName:i.basename(r)});var n=d.JavaScriptObfuscator.obfuscate(this.data,t);f.CLIUtils.writeFile(e,n.getObfuscatedCode()),"separate"===t.sourceMapMode&&n.getSourceMap()&&f.CLIUtils.writeFile(r,n.getSourceMap())}}],[{key:"getBuildVersion",value:function(){return f.CLIUtils.getPackageConfig().version}}]),e}();t.JavaScriptObfuscatorCLI=p},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.BooleanSanitizer=function(e){return"true"===e||"1"===e}},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(21);t.SourceMapModeSanitizer=function(e){if(!Object.keys(n.SourceMapMode).some(function(t){return n.SourceMapMode[t]===e}))throw new ReferenceError("Invalid value of `--sourceMapMode` option");return e}},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(24);t.StringArrayEncodingSanitizer=function(e){switch(e){case"true":case"1":case n.StringArrayEncoding.base64:return!0;case n.StringArrayEncoding.rc4:return n.StringArrayEncoding.rc4;default:return!1}}},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(17),o=r(0),a=r(2),i=r(10),c=r(30),s=r(56),u=r(69),l=r(71),f=r(74),d=r(78),p=r(57),y=r(58),b=r(62),m=r(59),g=r(63),v=r(55),h=r(66),_=r(67),N=r(68),O=r(70),S=r(64),w=r(60),C=r(72),j=r(73),I=r(75),E=r(76),T=r(77),F=r(65),k=r(61);t.customNodesModule=new o.ContainerModule(function(e){e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(p.BinaryExpressionFunctionNode).whenTargetNamed(i.CustomNode.BinaryExpressionFunctionNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(y.BlockStatementControlFlowFlatteningNode).whenTargetNamed(i.CustomNode.BlockStatementControlFlowFlatteningNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(b.CallExpressionControlFlowStorageCallNode).whenTargetNamed(i.CustomNode.CallExpressionControlFlowStorageCallNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(m.CallExpressionFunctionNode).whenTargetNamed(i.CustomNode.CallExpressionFunctionNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(g.ControlFlowStorageNode).whenTargetNamed(i.CustomNode.ControlFlowStorageNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(v.ConsoleOutputDisableExpressionNode).whenTargetNamed(i.CustomNode.ConsoleOutputDisableExpressionNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(h.DebugProtectionFunctionCallNode).whenTargetNamed(i.CustomNode.DebugProtectionFunctionCallNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(_.DebugProtectionFunctionIntervalNode).whenTargetNamed(i.CustomNode.DebugProtectionFunctionIntervalNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(N.DebugProtectionFunctionNode).whenTargetNamed(i.CustomNode.DebugProtectionFunctionNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(O.DomainLockNode).whenTargetNamed(i.CustomNode.DomainLockNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(S.ExpressionWithOperatorControlFlowStorageCallNode).whenTargetNamed(i.CustomNode.ExpressionWithOperatorControlFlowStorageCallNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(w.LogicalExpressionFunctionNode).whenTargetNamed(i.CustomNode.LogicalExpressionFunctionNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(C.NodeCallsControllerFunctionNode).whenTargetNamed(i.CustomNode.NodeCallsControllerFunctionNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(j.SelfDefendingUnicodeNode).whenTargetNamed(i.CustomNode.SelfDefendingUnicodeNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(I.StringArrayCallsWrapper).whenTargetNamed(i.CustomNode.StringArrayCallsWrapper),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(E.StringArrayNode).whenTargetNamed(i.CustomNode.StringArrayNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(T.StringArrayRotateFunctionNode).whenTargetNamed(i.CustomNode.StringArrayRotateFunctionNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(F.StringLiteralControlFlowStorageCallNode).whenTargetNamed(i.CustomNode.StringLiteralControlFlowStorageCallNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(k.StringLiteralNode).whenTargetNamed(i.CustomNode.StringLiteralNode),e(a.ServiceIdentifiers.ICustomNodeGroup).to(s.ConsoleOutputCustomNodeGroup).whenTargetNamed(c.CustomNodeGroup.ConsoleOutputCustomNodeGroup),e(a.ServiceIdentifiers.ICustomNodeGroup).to(u.DebugProtectionCustomNodeGroup).whenTargetNamed(c.CustomNodeGroup.DebugProtectionCustomNodeGroup),e(a.ServiceIdentifiers.ICustomNodeGroup).to(l.DomainLockCustomNodeGroup).whenTargetNamed(c.CustomNodeGroup.DomainLockCustomNodeGroup),e(a.ServiceIdentifiers.ICustomNodeGroup).to(f.SelfDefendingCustomNodeGroup).whenTargetNamed(c.CustomNodeGroup.SelfDefendingCustomNodeGroup),e(a.ServiceIdentifiers.ICustomNodeGroup).to(d.StringArrayCustomNodeGroup).whenTargetNamed(c.CustomNodeGroup.StringArrayCustomNodeGroup),e(a.ServiceIdentifiers.Factory__ICustomNode).toFactory(function(e){var t=new Map,r=void 0;return function(n){if(r||(r=e.container.get(a.ServiceIdentifiers.IOptions)),t.has(n))return new(t.get(n));var o=e.container.getNamed(a.ServiceIdentifiers.Newable__ICustomNode,n);return t.set(n,o),new o(r)}}),e(a.ServiceIdentifiers.Factory__ICustomNodeGroup).toFactory(n.InversifyContainerFacade.getFactory(a.ServiceIdentifiers.ICustomNodeGroup))})},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(17),o=r(0),a=r(2),i=r(31),c=r(84),s=r(85),u=r(86),l=r(87);t.controlFlowTransformersModule=new o.ContainerModule(function(e){e(a.ServiceIdentifiers.IControlFlowReplacer).to(c.BinaryExpressionControlFlowReplacer).whenTargetNamed(i.ControlFlowReplacer.BinaryExpressionControlFlowReplacer),e(a.ServiceIdentifiers.IControlFlowReplacer).to(s.CallExpressionControlFlowReplacer).whenTargetNamed(i.ControlFlowReplacer.CallExpressionControlFlowReplacer),e(a.ServiceIdentifiers.IControlFlowReplacer).to(u.LogicalExpressionControlFlowReplacer).whenTargetNamed(i.ControlFlowReplacer.LogicalExpressionControlFlowReplacer),e(a.ServiceIdentifiers.IControlFlowReplacer).to(l.StringLiteralControlFlowReplacer).whenTargetNamed(i.ControlFlowReplacer.StringLiteralControlFlowReplacer),e(a.ServiceIdentifiers.Factory__IControlFlowReplacer).toFactory(n.InversifyContainerFacade.getCacheFactory(a.ServiceIdentifiers.IControlFlowReplacer))})},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(17),o=r(0),a=r(2),i=r(33),c=r(83),s=r(82),u=r(91),l=r(92),f=r(93),d=r(94),p=r(95),y=r(96),b=r(88),m=r(89),g=r(97),v=r(90),h=r(98);t.nodeTransformersModule=new o.ContainerModule(function(e){e(a.ServiceIdentifiers.INodeTransformer).to(s.BlockStatementControlFlowTransformer).whenTargetNamed(i.NodeTransformer.BlockStatementControlFlowTransformer),e(a.ServiceIdentifiers.INodeTransformer).to(u.DeadCodeInjectionTransformer).whenTargetNamed(i.NodeTransformer.DeadCodeInjectionTransformer),e(a.ServiceIdentifiers.INodeTransformer).to(c.FunctionControlFlowTransformer).whenTargetNamed(i.NodeTransformer.FunctionControlFlowTransformer),e(a.ServiceIdentifiers.INodeTransformer).to(b.MemberExpressionTransformer).whenTargetNamed(i.NodeTransformer.MemberExpressionTransformer),e(a.ServiceIdentifiers.INodeTransformer).to(m.MethodDefinitionTransformer).whenTargetNamed(i.NodeTransformer.MethodDefinitionTransformer),e(a.ServiceIdentifiers.INodeTransformer).to(v.TemplateLiteralTransformer).whenTargetNamed(i.NodeTransformer.TemplateLiteralTransformer),e(a.ServiceIdentifiers.INodeTransformer).to(l.CatchClauseTransformer).whenTargetNamed(i.NodeTransformer.CatchClauseTransformer),e(a.ServiceIdentifiers.INodeTransformer).to(f.FunctionDeclarationTransformer).whenTargetNamed(i.NodeTransformer.FunctionDeclarationTransformer),e(a.ServiceIdentifiers.INodeTransformer).to(d.FunctionTransformer).whenTargetNamed(i.NodeTransformer.FunctionTransformer),e(a.ServiceIdentifiers.INodeTransformer).to(p.LabeledStatementTransformer).whenTargetNamed(i.NodeTransformer.LabeledStatementTransformer),e(a.ServiceIdentifiers.INodeTransformer).to(y.LiteralTransformer).whenTargetNamed(i.NodeTransformer.LiteralTransformer),e(a.ServiceIdentifiers.INodeTransformer).to(g.ObjectExpressionTransformer).whenTargetNamed(i.NodeTransformer.ObjectExpressionTransformer),e(a.ServiceIdentifiers.INodeTransformer).to(h.VariableDeclarationTransformer).whenTargetNamed(i.NodeTransformer.VariableDeclarationTransformer),e(a.ServiceIdentifiers.Factory__INodeTransformer).toFactory(n.InversifyContainerFacade.getCacheFactory(a.ServiceIdentifiers.INodeTransformer))})},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(17),o=r(0),a=r(2),i=r(18),c=r(32),s=r(99),u=r(100),l=r(101),f=r(102);t.obfuscatingTransformersModule=new o.ContainerModule(function(e){e(a.ServiceIdentifiers.IObfuscatingReplacer).to(u.BooleanLiteralObfuscatingReplacer).whenTargetNamed(c.LiteralObfuscatingReplacer.BooleanLiteralObfuscatingReplacer),e(a.ServiceIdentifiers.IObfuscatingReplacer).to(l.NumberLiteralObfuscatingReplacer).whenTargetNamed(c.LiteralObfuscatingReplacer.NumberLiteralObfuscatingReplacer),e(a.ServiceIdentifiers.IObfuscatingReplacer).to(f.StringLiteralObfuscatingReplacer).whenTargetNamed(c.LiteralObfuscatingReplacer.StringLiteralObfuscatingReplacer),e(a.ServiceIdentifiers.IIdentifierObfuscatingReplacer).to(s.BaseIdentifierObfuscatingReplacer).whenTargetNamed(i.IdentifierObfuscatingReplacer.BaseIdentifierObfuscatingReplacer),e(a.ServiceIdentifiers.Factory__IObfuscatingReplacer).toFactory(n.InversifyContainerFacade.getCacheFactory(a.ServiceIdentifiers.IObfuscatingReplacer)),e(a.ServiceIdentifiers.Factory__IIdentifierObfuscatingReplacer).toFactory(n.InversifyContainerFacade.getCacheFactory(a.ServiceIdentifiers.IIdentifierObfuscatingReplacer))})},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(17),o=r(0),a=r(2),i=r(34),c=r(117),s=r(118),u=r(119),l=r(116);t.stackTraceAnalyzerModule=new o.ContainerModule(function(e){e(a.ServiceIdentifiers.IStackTraceAnalyzer).to(l.StackTraceAnalyzer).inSingletonScope(),e(a.ServiceIdentifiers.ICalleeDataExtractor).to(c.FunctionDeclarationCalleeDataExtractor).whenTargetNamed(i.CalleeDataExtractor.FunctionDeclarationCalleeDataExtractor),e(a.ServiceIdentifiers.ICalleeDataExtractor).to(s.FunctionExpressionCalleeDataExtractor).whenTargetNamed(i.CalleeDataExtractor.FunctionExpressionCalleeDataExtractor),e(a.ServiceIdentifiers.ICalleeDataExtractor).to(u.ObjectExpressionCalleeDataExtractor).whenTargetNamed(i.CalleeDataExtractor.ObjectExpressionCalleeDataExtractor),e(a.ServiceIdentifiers.Factory__ICalleeDataExtractor).toFactory(n.InversifyContainerFacade.getCacheFactory(a.ServiceIdentifiers.ICalleeDataExtractor))})},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(0),o=r(2),a=r(121),i=r(122),c=r(123);t.storagesModule=new n.ContainerModule(function(e){e(o.ServiceIdentifiers.TCustomNodeGroupStorage).to(i.CustomNodeGroupStorage).inSingletonScope(),e(o.ServiceIdentifiers.TStringArrayStorage).to(c.StringArrayStorage).inSingletonScope(),e(o.ServiceIdentifiers.Newable__TControlFlowStorage).toConstructor(a.ControlFlowStorage),e(o.ServiceIdentifiers.Factory__TControlFlowStorage).toFactory(function(e){return function(){var t=e.container.get(o.ServiceIdentifiers.Newable__TControlFlowStorage);return new t}})})},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var i=function(){function e(e,t){for(var r=0;rthis.options.controlFlowFlatteningThreshold||m.blockStatementHasProhibitedStatements(e))return e;var r=e.body;if(r.length<=4)return e;var n=y.Utils.arrayRange(r.length),o=y.Utils.arrayShuffle(n),a=n.map(function(e){return o.indexOf(e)}),i=this.customNodeFactory(l.CustomNode.BlockStatementControlFlowFlatteningNode);return i.initialize(r,o,a),i.getNode()[0]}}],[{key:"blockStatementHasProhibitedStatements",value:function(e){return e.body.some(function(e){var t=d.Node.isBreakStatementNode(e)||d.Node.isContinueStatementNode(e),r=d.Node.isVariableDeclarationNode(e)&&("const"===e.kind||"let"===e.kind);return d.Node.isFunctionDeclarationNode(e)||t||r})}}]),t}(f.AbstractNodeTransformer);b=m=c.__decorate([s.injectable(),c.__param(0,s.inject(u.ServiceIdentifiers.Factory__ICustomNode)),c.__param(1,s.inject(u.ServiceIdentifiers.IOptions)),c.__metadata("design:paramtypes",[Function,Object])],b),t.BlockStatementControlFlowTransformer=b;var m},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var i=function(){function e(e,t){for(var r=0;rr.options.controlFlowFlatteningThreshold)return e;var o=_.controlFlowReplacersMap.get(e.type);return void 0===o?e:Object.assign({},r.controlFlowReplacerFactory(o).replace(e,n,t),{parentNode:n})}})}}],[{key:"getHostNode",value:function(e){var t=g.NodeUtils.getBlockScopesOfNode(e);return 1===t.length?e:(t.pop(),t.length>_.hostNodeSearchMinDepth&&t.splice(0,_.hostNodeSearchMinDepth),t.length>_.hostNodeSearchMaxDepth&&(t.length=_.hostNodeSearchMaxDepth),v.RandomGeneratorUtils.getRandomGenerator().pickone(t))}}]),t}(p.AbstractNodeTransformer);h.controlFlowReplacersMap=new Map([[d.NodeType.BinaryExpression,m.ControlFlowReplacer.BinaryExpressionControlFlowReplacer],[d.NodeType.CallExpression,m.ControlFlowReplacer.CallExpressionControlFlowReplacer],[d.NodeType.LogicalExpression,m.ControlFlowReplacer.LogicalExpressionControlFlowReplacer],[d.NodeType.Literal,m.ControlFlowReplacer.StringLiteralControlFlowReplacer]]),h.hostNodeSearchMinDepth=0,h.hostNodeSearchMaxDepth=2,h=_=c.__decorate([s.injectable(),c.__param(0,s.inject(u.ServiceIdentifiers.Factory__TControlFlowStorage)),c.__param(1,s.inject(u.ServiceIdentifiers.Factory__IControlFlowReplacer)),c.__param(2,s.inject(u.ServiceIdentifiers.Factory__ICustomNode)),c.__param(3,s.inject(u.ServiceIdentifiers.IOptions)),c.__metadata("design:paramtypes",[Function,Function,Function,Object])],h),t.FunctionControlFlowTransformer=h;var _},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var i=function(){function e(e,t){for(var r=0;r1){var o=d.Nodes.getBinaryExpressionNode("+",n.shift(),n.shift());return n.forEach(function(e){o=d.Nodes.getBinaryExpressionNode("+",o,e)}),o}return n[0]}}],[{key:"isLiteralNodeWithStringValue",value:function(e){return e&&f.Node.isLiteralNode(e)&&"string"==typeof e.value}}]),t}(l.AbstractNodeTransformer);p=y=c.__decorate([s.injectable(),c.__param(0,s.inject(u.ServiceIdentifiers.IOptions)),c.__metadata("design:paramtypes",[Object])],p),t.TemplateLiteralTransformer=p;var y},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var i=function(){function e(e,t){for(var r=0;rt.options.deadCodeInjectionThreshold)return e;var n=b.RandomGeneratorUtils.getRandomInteger(0,t.collectedBlockStatements.length-1),o=t.collectedBlockStatements.splice(n,1)[0];return o===e?e:g.replaceBlockStatementNode(e,o)}})}}],[{key:"collectBlockStatementNodes",value:function(e,t){var r=y.NodeUtils.clone(e),n=0,o=!0;l.replace(r,{enter:function(e,t){return d.Node.isBlockStatementNode(e)&&n++,n>g.maxNestedBlockStatementsCount||d.Node.isBreakStatementNode(e)||d.Node.isContinueStatementNode(e)?(o=!1,l.VisitorOption.Break):(d.Node.isIdentifierNode(e)&&!d.Node.isMemberExpressionNode(t)&&(e.name=b.RandomGeneratorUtils.getRandomVariableName(6)),e)}}),o&&t.push(r)}},{key:"replaceBlockStatementNode",value:function(e,t){var r=b.RandomGeneratorUtils.getMathRandom()>.5,n=b.RandomGeneratorUtils.getMathRandom()>.5,o=r?"===":"!==",a=b.RandomGeneratorUtils.getRandomString(3),i=n?a:b.RandomGeneratorUtils.getRandomString(3),c=void 0,s=void 0;r&&n||!r&&!n?(c=e,s=t):(c=t,s=e);var u=p.Nodes.getBlockStatementNode([p.Nodes.getIfStatementNode(p.Nodes.getBinaryExpressionNode(o,p.Nodes.getLiteralNode(a),p.Nodes.getLiteralNode(i)),c,s)]);return u=y.NodeUtils.parentize(u)}}]),t}(f.AbstractNodeTransformer);m.maxNestedBlockStatementsCount=4,m.minCollectedBlockStatementsCount=5,m=g=c.__decorate([s.injectable(),c.__param(0,s.inject(u.ServiceIdentifiers.IOptions)),c.__metadata("design:paramtypes",[Object])],m),t.DeadCodeInjectionTransformer=m;var g},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var i=function(){function e(e,t){for(var r=0;r=g.minimumLengthForStringArray&&y.RandomGeneratorUtils.getMathRandom()<=this.options.stringArrayThreshold}},{key:"getArrayHexadecimalIndex",value:function(e){if(this.stringLiteralHexadecimalIndexCache.has(e))return this.stringLiteralHexadecimalIndexCache.get(e);var t=this.stringArrayStorage.getLength(),r=""+b.Utils.hexadecimalPrefix+b.Utils.decToHex(t);return this.stringArrayStorage.set(t,e),this.stringLiteralHexadecimalIndexCache.set(e,r),r}},{key:"getEncodedValue",value:function(e){var t=void 0,r=void 0;switch(this.options.stringArrayEncoding){case l.StringArrayEncoding.rc4:r=y.RandomGeneratorUtils.getRandomGenerator().pickone(this.rc4Keys),t=d.CryptUtils.btoa(d.CryptUtils.rc4(e,r));break;case l.StringArrayEncoding.base64:t=d.CryptUtils.btoa(e);break;default:t=e}return t=b.Utils.stringToUnicodeEscapeSequence(t,!this.options.unicodeEscapeSequence),{encodedValue:t,key:r}}},{key:"replaceWithStringArrayCallNode",value:function(e){var t=this.getEncodedValue(e),r=t.encodedValue,n=t.key,o=b.Utils.stringRotate(this.stringArrayStorage.getStorageId(),1),a="_"+b.Utils.hexadecimalPrefix+o,i=[g.getHexadecimalLiteralNode(this.getArrayHexadecimalIndex(r))];return n&&i.push(g.getRc4KeyLiteralNode(b.Utils.stringToUnicodeEscapeSequence(n,!this.options.unicodeEscapeSequence))),p.Nodes.getCallExpressionNode(p.Nodes.getIdentifierNode(a),i)}}],[{key:"getHexadecimalLiteralNode",value:function(e){var t=p.Nodes.getLiteralNode(e);return t.obfuscatedNode=!0,t}},{key:"getRc4KeyLiteralNode",value:function(e){var t=p.Nodes.getLiteralNode(e);return t.obfuscatedNode=!0,t}}]),t}(f.AbstractObfuscatingReplacer);m.minimumLengthForStringArray=3,m=g=c.__decorate([s.injectable(),c.__param(0,s.inject(u.ServiceIdentifiers.TCustomNodeGroupStorage)),c.__param(1,s.inject(u.ServiceIdentifiers.TStringArrayStorage)),c.__param(2,s.inject(u.ServiceIdentifiers.IOptions)),c.__metadata("design:paramtypes",[Object,Object,Object])],m),t.StringLiteralObfuscatingReplacer=m;var g},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var o=r(1),a=r(0),i=r(141),c=r(26),s=r(104),u=r(105),l=f=function e(t){n(this,e),Object.assign(this,c.DEFAULT_PRESET,t);var r=i.validateSync(this,f.validatorOptions);if(r.length)throw new ReferenceError("Validation failed. errors:\n"+u.ValidationErrorsFormatter.format(r));Object.assign(this,s.OptionsNormalizer.normalizeOptions(this))};l.validatorOptions={validationError:{target:!1}},o.__decorate([i.IsBoolean(),o.__metadata("design:type",Boolean)],l.prototype,"compact",void 0),o.__decorate([i.IsBoolean(),o.__metadata("design:type",Boolean)],l.prototype,"controlFlowFlattening",void 0),o.__decorate([i.IsNumber(),i.Min(0),i.Max(1),o.__metadata("design:type",Number)],l.prototype,"controlFlowFlatteningThreshold",void 0),o.__decorate([i.IsBoolean(),o.__metadata("design:type",Boolean)],l.prototype,"deadCodeInjection",void 0),o.__decorate([i.IsNumber(),o.__metadata("design:type",Number)],l.prototype,"deadCodeInjectionThreshold",void 0),o.__decorate([i.IsBoolean(),o.__metadata("design:type",Boolean)],l.prototype,"debugProtection",void 0),o.__decorate([i.IsBoolean(),o.__metadata("design:type",Boolean)],l.prototype,"debugProtectionInterval",void 0),o.__decorate([i.IsBoolean(),o.__metadata("design:type",Boolean)],l.prototype,"disableConsoleOutput",void 0),o.__decorate([i.IsArray(),i.ArrayUnique(),i.IsString({each:!0}),o.__metadata("design:type",Array)],l.prototype,"domainLock",void 0),o.__decorate([i.IsBoolean(),o.__metadata("design:type",Boolean)],l.prototype,"mangle",void 0),o.__decorate([i.IsArray(),i.ArrayUnique(),i.IsString({each:!0}),o.__metadata("design:type",Array)],l.prototype,"reservedNames",void 0),o.__decorate([i.IsBoolean(),o.__metadata("design:type",Boolean)],l.prototype,"rotateStringArray",void 0),o.__decorate([i.IsNumber(),o.__metadata("design:type",Number)],l.prototype,"seed",void 0),o.__decorate([i.IsBoolean(),o.__metadata("design:type",Boolean)],l.prototype,"selfDefending",void 0),o.__decorate([i.IsBoolean(),o.__metadata("design:type",Boolean)],l.prototype,"sourceMap",void 0),o.__decorate([i.IsString(),i.ValidateIf(function(e){return Boolean(e.sourceMapBaseUrl)}),i.IsUrl({require_protocol:!0,require_valid_protocol:!0}),o.__metadata("design:type",String)],l.prototype,"sourceMapBaseUrl",void 0),o.__decorate([i.IsString(),o.__metadata("design:type",String)],l.prototype,"sourceMapFileName",void 0),o.__decorate([i.IsIn(["inline","separate"]),o.__metadata("design:type",String)],l.prototype,"sourceMapMode",void 0),o.__decorate([i.IsBoolean(),o.__metadata("design:type",Boolean)],l.prototype,"stringArray",void 0),o.__decorate([i.IsIn([!0,!1,"base64","rc4"]),o.__metadata("design:type",Object)],l.prototype,"stringArrayEncoding",void 0),o.__decorate([i.IsNumber(),i.Min(0),i.Max(1),o.__metadata("design:type",Number)],l.prototype,"stringArrayThreshold",void 0),o.__decorate([i.IsBoolean(),o.__metadata("design:type",Boolean)],l.prototype,"unicodeEscapeSequence",void 0),l=f=o.__decorate([a.injectable(),o.__metadata("design:paramtypes",[Object])],l),t.Options=l;var f},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var o=function(){function e(e,t){for(var r=0;rr)return"break";var a=e[o];s.traverse(a,{enter:function(r){if(l.Node.isCallExpressionNode(r))return a.parentNode!==f.NodeUtils.getBlockScopesOfNode(r)[0]?s.VisitorOption.Skip:void t.analyzeCallExpressionNode(n,e,r)}})}(a))break}return n}},{key:"analyzeCallExpressionNode",value:function(e,t,r){var n=this;p.calleeDataExtractorsList.forEach(function(o){var a=n.calleeDataExtractorFactory(o).extract(t,r.callee);a&&e.push(Object.assign({},a,{stackTrace:n.analyzeRecursive(a.callee.body)}))})}}],[{key:"getLimitIndex",value:function(e){var t=e-1,r=p.limitThresholdActivationLength-1,n=t;return t>r&&(n=Math.round(r+t*p.limitThreshold))>t&&(n=t),n}}]),e}();d.calleeDataExtractorsList=[u.CalleeDataExtractor.FunctionDeclarationCalleeDataExtractor,u.CalleeDataExtractor.FunctionExpressionCalleeDataExtractor,u.CalleeDataExtractor.ObjectExpressionCalleeDataExtractor],d.limitThresholdActivationLength=25,d.limitThreshold=.002,d=p=a.__decorate([i.injectable(),a.__param(0,i.inject(c.ServiceIdentifiers.Factory__ICalleeDataExtractor)),a.__metadata("design:paramtypes",[Function])],d),t.StackTraceAnalyzer=d;var p},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var i=function(){function e(e,t){for(var r=0;r=0?t:null}},{key:"getLength",value:function(){return this.storageLength}},{key:"getStorage",value:function(){return this.storage}},{key:"getStorageId",value:function(){return this.storageId}},{key:"initialize",value:function(){this.storage=[],this.storageId=u.RandomGeneratorUtils.getRandomString(6)}},{key:"mergeWith",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1];this.storage=[].concat(n(this.storage),n(e.getStorage())),t&&(this.storageId=e.getStorageId())}},{key:"set",value:function(e,t){e===this.storageLength?this.storage.push(t):this.storage.splice(e,0,t),this.storageLength++}}]),e}();i.__decorate([s.initializable(),i.__metadata("design:type",Array)],l.prototype,"storage",void 0),i.__decorate([s.initializable(),i.__metadata("design:type",String)],l.prototype,"storageId",void 0),l=i.__decorate([c.injectable()],l),t.ArrayStorage=l},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var i=r(36),c=function(e){function t(){n(this,t);var e=o(this,(t.__proto__||Object.getPrototypeOf(t)).call(this));return e.initialize(),e}return a(t,e),t}(i.MapStorage);t.ControlFlowStorage=c},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var i=function(){function e(e,t){for(var r=0;r> (-2 * bc & 6)) : 0\n ) {\n buffer = chars.indexOf(buffer);\n }\n return output;\n });\n })();\n "}Object.defineProperty(t,"__esModule",{value:!0}),t.AtobTemplate=n},function(e,t,r){"use strict";function n(){return"\n var rc4 = function (str, key) {\n var s = [], j = 0, x, res = '', newStr = '';\n \n str = atob(str);\n \n for (var k = 0, length = str.length; k < length; k++) {\n newStr += '%' + ('00' + str.charCodeAt(k).toString(16)).slice(-2);\n }\n \n str = decodeURIComponent(newStr);\n \t \n\t for (var i = 0; i < 256; i++) {\n s[i] = i;\n }\n \n for (i = 0; i < 256; i++) {\n j = (j + s[i] + key.charCodeAt(i % key.length)) % 256;\n x = s[i];\n s[i] = s[j];\n s[j] = x;\n }\n \n i = 0;\n j = 0;\n \n for (var y = 0; y < str.length; y++) {\n i = (i + 1) % 256;\n j = (j + s[i]) % 256;\n x = s[i];\n s[i] = s[j];\n s[j] = x;\n res += String.fromCharCode(str.charCodeAt(y) ^ s[(s[i] + s[j]) % 256]);\n }\n \n return res;\n }\n "}Object.defineProperty(t,"__esModule",{value:!0}),t.Rc4Template=n},function(e,t,r){"use strict";function n(){return"\n var {singleNodeCallControllerFunctionName} = (function(){\n var firstCall = true;\n \n return function (context, fn){\t\n var rfn = firstCall ? function(){\n if(fn){\n var res = fn.apply(context, arguments);\n fn = null;\n return res;\n }\n } : function(){}\n \n firstCall = false;\n \n return rfn;\n }\n })();\n "}Object.defineProperty(t,"__esModule",{value:!0}),t.SingleNodeCallControllerTemplate=n},function(e,t,r){"use strict";function n(){return"\n var {consoleLogDisableFunctionName} = {singleNodeCallControllerFunctionName}(this, function () {\n var getGlobal = Function('return (function() ' + '{}.constructor(\"return this\")( )' + ');');\n \n var func = function () {};\n var that = getGlobal();\n \n if (!that.console) {\n that.console = (function (func){ \n var c = {}; \n \n c.log = func;\n c.warn = func; \n c.debug = func;\n c.info = func;\n c.error = func;\n c.exception = func;\n c.trace = func;\n \n return c; \n })(func);\n } else {\n that.console.log = func;\n that.console.warn = func; \n that.console.debug = func;\n that.console.info = func;\n that.console.error = func;\n that.console.exception = func;\n that.console.trace = func;\n }\n });\n \n {consoleLogDisableFunctionName}();\n "}Object.defineProperty(t,"__esModule",{value:!0}),t.ConsoleOutputDisableExpressionTemplate=n},function(e,t,r){"use strict";function n(){return"{debugProtectionFunctionName}();"}Object.defineProperty(t,"__esModule",{value:!0}),t.DebugProtectionFunctionCallTemplate=n},function(e,t,r){"use strict";function n(){return"\n setInterval(function () {\n {debugProtectionFunctionName}();\n }, 4000);\n "}Object.defineProperty(t,"__esModule",{value:!0}),t.DebugProtectionFunctionIntervalTemplate=n},function(e,t,r){"use strict";function n(){return"\n var {debugProtectionFunctionName} = function () {\n function debuggerProtection (counter) {\n if (('' + counter / counter)['length'] !== 1 || counter % 20 === 0) {\n (function () {}.constructor('debugger')());\n } else {\n (function () {}.constructor('debugger')());\n }\n \n debuggerProtection(++counter);\n }\n \n try {\n debuggerProtection(0);\n } catch (y) {}\n };\n "}Object.defineProperty(t,"__esModule",{value:!0}),t.DebugProtectionFunctionTemplate=n},function(e,t,r){"use strict";function n(){return'\n var {domainLockFunctionName} = {singleNodeCallControllerFunctionName}(this, function () {\n var getGlobal = Function(\'return (function () \' + \'{}.constructor("return this")()\' + \');\');\n\n var func = function () { \n return {\n key: \'item\',\n value: \'attribute\',\n getAttribute: function () {\n getGlobal()[\'eval\'](\'while(true){}\')();\n }()\n };\n };\n \n var regExp = new RegExp("[{diff}]", "g");\n var domains = "{domains}".replace(regExp, "").split(";");\n var eval = []["forEach"]["constructor"];\n var windowObject = eval("return this")();\n var document;\n var domain;\n \n for (var d in windowObject) {\n if (d.length == 8 && d.charCodeAt(7) == 116 && d.charCodeAt(5) == 101 && d.charCodeAt(3) == 117 && d.charCodeAt(0) == 100) {\n document = d;\n \n break;\n }\n }\n\n for (var d1 in windowObject[document]) {\n if (d1.length == 6 && d1.charCodeAt(5) == 110 && d1.charCodeAt(0) == 100) {\n domain = d1;\n \n break;\n }\n }\n \n if ((!document && !domain) || (!windowObject[document] && !windowObject[document][domain])) {\n return;\n }\n \n var currentDomain = windowObject[document][domain];\n\n var ok = false;\n \n for (var i = 0; i < domains.length; i++) {\n var domain = domains[i];\n var position = currentDomain.length - domain.length;\n var lastIndex = currentDomain.indexOf(domain, position);\n var endsWith = lastIndex !== -1 && lastIndex === position;\n \n if (endsWith) {\n if (currentDomain.length == domain.length || domain.indexOf(".") === 0) {\n ok = true;\n }\n \n break;\n }\n }\n \n if (!ok) {\n data;\n } else {\n return;\n }\n \n func();\n });\n\n {domainLockFunctionName}();\n '}Object.defineProperty(t,"__esModule",{value:!0}),t.DomainLockNodeTemplate=n},function(e,t,r){"use strict";function n(){return"\n var {selfDefendingFunctionName} = {singleNodeCallControllerFunctionName}(this, function () {\n var func1 = function(){return 'dev';},\n func2 = function () {\n return 'window';\n };\n \n var test1 = function () {\n var regExp = new RegExp('"+o.Utils.stringToUnicodeEscapeSequence("\\w+ *\\(\\) *{\\w+ *['|\"].+['|\"];? *}")+"');\n \n return !regExp.test(func1.toString());\n };\n \n var test2 = function () {\n var regExp = new RegExp('"+o.Utils.stringToUnicodeEscapeSequence("(\\\\[x|u](\\w){2,4})+")+"');\n \n return regExp.test(func2.toString());\n };\n \n var recursiveFunc1 = function (string) {\n var i = ~-1 >> 1 + 255 % 0;\n \n if (string.indexOf('i' === i)) {\n recursiveFunc2(string)\n }\n };\n \n var recursiveFunc2 = function (string) {\n var i = ~-4 >> 1 + 255 % 0;\n \n if (string.indexOf((true+\"\")[3]) !== i) {\n recursiveFunc1(string)\n }\n };\n \n if (!test1()) {\n if (!test2()) {\n recursiveFunc1('indеxOf');\n } else {\n recursiveFunc1('indexOf');\n }\n } else {\n recursiveFunc1('indеxOf');\n }\n })\n \n {selfDefendingFunctionName}();\n "}Object.defineProperty(t,"__esModule",{value:!0});var o=r(9);t.SelfDefendingTemplate=n},function(e,t,r){"use strict";function n(){return"\n var StatesClass = function (rc4Bytes) {\n this.rc4Bytes = rc4Bytes;\n this.states = [1, 0, 0];\n this.newState = function(){return 'newState';};\n this.firstState = '"+o.Utils.stringToUnicodeEscapeSequence("\\w+ *\\(\\) *{\\w+ *")+"';\n this.secondState = '"+o.Utils.stringToUnicodeEscapeSequence("['|\"].+['|\"];? *}")+"';\n };\n \n StatesClass.prototype.checkState = function () {\n var regExp = new RegExp(this.firstState + this.secondState);\n\n return this.runState(regExp.test(this.newState.toString()) ? --this.states[1] : --this.states[0]);\n };\n \n StatesClass.prototype.runState = function (stateResult) {\n if (!Boolean(~stateResult)) {\n return stateResult;\n }\n \n return this.getState(this.rc4Bytes);\n };\n\n StatesClass.prototype.getState = function (rc4Bytes) {\n for (var i = 0, len = this.states.length; i < len; i++) {\n this.states.push(Math.round(Math.random()));\n len = this.states.length;\n }\n \n return rc4Bytes(this.states[0]);\n };\n\n new StatesClass({stringArrayCallsWrapperName}).checkState();\n "}Object.defineProperty(t,"__esModule",{value:!0});var o=r(9);t.SelfDefendingTemplate=n},function(e,t,r){"use strict";function n(){return" \n if ({stringArrayCallsWrapperName}.initialized === undefined) {\n {atobPolyfill}\n \n {stringArrayCallsWrapperName}.base64DecodeUnicode = function (str) {\n var string = atob(str);\n var newStringChars = [];\n \n for (var i = 0, length = string.length; i < length; i++) {\n newStringChars += '%' + ('00' + string.charCodeAt(i).toString(16)).slice(-2);\n }\n \n return decodeURIComponent(newStringChars);\n };\n \n {stringArrayCallsWrapperName}.data = {};\n \n {stringArrayCallsWrapperName}.initialized = true;\n }\n \n var cachedValue = {stringArrayCallsWrapperName}.data[index];\n \n if (cachedValue === undefined) {\n {selfDefendingCode}\n \n value = {stringArrayCallsWrapperName}.base64DecodeUnicode(value);\n {stringArrayCallsWrapperName}.data[index] = value;\n } else {\n value = cachedValue;\n } \n "}Object.defineProperty(t,"__esModule",{value:!0}),t.StringArrayBase64DecodeNodeTemplate=n},function(e,t,r){"use strict";function n(){return"\n var {stringArrayCallsWrapperName} = function (index, key) {\n index = index - 0;\n \n var value = {stringArrayName}[index];\n \n {decodeNodeTemplate}\n \n return value;\n };\n "}Object.defineProperty(t,"__esModule",{value:!0}),t.StringArrayCallsWrapperTemplate=n},function(e,t,r){"use strict";function n(){return"\n if ({stringArrayCallsWrapperName}.initialized === undefined) {\n {atobPolyfill}\n \n {rc4Polyfill}\n {stringArrayCallsWrapperName}.rc4 = rc4;\n \n {stringArrayCallsWrapperName}.data = {};\n \n {stringArrayCallsWrapperName}.initialized = true;\n }\n \n var cachedValue = {stringArrayCallsWrapperName}.data[index];\n\n if (cachedValue === undefined) {\n if ({stringArrayCallsWrapperName}.once === undefined) {\n {selfDefendingCode}\n \n {stringArrayCallsWrapperName}.once = true;\n }\n \n value = {stringArrayCallsWrapperName}.rc4(value, key);\n {stringArrayCallsWrapperName}.data[index] = value;\n } else {\n value = cachedValue;\n }\n "}Object.defineProperty(t,"__esModule",{value:!0}),t.StringArrayRc4DecodeNodeTemplate=n},function(e,t,r){"use strict";function n(){return"\n var {stringArrayName} = [{stringArray}];\n "}Object.defineProperty(t,"__esModule",{value:!0}),t.StringArrayTemplate=n},function(e,t,r){"use strict";function n(){return"\n var selfDefendingFunc = function () { \n var object = {\n data: {\n key: 'cookie',\n value: 'timeout'\n },\n setCookie: function (options, name, value, document) {\n document = document || {};\n \n var updatedCookie = name + \"=\" + value;\n\n var i = 0;\n \n for (var i = 0, len = options.length; i < len; i++) { \n var propName = options[i];\n \n updatedCookie += \"; \" + propName;\n \n var propValue = options[propName];\n \n options.push(propValue);\n len = options.length;\n \n if (propValue !== true) {\n updatedCookie += \"=\" + propValue;\n }\n }\n\n document['cookie'] = updatedCookie;\n },\n removeCookie: function(){return 'dev';},\n getCookie: function (document, name) { \n document = document || function (value) { return value };\n var matches = document(new RegExp(\n \"(?:^|; )\" + name.replace(/([.$?*|{}()[]\\/+^])/g, '\\$1') + \"=([^;]*)\"\n ));\n \n var func = function (param1, param2) {\n param1(++param2);\n };\n \n func({whileFunctionName}, {timesName});\n \n return matches ? decodeURIComponent(matches[1]) : undefined;\n }\n };\n \n var test1 = function () {\n var regExp = new RegExp('"+o.Utils.stringToUnicodeEscapeSequence("\\w+ *\\(\\) *{\\w+ *['|\"].+['|\"];? *}")+"');\n \n return regExp.test(object.removeCookie.toString());\n };\n \n object['updateCookie'] = test1;\n \n var cookie = '';\n var result = object['updateCookie']();\n \n if (!result) {\n object['setCookie'](['*'], 'counter', 1);\n } else if (result) {\n cookie = object['getCookie'](null, 'counter'); \n } else {\n object['removeCookie']();\n }\n };\n \n selfDefendingFunc();\n "}Object.defineProperty(t,"__esModule",{value:!0});var o=r(9);t.SelfDefendingTemplate=n},function(e,t,r){"use strict";function n(){return"\n (function (array, {timesName}) {\n var {whileFunctionName} = function (times) {\n while (--times) {\n array['push'](array['shift']());\n }\n };\n \n {code}\n })({stringArrayName}, 0x{stringArrayRotateValue});\n "}Object.defineProperty(t,"__esModule",{value:!0}),t.StringArrayRotateFunctionTemplate=n},function(e,t){e.exports=require("chance")},function(e,t){e.exports=require("class-validator")},function(e,t){e.exports=require("commander")},function(e,t){e.exports=require("esmangle")},function(e,t){e.exports=require("events")},function(e,t){e.exports=require("fs")},function(e,t){e.exports=require("mkdirp")},function(e,t){e.exports=require("reflect-metadata")}]); +require("source-map-support").install(),module.exports=function(e){function t(n){if(r[n])return r[n].exports;var o=r[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var r={};return t.m=e,t.c=r,t.i=function(e){return e},t.d=function(e,r,n){t.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:n})},t.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(r,"a",r),r},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=39)}([function(e,t){e.exports=require("inversify")},function(e,t){e.exports=require("tslib")},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.ServiceIdentifiers={Factory__ICalleeDataExtractor:Symbol("Factory"),Factory__IControlFlowReplacer:Symbol("Factory"),Factory__ICustomNode:Symbol("Factory"),Factory__ICustomNodeGroup:Symbol("Factory"),Factory__IIdentifierObfuscatingReplacer:Symbol("Factory"),Factory__INodeTransformer:Symbol("Factory"),Factory__IObfuscationResult:Symbol("Factory"),Factory__IObfuscatingReplacer:Symbol("Factory"),Factory__TControlFlowStorage:Symbol("Factory"),ICalleeDataExtractor:Symbol("ICalleeDataExtractor"),ICustomNodeGroup:Symbol("ICustomNodeGroup"),IControlFlowReplacer:Symbol("IControlFlowReplacer"),IDeadCodeInjectionReplacer:Symbol("IDeadCodeInjectionReplacer"),IIdentifierObfuscatingReplacer:Symbol("IIdentifierObfuscatingReplacer"),IJavaScriptObfuscator:Symbol("IJavaScriptObfuscator"),INodeTransformer:Symbol("INodeTransformer"),IObfuscationEventEmitter:Symbol("IObfuscationEventEmitter"),IObfuscationResult:Symbol("IObfuscationResult"),IObfuscator:Symbol("IObfuscator"),IOptions:Symbol("IOptions"),IObfuscatingReplacer:Symbol("IObfuscatingReplacer"),ISourceMapCorrector:Symbol("ISourceMapCorrector"),IStackTraceAnalyzer:Symbol("IStackTraceAnalyzer"),Newable__ICustomNode:Symbol("Newable"),Newable__TControlFlowStorage:Symbol("Newable"),TCustomNodeGroupStorage:Symbol("TCustomNodeGroupStorage"),TStringArrayStorage:Symbol("TStringArrayStorage")}},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var o="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},a=function(){function e(e,t){for(var r=0;r1&&void 0!==arguments[1]?arguments[1]:0;if(l.Node.isNodeHasBlockStatement(e)){if(void 0===e.body[t])throw new ReferenceError("Wrong index `"+t+"`. Block-statement body length is `"+e.body.length+"`");return e.body[t]}throw new TypeError("The specified node have no a block-statement")}},{key:"getBlockScopesOfNode",value:function(t){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[],n=t.parentNode;if(!n)throw new ReferenceError("`parentNode` property of given node is `undefined`");if(l.Node.isBlockStatementNode(n)){if(!n.parentNode)throw new ReferenceError("`parentNode` property of `parentNode` of given node is `undefined`");-1!==e.nodesWithBlockScope.indexOf(n.parentNode.type)&&r.push(n)}return l.Node.isProgramNode(n)?(r.push(n),r):e.getBlockScopesOfNode(n,r)}},{key:"getNodeBlockScopeDepth",value:function(t){var r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=t.parentNode;if(!n)throw new ReferenceError("`parentNode` property of given node is `undefined`");return l.Node.isProgramNode(n)?r:l.Node.isBlockStatementNode(t)&&-1!==e.nodesWithBlockScope.indexOf(n.type)?e.getNodeBlockScopeDepth(n,++r):e.getNodeBlockScopeDepth(n,r)}},{key:"getUnaryExpressionArgumentNode",value:function(t){return l.Node.isUnaryExpressionNode(t.argument)?e.getUnaryExpressionArgumentNode(t.argument):t.argument}},{key:"parentize",value:function(e){var t=!0;return s.traverse(e,{enter:function(e,r){var n=void 0;t?(e.type===u.NodeType.Program?n=e:(n=f.Nodes.getProgramNode([e]),n.parentNode=n),t=!1):n=r||e,e.parentNode=n,e.obfuscatedNode=!1}}),e}},{key:"typedReplace",value:function(t,r,n){e.typedTraverse(t,r,n,"replace")}},{key:"typedTraverse",value:function(e,t,r){var n=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"traverse";s[n](e,{enter:function(e,n){if(e.type===t&&r.enter)return r.enter(e,n)},leave:function(e,n){if(e.type===t&&r.leave)return r.leave(e,n)}})}}]),e}();d.nodesWithBlockScope=[u.NodeType.ArrowFunctionExpression,u.NodeType.FunctionDeclaration,u.NodeType.FunctionExpression,u.NodeType.MethodDefinition,u.NodeType.Program],t.NodeUtils=d},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var o=function(){function e(e,t){for(var r=0;r1&&void 0!==arguments[1]?arguments[1]:e.randomGeneratorPool;return e.getRandomGenerator().string({length:t,pool:r})}},{key:"getRandomVariableName",value:function(t){var r="_"+i.Utils.hexadecimalPrefix,n=""+r+i.Utils.decToHex(e.getRandomInteger(1e4,99999999)).substr(0,t);return e.randomVariableNameSet.has(n)?e.getRandomVariableName(t):(e.randomVariableNameSet.add(n),n)}}]),e}();c.randomGeneratorPool="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",c.randomGeneratorPoolNumbers="0123456789",c.randomGeneratorPoolHexadecimal="abcdef"+c.randomGeneratorPoolNumbers,c.randomGeneratorPoolWithNumbers=""+c.randomGeneratorPool+c.randomGeneratorPoolNumbers,c.randomVariableNameSet=new Set,t.RandomGeneratorUtils=c},function(e,t,r){"use strict";function n(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"initialize",t=Object.keys(this)[0];return function(r,n){var o={configurable:!0,enumerable:!0},a=r[e];if(!a||"function"!=typeof a)throw new Error("`"+e+"` method with initialization logic not found. `@"+t+"` decorator requires `"+e+"` method");var i="_"+n,c=Object.getOwnPropertyDescriptor(r,i)||o,s=Object.getOwnPropertyDescriptor(r,e)||o,u=s.value;return Object.defineProperty(r,n,Object.assign({},c,{get:function(){if(void 0===this[i])throw new Error("Property `"+n+"` is not initialized! Initialize it first!");return this[i]},set:function(e){this[i]=e}})),Object.defineProperty(r,e,Object.assign({},s,{value:function(){u.apply(this,arguments),this[n]}})),c}}Object.defineProperty(t,"__esModule",{value:!0}),t.initializable=n},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var o=function(){function e(e,t){for(var r=0;r0&&void 0!==arguments[0]?arguments[0]:[];return{type:i.NodeType.Program,body:e,sourceType:"script",obfuscatedNode:!1}}},{key:"getArrayExpressionNode",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];return{type:i.NodeType.ArrayExpression,elements:e}}},{key:"getAssignmentExpressionNode",value:function(e,t,r){return{type:i.NodeType.AssignmentExpression,operator:e,left:t,right:r,obfuscatedNode:!1}}},{key:"getBinaryExpressionNode",value:function(e,t,r){return{type:i.NodeType.BinaryExpression,operator:e,left:t,right:r,obfuscatedNode:!1}}},{key:"getBlockStatementNode",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];return{type:i.NodeType.BlockStatement,body:e,obfuscatedNode:!1}}},{key:"getBreakStatement",value:function(e){var t={type:i.NodeType.BreakStatement,obfuscatedNode:!1};return e&&(t.label=e),t}},{key:"getCatchClauseNode",value:function(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];return{type:i.NodeType.CatchClause,param:e.getIdentifierNode("err"),body:e.getBlockStatementNode(t),obfuscatedNode:!1}}},{key:"getCallExpressionNode",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:[];return{type:i.NodeType.CallExpression,callee:e,arguments:t,obfuscatedNode:!1}}},{key:"getContinueStatement",value:function(e){var t={type:i.NodeType.ContinueStatement,obfuscatedNode:!1};return e&&(t.label=e),t}},{key:"getExpressionStatementNode",value:function(e){return{type:i.NodeType.ExpressionStatement,expression:e,obfuscatedNode:!1}}},{key:"getFunctionDeclarationNode",value:function(t,r,n){return{type:i.NodeType.FunctionDeclaration,id:e.getIdentifierNode(t),params:r,body:n,generator:!1,obfuscatedNode:!1}}},{key:"getFunctionExpressionNode",value:function(e,t){return{type:i.NodeType.FunctionExpression,params:e,body:t,generator:!1,obfuscatedNode:!1}}},{key:"getIfStatementNode",value:function(e,t,r){return Object.assign({type:i.NodeType.IfStatement,test:e,consequent:t},r&&{alternate:r},{obfuscatedNode:!1})}},{key:"getIdentifierNode",value:function(e){return{type:i.NodeType.Identifier,name:e,obfuscatedNode:!1}}},{key:"getLabeledStatement",value:function(e,t){return{type:i.NodeType.LabeledStatement,label:e,body:t,obfuscatedNode:!1}}},{key:"getLiteralNode",value:function(e,t){return t=void 0!==t?t:"'"+e+"'",{type:i.NodeType.Literal,value:e,raw:t,"x-verbatim-property":{content:t,precedence:a.Precedence.Primary},obfuscatedNode:!1}}},{key:"getLogicalExpressionNode",value:function(e,t,r){return{type:i.NodeType.LogicalExpression,operator:e,left:t,right:r,obfuscatedNode:!1}}},{key:"getMemberExpressionNode",value:function(e,t){var r=arguments.length>2&&void 0!==arguments[2]&&arguments[2];return{type:i.NodeType.MemberExpression,computed:r,object:e,property:t,obfuscatedNode:!1}}},{key:"getObjectExpressionNode",value:function(e){return{type:i.NodeType.ObjectExpression,properties:e,obfuscatedNode:!1}}},{key:"getPropertyNode",value:function(e,t){var r=arguments.length>2&&void 0!==arguments[2]&&arguments[2];return{type:i.NodeType.Property,key:e,value:t,kind:"init",method:!1,shorthand:!1,computed:r,obfuscatedNode:!1}}},{key:"getUnaryExpressionNode",value:function(e,t){var r=!(arguments.length>2&&void 0!==arguments[2])||arguments[2];return{type:i.NodeType.UnaryExpression,operator:e,argument:t,prefix:r,obfuscatedNode:!1}}},{key:"getReturnStatementNode",value:function(e){return{type:i.NodeType.ReturnStatement,argument:e,obfuscatedNode:!1}}},{key:"getSwitchStatementNode",value:function(e,t){return{type:i.NodeType.SwitchStatement,discriminant:e,cases:t,obfuscatedNode:!1}}},{key:"getSwitchCaseNode",value:function(e,t){return{type:i.NodeType.SwitchCase,test:e,consequent:t,obfuscatedNode:!1}}},{key:"getUpdateExpressionNode",value:function(e,t){return{type:i.NodeType.UpdateExpression,operator:e,argument:t,prefix:!1,obfuscatedNode:!1}}},{key:"getVariableDeclarationNode",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"var";return{type:i.NodeType.VariableDeclaration,declarations:e,kind:t,obfuscatedNode:!1}}},{key:"getVariableDeclaratorNode",value:function(e,t){return{type:i.NodeType.VariableDeclarator,id:e,init:t,obfuscatedNode:!1}}},{key:"getWhileStatementNode",value:function(e,t){return{type:i.NodeType.WhileStatement,test:e,body:t,obfuscatedNode:!1}}}]),e}();t.Nodes=c},function(e,t,r){"use strict";function n(e){if(Array.isArray(e)){for(var t=0,r=Array(e.length);t-1||0===e.indexOf("//")?e.split("/")[2]:e.split("/")[0],t=t.split(":")[0]}},{key:"isCeilNumber",value:function(e){return e%1==0}},{key:"strEnumify",value:function(e){return e}},{key:"stringRotate",value:function(e,t){if(!e)throw new ReferenceError("Cannot rotate empty string.");for(var r=0;r1&&void 0!==arguments[1]&&arguments[1],n=t+"-"+String(r);if(e.stringToUnicodeEscapeSequenceCache.has(n))return e.stringToUnicodeEscapeSequenceCache.get(n);var o=new RegExp("[\\s\\S]","g"),a=new RegExp("[^a-zA-Z0-9]"),i=new RegExp("[\\x00-\\x7F]"),c=void 0,s=void 0,u=t.replace(o,function(e){return r&&!a.exec(e)?e:(i.exec(e)?(c="\\x",s="00"):(c="\\u",s="0000"),""+c+(s+e.charCodeAt(0).toString(16)).slice(-s.length))});return e.stringToUnicodeEscapeSequenceCache.set(n,u),u}}]),e}();s.hexadecimalPrefix="0x",s.stringToUnicodeEscapeSequenceCache=new Map,t.Utils=s},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});!function(e){e[e.BinaryExpressionFunctionNode=0]="BinaryExpressionFunctionNode",e[e.BlockStatementControlFlowFlatteningNode=1]="BlockStatementControlFlowFlatteningNode",e[e.CallExpressionControlFlowStorageCallNode=2]="CallExpressionControlFlowStorageCallNode",e[e.CallExpressionFunctionNode=3]="CallExpressionFunctionNode",e[e.ControlFlowStorageNode=4]="ControlFlowStorageNode",e[e.ConsoleOutputDisableExpressionNode=5]="ConsoleOutputDisableExpressionNode",e[e.DebugProtectionFunctionCallNode=6]="DebugProtectionFunctionCallNode",e[e.DebugProtectionFunctionIntervalNode=7]="DebugProtectionFunctionIntervalNode",e[e.DebugProtectionFunctionNode=8]="DebugProtectionFunctionNode",e[e.DomainLockNode=9]="DomainLockNode",e[e.ExpressionWithOperatorControlFlowStorageCallNode=10]="ExpressionWithOperatorControlFlowStorageCallNode",e[e.LogicalExpressionFunctionNode=11]="LogicalExpressionFunctionNode",e[e.NodeCallsControllerFunctionNode=12]="NodeCallsControllerFunctionNode",e[e.SelfDefendingUnicodeNode=13]="SelfDefendingUnicodeNode",e[e.StringArrayCallsWrapper=14]="StringArrayCallsWrapper",e[e.StringArrayNode=15]="StringArrayNode",e[e.StringArrayRotateFunctionNode=16]="StringArrayRotateFunctionNode",e[e.StringLiteralControlFlowStorageCallNode=17]="StringLiteralControlFlowStorageCallNode",e[e.StringLiteralNode=18]="StringLiteralNode"}(t.CustomNode||(t.CustomNode={}))},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var o=r(1),a=r(0),i=r(2),c=r(4),s=function e(t){n(this,e),this.nodeIdentifier=c.RandomGeneratorUtils.getRandomInteger(0,1e4),this.options=t};s=o.__decorate([a.injectable(),o.__param(0,a.inject(i.ServiceIdentifiers.IOptions)),o.__metadata("design:paramtypes",[Object])],s),t.AbstractNodeTransformer=s},function(e,t){e.exports=require("estraverse")},function(e,t){e.exports=require("string-template")},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(9);t.NodeType=n.Utils.strEnumify({ArrayExpression:"ArrayExpression",ArrowFunctionExpression:"ArrowFunctionExpression",AssignmentExpression:"AssignmentExpression",AssignmentPattern:"AssignmentPattern",BinaryExpression:"BinaryExpression",BlockStatement:"BlockStatement",BreakStatement:"BreakStatement",CallExpression:"CallExpression",CatchClause:"CatchClause",ClassDeclaration:"ClassDeclaration",ContinueStatement:"ContinueStatement",ExpressionStatement:"ExpressionStatement",FunctionDeclaration:"FunctionDeclaration",FunctionExpression:"FunctionExpression",Identifier:"Identifier",IfStatement:"IfStatement",LabeledStatement:"LabeledStatement",Literal:"Literal",LogicalExpression:"LogicalExpression",MemberExpression:"MemberExpression",MethodDefinition:"MethodDefinition",ObjectExpression:"ObjectExpression",ObjectPattern:"ObjectPattern",Program:"Program",Property:"Property",ReturnStatement:"ReturnStatement",SwitchCase:"SwitchCase",SwitchStatement:"SwitchStatement",TemplateLiteral:"TemplateLiteral",TryStatement:"TryStatement",UnaryExpression:"UnaryExpression",UpdateExpression:"UpdateExpression",VariableDeclaration:"VariableDeclaration",VariableDeclarator:"VariableDeclarator",WhileStatement:"WhileStatement"})},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.ObfuscationEvent={AfterObfuscation:"afterObfuscation",BeforeObfuscation:"beforeObfuscation"}},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var o=function(){function e(e,t){for(var r=0;r1&&void 0!==arguments[1]?arguments[1]:{},r=new i.InversifyContainerFacade(t),n=r.get(a.ServiceIdentifiers.IOptions);s.RandomGeneratorUtils.initializeRandomGenerator(n.seed);var o=r.get(a.ServiceIdentifiers.IJavaScriptObfuscator),c=o.obfuscate(e);return s.RandomGeneratorUtils.clearRandomGenerator(),c}},{key:"runCLI",value:function(e){new c.JavaScriptObfuscatorCLI(e).run()}}]),e}();t.JavaScriptObfuscator=u},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var o=function(){function e(e,t){for(var r=0;r3&&void 0!==arguments[3]?arguments[3]:0,a=void 0;a=t.length?e.getOptimalBlockScope(t,o):r,e.prependNode(a,n)}},{key:"getOptimalBlockScope",value:function(t,r){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1/0,o=t[r];if(n<=0)throw new Error("Invalid `deep` argument value. Value should be bigger then 0.");return n>1&&o.stackTrace.length?e.getOptimalBlockScope(o.stackTrace,0,--n):o.callee}},{key:"getRandomStackTraceIndex",value:function(e){return i.RandomGeneratorUtils.getRandomInteger(0,Math.max(0,Math.round(e-1)))}},{key:"insertNodeAtIndex",value:function(t,r,o){e.validateBodyStatements(r)||(r=[]),r=e.parentizeBodyStatementsBeforeAppend(t,r),t.body=[].concat(n(t.body.slice(0,o)),n(r),n(t.body.slice(o)))}},{key:"prependNode",value:function(t,r){e.validateBodyStatements(r)||(r=[]),r=e.parentizeBodyStatementsBeforeAppend(t,r),t.body=[].concat(n(r),n(t.body))}},{key:"parentizeBodyStatementsBeforeAppend",value:function(e,t){return t.forEach(function(t){t.parentNode=e}),t}},{key:"validateBodyStatements",value:function(e){return e.every(function(e){return!!e&&e.hasOwnProperty("type")})}}]),e}();t.NodeAppender=c},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var o=function(){function e(e,t){for(var r=0;r>8-o%1*8)){if((n=e.charCodeAt(o+=.75))>255)throw new Error("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range.");r=r<<8|n}return t}},{key:"hideString",value:function(e,t){var r=a.RandomGeneratorUtils.getRandomGenerator().string({length:t,pool:a.RandomGeneratorUtils.randomGeneratorPool}),n=r.replace(new RegExp("["+function(e){return e.replace(/[-\/\\^$*+?.()|[\]{}]/g,"\\$&")}(e)+"]","g"),""),o=n.split("");return a.RandomGeneratorUtils.getRandomGenerator().shuffle(o),n=o.join(""),[function(e,t){for(var r=-1,n=-1,o="";r1&&void 0!==arguments[1]&&arguments[1];this.storage=new Map([].concat(n(this.storage),n(e.getStorage()))),t&&(this.storageId=e.getStorageId())}},{key:"set",value:function(e,t){this.storage.set(e,t)}}]),e}();c.__decorate([u.initializable(),c.__metadata("design:type",String)],f.prototype,"storageId",void 0),c.__decorate([u.initializable(),c.__metadata("design:type",Map)],f.prototype,"storage",void 0),f=c.__decorate([s.injectable()],f),t.MapStorage=f},function(e,t){e.exports=require("esprima")},function(e,t){e.exports=require("path")},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(16);e.exports=n.JavaScriptObfuscator},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var o=function(){function e(e,t){for(var r=0;r [options]").option("-o, --output ","Output path for obfuscated code").option("--compact ","Disable one line output code compacting",s.BooleanSanitizer).option("--controlFlowFlattening ","Enables control flow flattening",s.BooleanSanitizer).option("--controlFlowFlatteningThreshold ","The probability that the control flow flattening transformation will be applied to the node",parseFloat).option("--deadCodeInjection ","Enables dead code injection",s.BooleanSanitizer).option("--deadCodeInjectionThreshold ","The probability that the dead code injection transformation will be applied to the node",parseFloat).option("--debugProtection ","Disable browser Debug panel (can cause DevTools enabled browser freeze)",s.BooleanSanitizer).option("--debugProtectionInterval ","Disable browser Debug panel even after page was loaded (can cause DevTools enabled browser freeze)",s.BooleanSanitizer).option("--disableConsoleOutput ","Allow console.log, console.info, console.error and console.warn messages output into browser console",s.BooleanSanitizer).option("--domainLock ","Blocks the execution of the code in domains that do not match the passed RegExp patterns (comma separated)",function(e){return e.split(",")}).option("--mangle ","Enables mangling of variable names",s.BooleanSanitizer).option("--reservedNames ","Disable obfuscation of variable names, function names and names of function parameters that match the passed RegExp patterns (comma separated)",function(e){return e.split(",")}).option("--rotateStringArray ","Disable rotation of unicode array values during obfuscation",s.BooleanSanitizer).option("--seed ","Sets seed for random generator. This is useful for creating repeatable results.",parseFloat).option("--selfDefending ","Disables self-defending for obfuscated code",s.BooleanSanitizer).option("--sourceMap ","Enables source map generation",s.BooleanSanitizer).option("--sourceMapBaseUrl ","Sets base url to the source map import url when `--sourceMapMode=separate`").option("--sourceMapFileName ","Sets file name for output source map when `--sourceMapMode=separate`").option("--sourceMapMode [inline, separate]","Specify source map output mode",u.SourceMapModeSanitizer).option("--stringArray ","Disables gathering of all literal strings into an array and replacing every literal string with an array call",s.BooleanSanitizer).option("--stringArrayEncoding [true, false, base64, rc4]","Encodes all strings in strings array using base64 or rc4 (this option can slow down your code speed",l.StringArrayEncodingSanitizer).option("--stringArrayThreshold ","The probability that the literal string will be inserted into stringArray (Default: 0.8, Min: 0, Max: 1)",parseFloat).option("--unicodeEscapeSequence ","Allows to enable/disable string conversion to unicode escape sequence",s.BooleanSanitizer).parse(this.rawArguments)}},{key:"configureHelp",value:function(){this.commands.on("--help",function(){console.log(" Examples:\n"),console.log(" %> javascript-obfuscator in.js --compact true --selfDefending false"),console.log(" %> javascript-obfuscator in.js --output out.js --compact true --selfDefending false"),console.log("")})}},{key:"getData",value:function(){this.sourceCode=f.CLIUtils.readFile(this.inputPath)}},{key:"processData",value:function(){var e=this.buildOptions(),t=f.CLIUtils.getOutputCodePath(this.commands.output,this.inputPath);e.sourceMap?this.processDataWithSourceMap(t,e):this.processDataWithoutSourceMap(t,e)}},{key:"processDataWithoutSourceMap",value:function(e,t){var r=d.JavaScriptObfuscator.obfuscate(this.sourceCode,t).getObfuscatedCode();f.CLIUtils.writeFile(e,r)}},{key:"processDataWithSourceMap",value:function(e,t){var r=f.CLIUtils.getOutputSourceMapPath(e,t.sourceMapFileName||"");t=Object.assign({},t,{sourceMapFileName:i.basename(r)});var n=d.JavaScriptObfuscator.obfuscate(this.sourceCode,t);f.CLIUtils.writeFile(e,n.getObfuscatedCode()),"separate"===t.sourceMapMode&&n.getSourceMap()&&f.CLIUtils.writeFile(r,n.getSourceMap())}}]),e}();t.JavaScriptObfuscatorCLI=p},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.BooleanSanitizer=function(e){return"true"===e||"1"===e}},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(21);t.SourceMapModeSanitizer=function(e){if(!Object.keys(n.SourceMapMode).some(function(t){return n.SourceMapMode[t]===e}))throw new ReferenceError("Invalid value of `--sourceMapMode` option");return e}},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(24);t.StringArrayEncodingSanitizer=function(e){switch(e){case"true":case"1":case n.StringArrayEncoding.base64:return!0;case n.StringArrayEncoding.rc4:return n.StringArrayEncoding.rc4;default:return!1}}},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var o=function(){function e(e,t){for(var r=0;r1&&void 0!==arguments[1]?arguments[1]:"";return t&&(e=e.substring(0,e.lastIndexOf("/"))+"/"+t),/\.js\.map$/.test(e)?/\.js$/.test(e)&&(e+=".map"):e=e.split(".")[0]+".js.map",e}},{key:"getPackageConfig",value:function(){return JSON.parse(a.readFileSync(c.join(c.dirname(a.realpathSync(process.argv[1])),"../package.json"),e.encoding))}},{key:"isFilePath",value:function(e){try{return a.statSync(e).isFile()}catch(e){return!1}}},{key:"readFile",value:function(t){return a.readFileSync(t,e.encoding)}},{key:"validateInputPath",value:function(t){if(!e.isFilePath(t))throw new ReferenceError("Given input path must be a valid file path");if(-1===e.availableInputExtensions.indexOf(c.extname(t)))throw new ReferenceError("Input file must have .js extension")}},{key:"writeFile",value:function(t,r){i.sync(c.dirname(t)),a.writeFileSync(t,r,{encoding:e.encoding})}}]),e}();s.availableInputExtensions=[".js"],s.encoding="utf8",t.CLIUtils=s},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(17),o=r(0),a=r(2),i=r(10),c=r(30),s=r(56),u=r(69),l=r(71),f=r(74),d=r(78),p=r(57),y=r(58),b=r(62),m=r(59),g=r(63),v=r(55),h=r(66),_=r(67),N=r(68),O=r(70),S=r(64),C=r(60),w=r(72),j=r(73),I=r(75),E=r(76),T=r(77),F=r(65),k=r(61);t.customNodesModule=new o.ContainerModule(function(e){e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(p.BinaryExpressionFunctionNode).whenTargetNamed(i.CustomNode.BinaryExpressionFunctionNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(y.BlockStatementControlFlowFlatteningNode).whenTargetNamed(i.CustomNode.BlockStatementControlFlowFlatteningNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(b.CallExpressionControlFlowStorageCallNode).whenTargetNamed(i.CustomNode.CallExpressionControlFlowStorageCallNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(m.CallExpressionFunctionNode).whenTargetNamed(i.CustomNode.CallExpressionFunctionNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(g.ControlFlowStorageNode).whenTargetNamed(i.CustomNode.ControlFlowStorageNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(v.ConsoleOutputDisableExpressionNode).whenTargetNamed(i.CustomNode.ConsoleOutputDisableExpressionNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(h.DebugProtectionFunctionCallNode).whenTargetNamed(i.CustomNode.DebugProtectionFunctionCallNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(_.DebugProtectionFunctionIntervalNode).whenTargetNamed(i.CustomNode.DebugProtectionFunctionIntervalNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(N.DebugProtectionFunctionNode).whenTargetNamed(i.CustomNode.DebugProtectionFunctionNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(O.DomainLockNode).whenTargetNamed(i.CustomNode.DomainLockNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(S.ExpressionWithOperatorControlFlowStorageCallNode).whenTargetNamed(i.CustomNode.ExpressionWithOperatorControlFlowStorageCallNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(C.LogicalExpressionFunctionNode).whenTargetNamed(i.CustomNode.LogicalExpressionFunctionNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(w.NodeCallsControllerFunctionNode).whenTargetNamed(i.CustomNode.NodeCallsControllerFunctionNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(j.SelfDefendingUnicodeNode).whenTargetNamed(i.CustomNode.SelfDefendingUnicodeNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(I.StringArrayCallsWrapper).whenTargetNamed(i.CustomNode.StringArrayCallsWrapper),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(E.StringArrayNode).whenTargetNamed(i.CustomNode.StringArrayNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(T.StringArrayRotateFunctionNode).whenTargetNamed(i.CustomNode.StringArrayRotateFunctionNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(F.StringLiteralControlFlowStorageCallNode).whenTargetNamed(i.CustomNode.StringLiteralControlFlowStorageCallNode),e(a.ServiceIdentifiers.Newable__ICustomNode).toConstructor(k.StringLiteralNode).whenTargetNamed(i.CustomNode.StringLiteralNode),e(a.ServiceIdentifiers.ICustomNodeGroup).to(s.ConsoleOutputCustomNodeGroup).whenTargetNamed(c.CustomNodeGroup.ConsoleOutputCustomNodeGroup),e(a.ServiceIdentifiers.ICustomNodeGroup).to(u.DebugProtectionCustomNodeGroup).whenTargetNamed(c.CustomNodeGroup.DebugProtectionCustomNodeGroup),e(a.ServiceIdentifiers.ICustomNodeGroup).to(l.DomainLockCustomNodeGroup).whenTargetNamed(c.CustomNodeGroup.DomainLockCustomNodeGroup),e(a.ServiceIdentifiers.ICustomNodeGroup).to(f.SelfDefendingCustomNodeGroup).whenTargetNamed(c.CustomNodeGroup.SelfDefendingCustomNodeGroup),e(a.ServiceIdentifiers.ICustomNodeGroup).to(d.StringArrayCustomNodeGroup).whenTargetNamed(c.CustomNodeGroup.StringArrayCustomNodeGroup),e(a.ServiceIdentifiers.Factory__ICustomNode).toFactory(function(e){var t=new Map,r=void 0;return function(n){if(r||(r=e.container.get(a.ServiceIdentifiers.IOptions)),t.has(n))return new(t.get(n));var o=e.container.getNamed(a.ServiceIdentifiers.Newable__ICustomNode,n);return t.set(n,o),new o(r)}}),e(a.ServiceIdentifiers.Factory__ICustomNodeGroup).toFactory(n.InversifyContainerFacade.getFactory(a.ServiceIdentifiers.ICustomNodeGroup))})},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(17),o=r(0),a=r(2),i=r(31),c=r(84),s=r(85),u=r(86),l=r(87);t.controlFlowTransformersModule=new o.ContainerModule(function(e){e(a.ServiceIdentifiers.IControlFlowReplacer).to(c.BinaryExpressionControlFlowReplacer).whenTargetNamed(i.ControlFlowReplacer.BinaryExpressionControlFlowReplacer),e(a.ServiceIdentifiers.IControlFlowReplacer).to(s.CallExpressionControlFlowReplacer).whenTargetNamed(i.ControlFlowReplacer.CallExpressionControlFlowReplacer),e(a.ServiceIdentifiers.IControlFlowReplacer).to(u.LogicalExpressionControlFlowReplacer).whenTargetNamed(i.ControlFlowReplacer.LogicalExpressionControlFlowReplacer),e(a.ServiceIdentifiers.IControlFlowReplacer).to(l.StringLiteralControlFlowReplacer).whenTargetNamed(i.ControlFlowReplacer.StringLiteralControlFlowReplacer),e(a.ServiceIdentifiers.Factory__IControlFlowReplacer).toFactory(n.InversifyContainerFacade.getCacheFactory(a.ServiceIdentifiers.IControlFlowReplacer))})},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(17),o=r(0),a=r(2),i=r(33),c=r(83),s=r(82),u=r(91),l=r(92),f=r(93),d=r(94),p=r(95),y=r(96),b=r(88),m=r(89),g=r(97),v=r(90),h=r(98);t.nodeTransformersModule=new o.ContainerModule(function(e){e(a.ServiceIdentifiers.INodeTransformer).to(s.BlockStatementControlFlowTransformer).whenTargetNamed(i.NodeTransformer.BlockStatementControlFlowTransformer),e(a.ServiceIdentifiers.INodeTransformer).to(u.DeadCodeInjectionTransformer).whenTargetNamed(i.NodeTransformer.DeadCodeInjectionTransformer),e(a.ServiceIdentifiers.INodeTransformer).to(c.FunctionControlFlowTransformer).whenTargetNamed(i.NodeTransformer.FunctionControlFlowTransformer),e(a.ServiceIdentifiers.INodeTransformer).to(b.MemberExpressionTransformer).whenTargetNamed(i.NodeTransformer.MemberExpressionTransformer),e(a.ServiceIdentifiers.INodeTransformer).to(m.MethodDefinitionTransformer).whenTargetNamed(i.NodeTransformer.MethodDefinitionTransformer),e(a.ServiceIdentifiers.INodeTransformer).to(v.TemplateLiteralTransformer).whenTargetNamed(i.NodeTransformer.TemplateLiteralTransformer),e(a.ServiceIdentifiers.INodeTransformer).to(l.CatchClauseTransformer).whenTargetNamed(i.NodeTransformer.CatchClauseTransformer),e(a.ServiceIdentifiers.INodeTransformer).to(f.FunctionDeclarationTransformer).whenTargetNamed(i.NodeTransformer.FunctionDeclarationTransformer),e(a.ServiceIdentifiers.INodeTransformer).to(d.FunctionTransformer).whenTargetNamed(i.NodeTransformer.FunctionTransformer),e(a.ServiceIdentifiers.INodeTransformer).to(p.LabeledStatementTransformer).whenTargetNamed(i.NodeTransformer.LabeledStatementTransformer),e(a.ServiceIdentifiers.INodeTransformer).to(y.LiteralTransformer).whenTargetNamed(i.NodeTransformer.LiteralTransformer),e(a.ServiceIdentifiers.INodeTransformer).to(g.ObjectExpressionTransformer).whenTargetNamed(i.NodeTransformer.ObjectExpressionTransformer),e(a.ServiceIdentifiers.INodeTransformer).to(h.VariableDeclarationTransformer).whenTargetNamed(i.NodeTransformer.VariableDeclarationTransformer),e(a.ServiceIdentifiers.Factory__INodeTransformer).toFactory(n.InversifyContainerFacade.getCacheFactory(a.ServiceIdentifiers.INodeTransformer))})},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(17),o=r(0),a=r(2),i=r(18),c=r(32),s=r(99),u=r(100),l=r(101),f=r(102);t.obfuscatingTransformersModule=new o.ContainerModule(function(e){e(a.ServiceIdentifiers.IObfuscatingReplacer).to(u.BooleanLiteralObfuscatingReplacer).whenTargetNamed(c.LiteralObfuscatingReplacer.BooleanLiteralObfuscatingReplacer),e(a.ServiceIdentifiers.IObfuscatingReplacer).to(l.NumberLiteralObfuscatingReplacer).whenTargetNamed(c.LiteralObfuscatingReplacer.NumberLiteralObfuscatingReplacer),e(a.ServiceIdentifiers.IObfuscatingReplacer).to(f.StringLiteralObfuscatingReplacer).whenTargetNamed(c.LiteralObfuscatingReplacer.StringLiteralObfuscatingReplacer),e(a.ServiceIdentifiers.IIdentifierObfuscatingReplacer).to(s.BaseIdentifierObfuscatingReplacer).whenTargetNamed(i.IdentifierObfuscatingReplacer.BaseIdentifierObfuscatingReplacer),e(a.ServiceIdentifiers.Factory__IObfuscatingReplacer).toFactory(n.InversifyContainerFacade.getCacheFactory(a.ServiceIdentifiers.IObfuscatingReplacer)),e(a.ServiceIdentifiers.Factory__IIdentifierObfuscatingReplacer).toFactory(n.InversifyContainerFacade.getCacheFactory(a.ServiceIdentifiers.IIdentifierObfuscatingReplacer))})},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(17),o=r(0),a=r(2),i=r(34),c=r(117),s=r(118),u=r(119),l=r(116);t.stackTraceAnalyzerModule=new o.ContainerModule(function(e){e(a.ServiceIdentifiers.IStackTraceAnalyzer).to(l.StackTraceAnalyzer).inSingletonScope(),e(a.ServiceIdentifiers.ICalleeDataExtractor).to(c.FunctionDeclarationCalleeDataExtractor).whenTargetNamed(i.CalleeDataExtractor.FunctionDeclarationCalleeDataExtractor),e(a.ServiceIdentifiers.ICalleeDataExtractor).to(s.FunctionExpressionCalleeDataExtractor).whenTargetNamed(i.CalleeDataExtractor.FunctionExpressionCalleeDataExtractor),e(a.ServiceIdentifiers.ICalleeDataExtractor).to(u.ObjectExpressionCalleeDataExtractor).whenTargetNamed(i.CalleeDataExtractor.ObjectExpressionCalleeDataExtractor),e(a.ServiceIdentifiers.Factory__ICalleeDataExtractor).toFactory(n.InversifyContainerFacade.getCacheFactory(a.ServiceIdentifiers.ICalleeDataExtractor))})},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(0),o=r(2),a=r(121),i=r(122),c=r(123);t.storagesModule=new n.ContainerModule(function(e){e(o.ServiceIdentifiers.TCustomNodeGroupStorage).to(i.CustomNodeGroupStorage).inSingletonScope(),e(o.ServiceIdentifiers.TStringArrayStorage).to(c.StringArrayStorage).inSingletonScope(),e(o.ServiceIdentifiers.Newable__TControlFlowStorage).toConstructor(a.ControlFlowStorage),e(o.ServiceIdentifiers.Factory__TControlFlowStorage).toFactory(function(e){return function(){var t=e.container.get(o.ServiceIdentifiers.Newable__TControlFlowStorage);return new t}})})},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var i=function(){function e(e,t){for(var r=0;rthis.options.controlFlowFlatteningThreshold||m.blockStatementHasProhibitedStatements(e))return e;var r=e.body;if(r.length<=4)return e;var n=y.Utils.arrayRange(r.length),o=y.Utils.arrayShuffle(n),a=n.map(function(e){return o.indexOf(e)}),i=this.customNodeFactory(l.CustomNode.BlockStatementControlFlowFlatteningNode);return i.initialize(r,o,a),i.getNode()[0]}}],[{key:"blockStatementHasProhibitedStatements",value:function(e){return e.body.some(function(e){var t=d.Node.isBreakStatementNode(e)||d.Node.isContinueStatementNode(e),r=d.Node.isVariableDeclarationNode(e)&&("const"===e.kind||"let"===e.kind);return d.Node.isFunctionDeclarationNode(e)||t||r})}}]),t}(f.AbstractNodeTransformer);b=m=c.__decorate([s.injectable(),c.__param(0,s.inject(u.ServiceIdentifiers.Factory__ICustomNode)),c.__param(1,s.inject(u.ServiceIdentifiers.IOptions)),c.__metadata("design:paramtypes",[Function,Object])],b),t.BlockStatementControlFlowTransformer=b;var m},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var i=function(){function e(e,t){for(var r=0;rr.options.controlFlowFlatteningThreshold)return e;var o=_.controlFlowReplacersMap.get(e.type);return void 0===o?e:Object.assign({},r.controlFlowReplacerFactory(o).replace(e,n,t),{parentNode:n})}})}}],[{key:"getHostNode",value:function(e){var t=g.NodeUtils.getBlockScopesOfNode(e);return 1===t.length?e:(t.pop(),t.length>_.hostNodeSearchMinDepth&&t.splice(0,_.hostNodeSearchMinDepth),t.length>_.hostNodeSearchMaxDepth&&(t.length=_.hostNodeSearchMaxDepth),v.RandomGeneratorUtils.getRandomGenerator().pickone(t))}}]),t}(p.AbstractNodeTransformer);h.controlFlowReplacersMap=new Map([[d.NodeType.BinaryExpression,m.ControlFlowReplacer.BinaryExpressionControlFlowReplacer],[d.NodeType.CallExpression,m.ControlFlowReplacer.CallExpressionControlFlowReplacer],[d.NodeType.LogicalExpression,m.ControlFlowReplacer.LogicalExpressionControlFlowReplacer],[d.NodeType.Literal,m.ControlFlowReplacer.StringLiteralControlFlowReplacer]]),h.hostNodeSearchMinDepth=0,h.hostNodeSearchMaxDepth=2,h=_=c.__decorate([s.injectable(),c.__param(0,s.inject(u.ServiceIdentifiers.Factory__TControlFlowStorage)),c.__param(1,s.inject(u.ServiceIdentifiers.Factory__IControlFlowReplacer)),c.__param(2,s.inject(u.ServiceIdentifiers.Factory__ICustomNode)),c.__param(3,s.inject(u.ServiceIdentifiers.IOptions)),c.__metadata("design:paramtypes",[Function,Function,Function,Object])],h),t.FunctionControlFlowTransformer=h;var _},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var i=function(){function e(e,t){for(var r=0;r1){var o=d.Nodes.getBinaryExpressionNode("+",n.shift(),n.shift());return n.forEach(function(e){o=d.Nodes.getBinaryExpressionNode("+",o,e)}),o}return n[0]}}],[{key:"isLiteralNodeWithStringValue",value:function(e){return e&&f.Node.isLiteralNode(e)&&"string"==typeof e.value}}]),t}(l.AbstractNodeTransformer);p=y=c.__decorate([s.injectable(),c.__param(0,s.inject(u.ServiceIdentifiers.IOptions)),c.__metadata("design:paramtypes",[Object])],p),t.TemplateLiteralTransformer=p;var y},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var i=function(){function e(e,t){for(var r=0;rt.options.deadCodeInjectionThreshold)return e;var n=b.RandomGeneratorUtils.getRandomInteger(0,t.collectedBlockStatements.length-1),o=t.collectedBlockStatements.splice(n,1)[0];return o===e?e:g.replaceBlockStatementNode(e,o)}})}}],[{key:"collectBlockStatementNodes",value:function(e,t){var r=y.NodeUtils.clone(e),n=0,o=!0;l.replace(r,{enter:function(e,t){return d.Node.isBlockStatementNode(e)&&n++,n>g.maxNestedBlockStatementsCount||d.Node.isBreakStatementNode(e)||d.Node.isContinueStatementNode(e)?(o=!1,l.VisitorOption.Break):(d.Node.isIdentifierNode(e)&&!d.Node.isMemberExpressionNode(t)&&(e.name=b.RandomGeneratorUtils.getRandomVariableName(6)),e)}}),o&&t.push(r)}},{key:"replaceBlockStatementNode",value:function(e,t){var r=b.RandomGeneratorUtils.getMathRandom()>.5,n=b.RandomGeneratorUtils.getMathRandom()>.5,o=r?"===":"!==",a=b.RandomGeneratorUtils.getRandomString(3),i=n?a:b.RandomGeneratorUtils.getRandomString(3),c=void 0,s=void 0;r&&n||!r&&!n?(c=e,s=t):(c=t,s=e);var u=p.Nodes.getBlockStatementNode([p.Nodes.getIfStatementNode(p.Nodes.getBinaryExpressionNode(o,p.Nodes.getLiteralNode(a),p.Nodes.getLiteralNode(i)),c,s)]);return u=y.NodeUtils.parentize(u)}}]),t}(f.AbstractNodeTransformer);m.maxNestedBlockStatementsCount=4,m.minCollectedBlockStatementsCount=5,m=g=c.__decorate([s.injectable(),c.__param(0,s.inject(u.ServiceIdentifiers.IOptions)),c.__metadata("design:paramtypes",[Object])],m),t.DeadCodeInjectionTransformer=m;var g},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var i=function(){function e(e,t){for(var r=0;r=g.minimumLengthForStringArray&&y.RandomGeneratorUtils.getMathRandom()<=this.options.stringArrayThreshold}},{key:"getArrayHexadecimalIndex",value:function(e){if(this.stringLiteralHexadecimalIndexCache.has(e))return this.stringLiteralHexadecimalIndexCache.get(e);var t=this.stringArrayStorage.getLength(),r=""+b.Utils.hexadecimalPrefix+b.Utils.decToHex(t);return this.stringArrayStorage.set(t,e),this.stringLiteralHexadecimalIndexCache.set(e,r),r}},{key:"getEncodedValue",value:function(e){var t=void 0,r=void 0;switch(this.options.stringArrayEncoding){case l.StringArrayEncoding.rc4:r=y.RandomGeneratorUtils.getRandomGenerator().pickone(this.rc4Keys),t=d.CryptUtils.btoa(d.CryptUtils.rc4(e,r));break;case l.StringArrayEncoding.base64:t=d.CryptUtils.btoa(e);break;default:t=e}return t=b.Utils.stringToUnicodeEscapeSequence(t,!this.options.unicodeEscapeSequence),{encodedValue:t,key:r}}},{key:"replaceWithStringArrayCallNode",value:function(e){var t=this.getEncodedValue(e),r=t.encodedValue,n=t.key,o=b.Utils.stringRotate(this.stringArrayStorage.getStorageId(),1),a="_"+b.Utils.hexadecimalPrefix+o,i=[g.getHexadecimalLiteralNode(this.getArrayHexadecimalIndex(r))];return n&&i.push(g.getRc4KeyLiteralNode(b.Utils.stringToUnicodeEscapeSequence(n,!this.options.unicodeEscapeSequence))),p.Nodes.getCallExpressionNode(p.Nodes.getIdentifierNode(a),i)}}],[{key:"getHexadecimalLiteralNode",value:function(e){var t=p.Nodes.getLiteralNode(e);return t.obfuscatedNode=!0,t}},{key:"getRc4KeyLiteralNode",value:function(e){var t=p.Nodes.getLiteralNode(e);return t.obfuscatedNode=!0,t}}]),t}(f.AbstractObfuscatingReplacer);m.minimumLengthForStringArray=3,m=g=c.__decorate([s.injectable(),c.__param(0,s.inject(u.ServiceIdentifiers.TCustomNodeGroupStorage)),c.__param(1,s.inject(u.ServiceIdentifiers.TStringArrayStorage)),c.__param(2,s.inject(u.ServiceIdentifiers.IOptions)),c.__metadata("design:paramtypes",[Object,Object,Object])],m),t.StringLiteralObfuscatingReplacer=m;var g},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}Object.defineProperty(t,"__esModule",{value:!0});var o=r(1),a=r(0),i=r(141),c=r(26),s=r(104),u=r(105),l=f=function e(t){n(this,e),Object.assign(this,c.DEFAULT_PRESET,t);var r=i.validateSync(this,f.validatorOptions);if(r.length)throw new ReferenceError("Validation failed. errors:\n"+u.ValidationErrorsFormatter.format(r));Object.assign(this,s.OptionsNormalizer.normalizeOptions(this))};l.validatorOptions={validationError:{target:!1}},o.__decorate([i.IsBoolean(),o.__metadata("design:type",Boolean)],l.prototype,"compact",void 0),o.__decorate([i.IsBoolean(),o.__metadata("design:type",Boolean)],l.prototype,"controlFlowFlattening",void 0),o.__decorate([i.IsNumber(),i.Min(0),i.Max(1),o.__metadata("design:type",Number)],l.prototype,"controlFlowFlatteningThreshold",void 0),o.__decorate([i.IsBoolean(),o.__metadata("design:type",Boolean)],l.prototype,"deadCodeInjection",void 0),o.__decorate([i.IsNumber(),o.__metadata("design:type",Number)],l.prototype,"deadCodeInjectionThreshold",void 0),o.__decorate([i.IsBoolean(),o.__metadata("design:type",Boolean)],l.prototype,"debugProtection",void 0),o.__decorate([i.IsBoolean(),o.__metadata("design:type",Boolean)],l.prototype,"debugProtectionInterval",void 0),o.__decorate([i.IsBoolean(),o.__metadata("design:type",Boolean)],l.prototype,"disableConsoleOutput",void 0),o.__decorate([i.IsArray(),i.ArrayUnique(),i.IsString({each:!0}),o.__metadata("design:type",Array)],l.prototype,"domainLock",void 0),o.__decorate([i.IsBoolean(),o.__metadata("design:type",Boolean)],l.prototype,"mangle",void 0),o.__decorate([i.IsArray(),i.ArrayUnique(),i.IsString({each:!0}),o.__metadata("design:type",Array)],l.prototype,"reservedNames",void 0),o.__decorate([i.IsBoolean(),o.__metadata("design:type",Boolean)],l.prototype,"rotateStringArray",void 0),o.__decorate([i.IsNumber(),o.__metadata("design:type",Number)],l.prototype,"seed",void 0),o.__decorate([i.IsBoolean(),o.__metadata("design:type",Boolean)],l.prototype,"selfDefending",void 0),o.__decorate([i.IsBoolean(),o.__metadata("design:type",Boolean)],l.prototype,"sourceMap",void 0),o.__decorate([i.IsString(),i.ValidateIf(function(e){return Boolean(e.sourceMapBaseUrl)}),i.IsUrl({require_protocol:!0,require_valid_protocol:!0}),o.__metadata("design:type",String)],l.prototype,"sourceMapBaseUrl",void 0),o.__decorate([i.IsString(),o.__metadata("design:type",String)],l.prototype,"sourceMapFileName",void 0),o.__decorate([i.IsIn(["inline","separate"]),o.__metadata("design:type",String)],l.prototype,"sourceMapMode",void 0),o.__decorate([i.IsBoolean(),o.__metadata("design:type",Boolean)],l.prototype,"stringArray",void 0),o.__decorate([i.IsIn([!0,!1,"base64","rc4"]),o.__metadata("design:type",Object)],l.prototype,"stringArrayEncoding",void 0),o.__decorate([i.IsNumber(),i.Min(0),i.Max(1),o.__metadata("design:type",Number)],l.prototype,"stringArrayThreshold",void 0),o.__decorate([i.IsBoolean(),o.__metadata("design:type",Boolean)],l.prototype,"unicodeEscapeSequence",void 0),l=f=o.__decorate([a.injectable(),o.__metadata("design:paramtypes",[Object])],l),t.Options=l;var f},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var o=function(){function e(e,t){for(var r=0;rr)return"break";var a=e[o];s.traverse(a,{enter:function(r){if(l.Node.isCallExpressionNode(r))return a.parentNode!==f.NodeUtils.getBlockScopesOfNode(r)[0]?s.VisitorOption.Skip:void t.analyzeCallExpressionNode(n,e,r)}})}(a))break}return n}},{key:"analyzeCallExpressionNode",value:function(e,t,r){var n=this;p.calleeDataExtractorsList.forEach(function(o){var a=n.calleeDataExtractorFactory(o).extract(t,r.callee);a&&e.push(Object.assign({},a,{stackTrace:n.analyzeRecursive(a.callee.body)}))})}}],[{key:"getLimitIndex",value:function(e){var t=e-1,r=p.limitThresholdActivationLength-1,n=t;return t>r&&(n=Math.round(r+t*p.limitThreshold))>t&&(n=t),n}}]),e}();d.calleeDataExtractorsList=[u.CalleeDataExtractor.FunctionDeclarationCalleeDataExtractor,u.CalleeDataExtractor.FunctionExpressionCalleeDataExtractor,u.CalleeDataExtractor.ObjectExpressionCalleeDataExtractor],d.limitThresholdActivationLength=25,d.limitThreshold=.002,d=p=a.__decorate([i.injectable(),a.__param(0,i.inject(c.ServiceIdentifiers.Factory__ICalleeDataExtractor)),a.__metadata("design:paramtypes",[Function])],d),t.StackTraceAnalyzer=d;var p},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var i=function(){function e(e,t){for(var r=0;r=0?t:null}},{key:"getLength",value:function(){return this.storageLength}},{key:"getStorage",value:function(){return this.storage}},{key:"getStorageId",value:function(){return this.storageId}},{key:"initialize",value:function(){this.storage=[],this.storageId=u.RandomGeneratorUtils.getRandomString(6)}},{key:"mergeWith",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]&&arguments[1];this.storage=[].concat(n(this.storage),n(e.getStorage())),t&&(this.storageId=e.getStorageId())}},{key:"set",value:function(e,t){e===this.storageLength?this.storage.push(t):this.storage.splice(e,0,t),this.storageLength++}}]),e}();i.__decorate([s.initializable(),i.__metadata("design:type",Array)],l.prototype,"storage",void 0),i.__decorate([s.initializable(),i.__metadata("design:type",String)],l.prototype,"storageId",void 0),l=i.__decorate([c.injectable()],l),t.ArrayStorage=l},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}Object.defineProperty(t,"__esModule",{value:!0});var i=r(36),c=function(e){function t(){n(this,t);var e=o(this,(t.__proto__||Object.getPrototypeOf(t)).call(this));return e.initialize(),e}return a(t,e),t}(i.MapStorage);t.ControlFlowStorage=c},function(e,t,r){"use strict";function n(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function o(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!=typeof t&&"function"!=typeof t?e:t}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function, not "+typeof t);e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,enumerable:!1,writable:!0,configurable:!0}}),t&&(Object.setPrototypeOf?Object.setPrototypeOf(e,t):e.__proto__=t)}var i=function(){function e(e,t){for(var r=0;r> (-2 * bc & 6)) : 0\n ) {\n buffer = chars.indexOf(buffer);\n }\n return output;\n });\n })();\n "}Object.defineProperty(t,"__esModule",{value:!0}),t.AtobTemplate=n},function(e,t,r){"use strict";function n(){return"\n var rc4 = function (str, key) {\n var s = [], j = 0, x, res = '', newStr = '';\n \n str = atob(str);\n \n for (var k = 0, length = str.length; k < length; k++) {\n newStr += '%' + ('00' + str.charCodeAt(k).toString(16)).slice(-2);\n }\n \n str = decodeURIComponent(newStr);\n \t \n\t for (var i = 0; i < 256; i++) {\n s[i] = i;\n }\n \n for (i = 0; i < 256; i++) {\n j = (j + s[i] + key.charCodeAt(i % key.length)) % 256;\n x = s[i];\n s[i] = s[j];\n s[j] = x;\n }\n \n i = 0;\n j = 0;\n \n for (var y = 0; y < str.length; y++) {\n i = (i + 1) % 256;\n j = (j + s[i]) % 256;\n x = s[i];\n s[i] = s[j];\n s[j] = x;\n res += String.fromCharCode(str.charCodeAt(y) ^ s[(s[i] + s[j]) % 256]);\n }\n \n return res;\n }\n "}Object.defineProperty(t,"__esModule",{value:!0}),t.Rc4Template=n},function(e,t,r){"use strict";function n(){return"\n var {singleNodeCallControllerFunctionName} = (function(){\n var firstCall = true;\n \n return function (context, fn){\t\n var rfn = firstCall ? function(){\n if(fn){\n var res = fn.apply(context, arguments);\n fn = null;\n return res;\n }\n } : function(){}\n \n firstCall = false;\n \n return rfn;\n }\n })();\n "}Object.defineProperty(t,"__esModule",{value:!0}),t.SingleNodeCallControllerTemplate=n},function(e,t,r){"use strict";function n(){return"\n var {consoleLogDisableFunctionName} = {singleNodeCallControllerFunctionName}(this, function () {\n var getGlobal = Function('return (function() ' + '{}.constructor(\"return this\")( )' + ');');\n \n var func = function () {};\n var that = getGlobal();\n \n if (!that.console) {\n that.console = (function (func){ \n var c = {}; \n \n c.log = func;\n c.warn = func; \n c.debug = func;\n c.info = func;\n c.error = func;\n c.exception = func;\n c.trace = func;\n \n return c; \n })(func);\n } else {\n that.console.log = func;\n that.console.warn = func; \n that.console.debug = func;\n that.console.info = func;\n that.console.error = func;\n that.console.exception = func;\n that.console.trace = func;\n }\n });\n \n {consoleLogDisableFunctionName}();\n "}Object.defineProperty(t,"__esModule",{value:!0}),t.ConsoleOutputDisableExpressionTemplate=n},function(e,t,r){"use strict";function n(){return"{debugProtectionFunctionName}();"}Object.defineProperty(t,"__esModule",{value:!0}),t.DebugProtectionFunctionCallTemplate=n},function(e,t,r){"use strict";function n(){return"\n setInterval(function () {\n {debugProtectionFunctionName}();\n }, 4000);\n "}Object.defineProperty(t,"__esModule",{value:!0}),t.DebugProtectionFunctionIntervalTemplate=n},function(e,t,r){"use strict";function n(){return"\n var {debugProtectionFunctionName} = function () {\n function debuggerProtection (counter) {\n if (('' + counter / counter)['length'] !== 1 || counter % 20 === 0) {\n (function () {}.constructor('debugger')());\n } else {\n (function () {}.constructor('debugger')());\n }\n \n debuggerProtection(++counter);\n }\n \n try {\n debuggerProtection(0);\n } catch (y) {}\n };\n "}Object.defineProperty(t,"__esModule",{value:!0}),t.DebugProtectionFunctionTemplate=n},function(e,t,r){"use strict";function n(){return'\n var {domainLockFunctionName} = {singleNodeCallControllerFunctionName}(this, function () {\n var getGlobal = Function(\'return (function () \' + \'{}.constructor("return this")()\' + \');\');\n\n var func = function () { \n return {\n key: \'item\',\n value: \'attribute\',\n getAttribute: function () {\n getGlobal()[\'eval\'](\'while(true){}\')();\n }()\n };\n };\n \n var regExp = new RegExp("[{diff}]", "g");\n var domains = "{domains}".replace(regExp, "").split(";");\n var eval = []["forEach"]["constructor"];\n var windowObject = eval("return this")();\n var document;\n var domain;\n \n for (var d in windowObject) {\n if (d.length == 8 && d.charCodeAt(7) == 116 && d.charCodeAt(5) == 101 && d.charCodeAt(3) == 117 && d.charCodeAt(0) == 100) {\n document = d;\n \n break;\n }\n }\n\n for (var d1 in windowObject[document]) {\n if (d1.length == 6 && d1.charCodeAt(5) == 110 && d1.charCodeAt(0) == 100) {\n domain = d1;\n \n break;\n }\n }\n \n if ((!document && !domain) || (!windowObject[document] && !windowObject[document][domain])) {\n return;\n }\n \n var currentDomain = windowObject[document][domain];\n\n var ok = false;\n \n for (var i = 0; i < domains.length; i++) {\n var domain = domains[i];\n var position = currentDomain.length - domain.length;\n var lastIndex = currentDomain.indexOf(domain, position);\n var endsWith = lastIndex !== -1 && lastIndex === position;\n \n if (endsWith) {\n if (currentDomain.length == domain.length || domain.indexOf(".") === 0) {\n ok = true;\n }\n \n break;\n }\n }\n \n if (!ok) {\n data;\n } else {\n return;\n }\n \n func();\n });\n\n {domainLockFunctionName}();\n '}Object.defineProperty(t,"__esModule",{value:!0}),t.DomainLockNodeTemplate=n},function(e,t,r){"use strict";function n(){return"\n var {selfDefendingFunctionName} = {singleNodeCallControllerFunctionName}(this, function () {\n var func1 = function(){return 'dev';},\n func2 = function () {\n return 'window';\n };\n \n var test1 = function () {\n var regExp = new RegExp('"+o.Utils.stringToUnicodeEscapeSequence("\\w+ *\\(\\) *{\\w+ *['|\"].+['|\"];? *}")+"');\n \n return !regExp.test(func1.toString());\n };\n \n var test2 = function () {\n var regExp = new RegExp('"+o.Utils.stringToUnicodeEscapeSequence("(\\\\[x|u](\\w){2,4})+")+"');\n \n return regExp.test(func2.toString());\n };\n \n var recursiveFunc1 = function (string) {\n var i = ~-1 >> 1 + 255 % 0;\n \n if (string.indexOf('i' === i)) {\n recursiveFunc2(string)\n }\n };\n \n var recursiveFunc2 = function (string) {\n var i = ~-4 >> 1 + 255 % 0;\n \n if (string.indexOf((true+\"\")[3]) !== i) {\n recursiveFunc1(string)\n }\n };\n \n if (!test1()) {\n if (!test2()) {\n recursiveFunc1('indеxOf');\n } else {\n recursiveFunc1('indexOf');\n }\n } else {\n recursiveFunc1('indеxOf');\n }\n })\n \n {selfDefendingFunctionName}();\n "}Object.defineProperty(t,"__esModule",{value:!0});var o=r(9);t.SelfDefendingTemplate=n},function(e,t,r){"use strict";function n(){return"\n var StatesClass = function (rc4Bytes) {\n this.rc4Bytes = rc4Bytes;\n this.states = [1, 0, 0];\n this.newState = function(){return 'newState';};\n this.firstState = '"+o.Utils.stringToUnicodeEscapeSequence("\\w+ *\\(\\) *{\\w+ *")+"';\n this.secondState = '"+o.Utils.stringToUnicodeEscapeSequence("['|\"].+['|\"];? *}")+"';\n };\n \n StatesClass.prototype.checkState = function () {\n var regExp = new RegExp(this.firstState + this.secondState);\n\n return this.runState(regExp.test(this.newState.toString()) ? --this.states[1] : --this.states[0]);\n };\n \n StatesClass.prototype.runState = function (stateResult) {\n if (!Boolean(~stateResult)) {\n return stateResult;\n }\n \n return this.getState(this.rc4Bytes);\n };\n\n StatesClass.prototype.getState = function (rc4Bytes) {\n for (var i = 0, len = this.states.length; i < len; i++) {\n this.states.push(Math.round(Math.random()));\n len = this.states.length;\n }\n \n return rc4Bytes(this.states[0]);\n };\n\n new StatesClass({stringArrayCallsWrapperName}).checkState();\n "}Object.defineProperty(t,"__esModule",{value:!0});var o=r(9);t.SelfDefendingTemplate=n},function(e,t,r){"use strict";function n(){return" \n if ({stringArrayCallsWrapperName}.initialized === undefined) {\n {atobPolyfill}\n \n {stringArrayCallsWrapperName}.base64DecodeUnicode = function (str) {\n var string = atob(str);\n var newStringChars = [];\n \n for (var i = 0, length = string.length; i < length; i++) {\n newStringChars += '%' + ('00' + string.charCodeAt(i).toString(16)).slice(-2);\n }\n \n return decodeURIComponent(newStringChars);\n };\n \n {stringArrayCallsWrapperName}.data = {};\n \n {stringArrayCallsWrapperName}.initialized = true;\n }\n \n var cachedValue = {stringArrayCallsWrapperName}.data[index];\n \n if (cachedValue === undefined) {\n {selfDefendingCode}\n \n value = {stringArrayCallsWrapperName}.base64DecodeUnicode(value);\n {stringArrayCallsWrapperName}.data[index] = value;\n } else {\n value = cachedValue;\n } \n "}Object.defineProperty(t,"__esModule",{value:!0}),t.StringArrayBase64DecodeNodeTemplate=n},function(e,t,r){"use strict";function n(){return"\n var {stringArrayCallsWrapperName} = function (index, key) {\n index = index - 0;\n \n var value = {stringArrayName}[index];\n \n {decodeNodeTemplate}\n \n return value;\n };\n "}Object.defineProperty(t,"__esModule",{value:!0}),t.StringArrayCallsWrapperTemplate=n},function(e,t,r){"use strict";function n(){return"\n if ({stringArrayCallsWrapperName}.initialized === undefined) {\n {atobPolyfill}\n \n {rc4Polyfill}\n {stringArrayCallsWrapperName}.rc4 = rc4;\n \n {stringArrayCallsWrapperName}.data = {};\n \n {stringArrayCallsWrapperName}.initialized = true;\n }\n \n var cachedValue = {stringArrayCallsWrapperName}.data[index];\n\n if (cachedValue === undefined) {\n if ({stringArrayCallsWrapperName}.once === undefined) {\n {selfDefendingCode}\n \n {stringArrayCallsWrapperName}.once = true;\n }\n \n value = {stringArrayCallsWrapperName}.rc4(value, key);\n {stringArrayCallsWrapperName}.data[index] = value;\n } else {\n value = cachedValue;\n }\n "}Object.defineProperty(t,"__esModule",{value:!0}),t.StringArrayRc4DecodeNodeTemplate=n},function(e,t,r){"use strict";function n(){return"\n var {stringArrayName} = [{stringArray}];\n "}Object.defineProperty(t,"__esModule",{value:!0}),t.StringArrayTemplate=n},function(e,t,r){"use strict";function n(){return"\n var selfDefendingFunc = function () { \n var object = {\n data: {\n key: 'cookie',\n value: 'timeout'\n },\n setCookie: function (options, name, value, document) {\n document = document || {};\n \n var updatedCookie = name + \"=\" + value;\n\n var i = 0;\n \n for (var i = 0, len = options.length; i < len; i++) { \n var propName = options[i];\n \n updatedCookie += \"; \" + propName;\n \n var propValue = options[propName];\n \n options.push(propValue);\n len = options.length;\n \n if (propValue !== true) {\n updatedCookie += \"=\" + propValue;\n }\n }\n\n document['cookie'] = updatedCookie;\n },\n removeCookie: function(){return 'dev';},\n getCookie: function (document, name) { \n document = document || function (value) { return value };\n var matches = document(new RegExp(\n \"(?:^|; )\" + name.replace(/([.$?*|{}()[]\\/+^])/g, '\\$1') + \"=([^;]*)\"\n ));\n \n var func = function (param1, param2) {\n param1(++param2);\n };\n \n func({whileFunctionName}, {timesName});\n \n return matches ? decodeURIComponent(matches[1]) : undefined;\n }\n };\n \n var test1 = function () {\n var regExp = new RegExp('"+o.Utils.stringToUnicodeEscapeSequence("\\w+ *\\(\\) *{\\w+ *['|\"].+['|\"];? *}")+"');\n \n return regExp.test(object.removeCookie.toString());\n };\n \n object['updateCookie'] = test1;\n \n var cookie = '';\n var result = object['updateCookie']();\n \n if (!result) {\n object['setCookie'](['*'], 'counter', 1);\n } else if (result) {\n cookie = object['getCookie'](null, 'counter'); \n } else {\n object['removeCookie']();\n }\n };\n \n selfDefendingFunc();\n "}Object.defineProperty(t,"__esModule",{value:!0});var o=r(9);t.SelfDefendingTemplate=n},function(e,t,r){"use strict";function n(){return"\n (function (array, {timesName}) {\n var {whileFunctionName} = function (times) {\n while (--times) {\n array['push'](array['shift']());\n }\n };\n \n {code}\n })({stringArrayName}, 0x{stringArrayRotateValue});\n "}Object.defineProperty(t,"__esModule",{value:!0}),t.StringArrayRotateFunctionTemplate=n},function(e,t){e.exports=require("chance")},function(e,t){e.exports=require("class-validator")},function(e,t){e.exports=require("commander")},function(e,t){e.exports=require("esmangle")},function(e,t){e.exports=require("events")},function(e,t){e.exports=require("fs")},function(e,t){e.exports=require("mkdirp")},function(e,t){e.exports=require("reflect-metadata")}]); //# sourceMappingURL=index.js.map \ No newline at end of file diff --git a/package.json b/package.json index ac63e171..34fd1d84 100644 --- a/package.json +++ b/package.json @@ -37,29 +37,29 @@ "devDependencies": { "@types/chai": "4.0.0", "@types/chance": "0.7.33", - "@types/commander": "2.3.31", + "@types/commander": "2.9.1", "@types/escodegen": "0.0.6", "@types/esprima": "2.1.33", "@types/estraverse": "0.0.6", "@types/estree": "0.0.35", "@types/mkdirp": "0.3.29", "@types/mocha": "2.2.41", - "@types/node": "7.0.27", - "@types/sinon": "2.3.0", + "@types/node": "7.0.29", + "@types/sinon": "2.3.1", "@types/string-template": "1.0.2", "awesome-typescript-loader": "3.1.3", "babel-cli": "6.24.1", "babel-loader": "7.0.0", "babel-plugin-array-includes": "2.0.3", "babel-preset-es2015": "6.24.1", - "chai": "4.0.1", + "chai": "4.0.2", "coveralls": "2.13.1", "istanbul": "1.1.0-alpha.1", "mocha": "3.4.2", "pre-commit": "1.2.2", - "sinon": "2.3.2", - "ts-node": "3.0.4", - "tslint": "5.4.2", + "sinon": "2.3.3", + "ts-node": "3.0.6", + "tslint": "5.4.3", "tslint-loader": "3.5.3", "typescript": "2.3.4", "webpack": "2.6.1", diff --git a/src/cli/JavaScriptObfuscatorCLI.ts b/src/cli/JavaScriptObfuscatorCLI.ts index 11b7a808..1a3cffb9 100644 --- a/src/cli/JavaScriptObfuscatorCLI.ts +++ b/src/cli/JavaScriptObfuscatorCLI.ts @@ -11,7 +11,7 @@ import { BooleanSanitizer } from './sanitizers/BooleanSanitizer'; import { SourceMapModeSanitizer } from './sanitizers/SourceMapModeSanitizer'; import { StringArrayEncodingSanitizer } from './sanitizers/StringArrayEncodingSanitizer'; -import { CLIUtils } from './CLIUtils'; +import { CLIUtils } from './utils/CLIUtils'; import { JavaScriptObfuscator } from '../JavaScriptObfuscator'; export class JavaScriptObfuscatorCLI { @@ -21,14 +21,14 @@ export class JavaScriptObfuscatorCLI { private readonly arguments: string[]; /** - * @type {commander.ICommand} + * @type {string[]} */ - private commands: commander.ICommand; + private readonly rawArguments: string[]; /** - * @type {string} + * @type {commander.CommanderStatic} */ - private data: string = ''; + private commands: commander.CommanderStatic; /** * @type {string} @@ -36,9 +36,9 @@ export class JavaScriptObfuscatorCLI { private inputPath: string; /** - * @type {string[]} + * @type {string} */ - private rawArguments: string[]; + private sourceCode: string = ''; /** * @param argv @@ -46,17 +46,13 @@ export class JavaScriptObfuscatorCLI { constructor (argv: string[]) { this.rawArguments = argv; this.arguments = this.rawArguments.slice(2); - } - /** - * @returns {string} - */ - private static getBuildVersion (): string { - return CLIUtils.getPackageConfig().version; + this.commands = (new commander.Command()); } public run (): void { this.configureCommands(); + this.configureHelp(); if (!this.arguments.length || this.arguments.includes('--help')) { this.commands.outputHelp(); @@ -97,8 +93,8 @@ export class JavaScriptObfuscatorCLI { } private configureCommands (): void { - this.commands = new commander.Command() - .version(JavaScriptObfuscatorCLI.getBuildVersion(), '-v, --version') + this.commands + .version(CLIUtils.getPackageConfig().version, '-v, --version') .usage(' [options]') .option( '-o, --output ', @@ -211,7 +207,9 @@ export class JavaScriptObfuscatorCLI { BooleanSanitizer ) .parse(this.rawArguments); + } + private configureHelp (): void { this.commands.on('--help', () => { console.log(' Examples:\n'); console.log(' %> javascript-obfuscator in.js --compact true --selfDefending false'); @@ -221,7 +219,7 @@ export class JavaScriptObfuscatorCLI { } private getData (): void { - this.data = CLIUtils.readFile(this.inputPath); + this.sourceCode = CLIUtils.readFile(this.inputPath); } private processData (): void { @@ -240,7 +238,7 @@ export class JavaScriptObfuscatorCLI { * @param options */ private processDataWithoutSourceMap (outputCodePath: string, options: TInputOptions): void { - const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(this.data, options).getObfuscatedCode(); + const obfuscatedCode: string = JavaScriptObfuscator.obfuscate(this.sourceCode, options).getObfuscatedCode(); CLIUtils.writeFile(outputCodePath, obfuscatedCode); } @@ -260,7 +258,7 @@ export class JavaScriptObfuscatorCLI { sourceMapFileName: path.basename(outputSourceMapPath) }; - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(this.data, options); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate(this.sourceCode, options); CLIUtils.writeFile(outputCodePath, obfuscationResult.getObfuscatedCode()); diff --git a/src/cli/CLIUtils.ts b/src/cli/utils/CLIUtils.ts similarity index 97% rename from src/cli/CLIUtils.ts rename to src/cli/utils/CLIUtils.ts index c3d95010..8979f65e 100644 --- a/src/cli/CLIUtils.ts +++ b/src/cli/utils/CLIUtils.ts @@ -2,7 +2,7 @@ import * as fs from 'fs'; import * as mkdirp from 'mkdirp'; import * as path from 'path'; -import { IPackageConfig } from '../interfaces/IPackageConfig'; +import { IPackageConfig } from '../../interfaces/IPackageConfig'; export class CLIUtils { /** diff --git a/test/functional-tests/custom-nodes/console-output-nodes/ConsoleOutputDisableExpressionNode.spec.ts b/test/functional-tests/custom-nodes/console-output-nodes/ConsoleOutputDisableExpressionNode.spec.ts index 4224af9c..6ec6eee3 100644 --- a/test/functional-tests/custom-nodes/console-output-nodes/ConsoleOutputDisableExpressionNode.spec.ts +++ b/test/functional-tests/custom-nodes/console-output-nodes/ConsoleOutputDisableExpressionNode.spec.ts @@ -13,32 +13,61 @@ describe('ConsoleOutputDisableExpressionNode', () => { const consoleErrorRegExp: RegExp = /_0x([a-f0-9]){4,6}\['console'\]\['error'\] *= *_0x([a-f0-9]){4,6};/u; const consoleWarnRegExp: RegExp = /_0x([a-f0-9]){4,6}\['console'\]\['warn'\] *= *_0x([a-f0-9]){4,6};/u; - it('should correctly append `ConsoleOutputDisableExpressionNode` custom node into the obfuscated code if `disableConsoleOutput` option is set', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/simple-input.js'), - { - ...NO_CUSTOM_NODES_PRESET, - disableConsoleOutput: true - } - ); + describe('`disableConsoleOutput` option is set', () => { + let obfuscatedCode: string; - assert.match(obfuscationResult.getObfuscatedCode(), consoleLogRegExp); - assert.match(obfuscationResult.getObfuscatedCode(), consoleErrorRegExp); - assert.match(obfuscationResult.getObfuscatedCode(), consoleWarnRegExp); + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/simple-input.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + disableConsoleOutput: true + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('match #1: should correctly append custom node into the obfuscated code', () => { + assert.match(obfuscatedCode, consoleLogRegExp); + }); + + it('match #2: should correctly append custom node into the obfuscated code', () => { + assert.match(obfuscatedCode, consoleErrorRegExp); + }); + + it('match #3: should correctly append custom node into the obfuscated code', () => { + assert.match(obfuscatedCode, consoleWarnRegExp); + }); }); - it('should\'t append `ConsoleOutputDisableExpressionNode` custom node into the obfuscated code if `disableConsoleOutput` option is not set', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/simple-input.js'), - { - ...NO_CUSTOM_NODES_PRESET, - disableConsoleOutput: false, - stringArrayThreshold: 1 - } - ); + describe('`disableConsoleOutput` option isn\'t set', () => { + let obfuscatedCode: string; - assert.notMatch(obfuscationResult.getObfuscatedCode(), consoleLogRegExp); - assert.notMatch(obfuscationResult.getObfuscatedCode(), consoleErrorRegExp); - assert.notMatch(obfuscationResult.getObfuscatedCode(), consoleWarnRegExp); + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/simple-input.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + disableConsoleOutput: false + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('match #1: shouldn\'t append custom node into the obfuscated code', () => { + assert.notMatch(obfuscatedCode, consoleLogRegExp); + }); + + it('match #2: shouldn\'t append custom node into the obfuscated code', () => { + assert.notMatch(obfuscatedCode, consoleErrorRegExp); + }); + + it('match #3: shouldn\'t append custom node into the obfuscated code', () => { + assert.notMatch(obfuscatedCode, consoleWarnRegExp); + }); }); }); diff --git a/test/functional-tests/custom-nodes/domain-lock-nodes/DomainLockNode.spec.ts b/test/functional-tests/custom-nodes/domain-lock-nodes/DomainLockNode.spec.ts index 194c92c3..5cfa1075 100644 --- a/test/functional-tests/custom-nodes/domain-lock-nodes/DomainLockNode.spec.ts +++ b/test/functional-tests/custom-nodes/domain-lock-nodes/DomainLockNode.spec.ts @@ -9,27 +9,47 @@ import { readFileAsString } from '../../../helpers/readFileAsString'; import { JavaScriptObfuscator } from '../../../../src/JavaScriptObfuscator'; describe('DomainLockNode', () => { - it('should correctly append `DomainLockNode` custom node into the obfuscated code if `domainLock` option is set', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/simple-input.js'), - { - ...NO_CUSTOM_NODES_PRESET, - domainLock: ['.example.com'] - } - ); + const regExp: RegExp = /var _0x([a-f0-9]){4,6} *= *new RegExp/; - assert.match(obfuscationResult.getObfuscatedCode(), /var _0x([a-f0-9]){4,6} *= *new RegExp/); + describe('`domainLock` option is set', () => { + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/simple-input.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + domainLock: ['.example.com'] + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('should correctly append custom node into the obfuscated code', () => { + assert.match(obfuscatedCode, regExp); + }); }); - it('should\'t append `DomainLockNode` custom node into the obfuscated code if `domainLock` option is not set', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/simple-input.js'), - { - ...NO_CUSTOM_NODES_PRESET, - domainLock: [] - } - ); + describe('`domainLock` option isn\'t set', () => { + let obfuscatedCode: string; - assert.notMatch(obfuscationResult.getObfuscatedCode(), /var _0x([a-f0-9]){4,6} *= *new RegExp/); + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/simple-input.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + domainLock: [] + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('shouldn\'t append custom node into the obfuscated code', () => { + assert.notMatch(obfuscatedCode, regExp); + }); }); }); diff --git a/test/functional-tests/custom-nodes/string-array-nodes/StringArrayCallsWrapper.spec.ts b/test/functional-tests/custom-nodes/string-array-nodes/StringArrayCallsWrapper.spec.ts index 7cf7c312..2500ce2d 100644 --- a/test/functional-tests/custom-nodes/string-array-nodes/StringArrayCallsWrapper.spec.ts +++ b/test/functional-tests/custom-nodes/string-array-nodes/StringArrayCallsWrapper.spec.ts @@ -9,19 +9,50 @@ import { readFileAsString } from '../../../helpers/readFileAsString'; import { JavaScriptObfuscator } from '../../../../src/JavaScriptObfuscator'; describe('StringArrayCallsWrapper', () => { - it('should correctly append `StringArrayCallsWrapper` custom node into the obfuscated code', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/simple-input.js'), - { - ...NO_CUSTOM_NODES_PRESET, - stringArray: true, - stringArrayThreshold: 1 - } - ); + const regExp: RegExp = /_0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6} *- *0x0\;/; - assert.match( - obfuscationResult.getObfuscatedCode(), - /_0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6} *- *0x0\;/ - ); + describe('`stringArray` option is set', () => { + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/simple-input.js'); + + let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + stringArray: true, + stringArrayThreshold: 1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('should correctly append custom node into the obfuscated code', () => { + assert.match(obfuscatedCode, regExp); + }); + }); + + describe('`stringArray` option isn\'t set', () => { + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/simple-input.js'); + + let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + stringArray: false + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('shouldn\'t append custom node into the obfuscated code', () => { + assert.notMatch(obfuscatedCode, regExp); + }); }); }); diff --git a/test/functional-tests/custom-nodes/string-array-nodes/StringArrayNode.spec.ts b/test/functional-tests/custom-nodes/string-array-nodes/StringArrayNode.spec.ts index bf061a23..8c142896 100644 --- a/test/functional-tests/custom-nodes/string-array-nodes/StringArrayNode.spec.ts +++ b/test/functional-tests/custom-nodes/string-array-nodes/StringArrayNode.spec.ts @@ -9,28 +9,50 @@ import { readFileAsString } from '../../../helpers/readFileAsString'; import { JavaScriptObfuscator } from '../../../../src/JavaScriptObfuscator'; describe('StringArrayNode', () => { - it('should correctly append `StringArrayNode` custom node into the obfuscated code if `stringArray` option is set', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/simple-input.js'), - { - ...NO_CUSTOM_NODES_PRESET, - stringArray: true, - stringArrayThreshold: 1 - } - ); + const regExp: RegExp = /^var _0x([a-f0-9]){4} *= *\[/; - assert.match(obfuscationResult.getObfuscatedCode(), /^var _0x([a-f0-9]){4} *= *\[/); + describe('`stringArray` option is set', () => { + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/simple-input.js'); + + let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + stringArray: true, + stringArrayThreshold: 1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('should correctly append custom node into the obfuscated code', () => { + assert.match(obfuscatedCode, regExp); + }); }); - it('should\'t append `StringArrayNode` custom node into the obfuscated code if `stringArray` option is not set', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/simple-input.js'), - { - ...NO_CUSTOM_NODES_PRESET, - stringArray: false - } - ); + describe('`stringArray` option isn\'t set', () => { + let obfuscatedCode: string; - assert.notMatch(obfuscationResult.getObfuscatedCode(), /^var _0x([a-f0-9]){4} *= *\[/); + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/simple-input.js'); + + let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + stringArray: false + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('shouldn\'t append custom node into the obfuscated code', () => { + assert.notMatch(obfuscatedCode, regExp); + }); }); }); diff --git a/test/functional-tests/custom-nodes/string-array-nodes/StringArrayRotateFunctionNode.spec.ts b/test/functional-tests/custom-nodes/string-array-nodes/StringArrayRotateFunctionNode.spec.ts index e9a90efc..9fe7ec6d 100644 --- a/test/functional-tests/custom-nodes/string-array-nodes/StringArrayRotateFunctionNode.spec.ts +++ b/test/functional-tests/custom-nodes/string-array-nodes/StringArrayRotateFunctionNode.spec.ts @@ -9,31 +9,53 @@ import { readFileAsString } from '../../../helpers/readFileAsString'; import { JavaScriptObfuscator } from '../../../../src/JavaScriptObfuscator'; describe('StringArrayRotateFunctionNode', () => { - it('should correctly append `StringArrayRotateFunctionNode` custom node into the obfuscated code if `rotateStringArray` option is set', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/simple-input.js'), - { - ...NO_CUSTOM_NODES_PRESET, - rotateStringArray: true, - stringArray: true, - stringArrayThreshold: 1 - } - ); + const regExp: RegExp = /while *\(-- *_0x([a-f0-9]){4,6}\) *\{/; - assert.match(obfuscationResult.getObfuscatedCode(), /while *\(-- *_0x([a-f0-9]){4,6}\) *\{/); + describe('`stringArray` option is set', () => { + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/simple-input.js'); + + let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + rotateStringArray: true, + stringArray: true, + stringArrayThreshold: 1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('should correctly append custom node into the obfuscated code', () => { + assert.match(obfuscatedCode, regExp); + }); }); - it('should\'t append `StringArrayRotateFunctionNode` custom node into the obfuscated code if `rotateStringArray` option is not set', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/simple-input.js'), - { - ...NO_CUSTOM_NODES_PRESET, - rotateStringArray: false, - stringArray: true, - stringArrayThreshold: 1 - } - ); + describe('`stringArray` option isn\'t set', () => { + let obfuscatedCode: string; - assert.notMatch(obfuscationResult.getObfuscatedCode(), /while *\(-- *_0x([a-f0-9]){4,6}\) *\{/); + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/simple-input.js'); + + let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + rotateStringArray: false, + stringArray: true, + stringArrayThreshold: 1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('shouldn\'t append custom node into the obfuscated code', () => { + assert.notMatch(obfuscatedCode, regExp); + }); }); }); diff --git a/test/functional-tests/javascript-obfuscator-cli/JavaScriptObfuscatorCLI.spec.ts b/test/functional-tests/javascript-obfuscator-cli/JavaScriptObfuscatorCLI.spec.ts index a0b66f66..260d525e 100644 --- a/test/functional-tests/javascript-obfuscator-cli/JavaScriptObfuscatorCLI.spec.ts +++ b/test/functional-tests/javascript-obfuscator-cli/JavaScriptObfuscatorCLI.spec.ts @@ -9,22 +9,24 @@ import { StdoutWriteMock } from '../../mocks/StdoutWriteMock'; import { JavaScriptObfuscator } from '../../../src/JavaScriptObfuscator'; describe('JavaScriptObfuscatorCLI', function (): void { - let fixturesDirName: string = 'test/fixtures', - fixtureFileName: string = 'sample.js', - fixtureFilePath: string = `${fixturesDirName}/${fixtureFileName}`, - outputDirName: string = 'test/tmp', - outputFileName: string = 'sample-obfuscated.js', - outputFilePath: string = `${outputDirName}/${outputFileName}`; + this.timeout(100000); - this.timeout(5000); + const fixturesDirName: string = 'test/fixtures'; + const fixtureFileName: string = 'sample.js'; + const fixtureFilePath: string = `${fixturesDirName}/${fixtureFileName}`; + const outputDirName: string = 'test/tmp'; + const outputFileName: string = 'sample-obfuscated.js'; + const outputFilePath: string = `${outputDirName}/${outputFileName}`; describe('run (): void', () => { before(() => { mkdirp.sync(outputDirName); }); - describe('--output option is set', () => { - it('should creates file with obfuscated JS code in --output directory', () => { + describe('`--output` option is set', () => { + let isFileExist: boolean; + + before(() => { JavaScriptObfuscator.runCLI([ 'node', 'javascript-obfuscator', @@ -37,153 +39,259 @@ describe('JavaScriptObfuscatorCLI', function (): void { '0' ]); - assert.equal(fs.existsSync(outputFilePath), true); + isFileExist = fs.existsSync(outputFilePath); }); - afterEach(() => { + it('should create file with obfuscated code in `--output` directory', () => { + assert.equal(isFileExist, true); + }); + + after(() => { fs.unlinkSync(outputFilePath); }); }); - describe('--output option is not set', () => { - it(`should creates file called \`${outputFileName}\` with obfuscated JS code in \`${fixturesDirName}\` directory`, () => { - let outputFixturesFilePath: string = `${fixturesDirName}/${outputFileName}`; + describe('`--output` option isn\'t set', () => { + describe('variant #1: default behaviour', () => { + let outputFixturesFilePath: string, + isFileExist: boolean; - JavaScriptObfuscator.runCLI([ - 'node', - 'javascript-obfuscator', - fixtureFilePath - ]); + before(() => { + outputFixturesFilePath = `${fixturesDirName}/${outputFileName}`; - assert.equal(fs.existsSync(outputFixturesFilePath), true); + JavaScriptObfuscator.runCLI([ + 'node', + 'javascript-obfuscator', + fixtureFilePath + ]); - fs.unlinkSync(outputFixturesFilePath); + isFileExist = fs.existsSync(outputFixturesFilePath); + }); + + it(`should create file \`${outputFileName}\` with obfuscated code in \`${fixturesDirName}\` directory`, () => { + assert.equal(isFileExist, true); + }); + + after(() => { + fs.unlinkSync(outputFixturesFilePath); + }); }); - it(`should throw an error if input path is not a valid file path`, () => { - assert.throws(() => JavaScriptObfuscator.runCLI([ - 'node', - 'javascript-obfuscator', - 'wrong/file/path' - ]), ReferenceError); + describe('variant #2: invalid input file path', () => { + const expectedError: ReferenceErrorConstructor = ReferenceError; + + let testFunc: () => void; + + before(() => { + testFunc = () => JavaScriptObfuscator.runCLI([ + 'node', + 'javascript-obfuscator', + 'wrong/file/path' + ]); + }); + + it(`should throw an error`, () => { + assert.throws(testFunc, expectedError); + }); }); - it(`should throw an error if input file extension is not a .js extension`, () => { - let outputWrongExtensionFileName: string = 'sample-obfuscated.ts', - outputWrongExtensionFilePath: string = `${outputDirName}/${outputWrongExtensionFileName}`; + describe('variant #3: input file extension isn\'t `.js`', () => { + const expectedError: ReferenceErrorConstructor = ReferenceError; + const outputFileName: string = 'sample-obfuscated.ts'; + const outputFilePath: string = `${outputDirName}/${outputFileName}`; - fs.writeFileSync(outputWrongExtensionFilePath, 'data'); + let testFunc: () => void; - assert.throws(() => JavaScriptObfuscator.runCLI([ - 'node', - 'javascript-obfuscator', - outputWrongExtensionFilePath - ]), ReferenceError); + before(() => { + fs.writeFileSync(outputFilePath, 'data'); - fs.unlinkSync(outputWrongExtensionFilePath); + testFunc = () => JavaScriptObfuscator.runCLI([ + 'node', + 'javascript-obfuscator', + outputFilePath + ]); + }); + + it(`should throw an error`, () => { + assert.throws(testFunc, expectedError); + }); + + after(() => { + fs.unlinkSync(outputFilePath); + }); }); }); - describe('--sourceMap option is set', () => { - let outputSourceMapPath: string = `${outputFilePath}.map`; + describe('`--sourceMap` option is set', () => { + const outputSourceMapPath: string = `${outputFilePath}.map`; - describe('--sourceMapMode option is `separate`', () => { - it('should creates file with source map in the same directory as output file', () => { - JavaScriptObfuscator.runCLI([ - 'node', - 'javascript-obfuscator', - fixtureFilePath, - '--output', - outputFilePath, - '--compact', - 'true', - '--selfDefending', - '0', - '--sourceMap', - 'true' - ]); + describe('variant #1: `--sourceMapMode` option value is `separate`', () => { + describe('variant #1: default behaviour', () => { + let isFileExist: boolean, + sourceMapObject: any; - assert.equal(fs.existsSync(outputSourceMapPath), true); + before(() => { + JavaScriptObfuscator.runCLI([ + 'node', + 'javascript-obfuscator', + fixtureFilePath, + '--output', + outputFilePath, + '--compact', + 'true', + '--selfDefending', + '0', + '--sourceMap', + 'true' + ]); - const content: string = fs.readFileSync(outputSourceMapPath, { encoding: 'utf8' }), - sourceMap: any = JSON.parse(content); + try { + const content: string = fs.readFileSync(outputSourceMapPath, { encoding: 'utf8' }); - assert.property(sourceMap, 'version'); - assert.property(sourceMap, 'sources'); - assert.property(sourceMap, 'names'); + isFileExist = true; + sourceMapObject = JSON.parse(content); + } catch (e) { + isFileExist = false; + } + }); + + it('should create file with source map in the same directory as output file', () => { + assert.equal(isFileExist, true); + }); + + it('source map from created file should contains property `version`', () => { + assert.property(sourceMapObject, 'version'); + }); + + it('source map from created file should contains property `sources`', () => { + assert.property(sourceMapObject, 'sources'); + }); + + it('source map from created file should contains property `names`', () => { + assert.property(sourceMapObject, 'names'); + }); + + after(() => { + fs.unlinkSync(outputFilePath); + fs.unlinkSync(outputSourceMapPath); + }); }); - it('should creates file with source map in the same directory as output file if `sourceMapBaseUrl` is set', () => { - JavaScriptObfuscator.runCLI([ - 'node', - 'javascript-obfuscator', - fixtureFilePath, - '--output', - outputFilePath, - '--compact', - 'true', - '--selfDefending', - '0', - '--sourceMap', - 'true', - '--sourceMapBaseUrl', - 'http://localhost:9000/' - ]); + describe('variant #2: `sourceMapBaseUrl` option is set', () => { + let isFileExist: boolean, + sourceMapObject: any; - assert.equal(fs.existsSync(outputSourceMapPath), true); + before(() => { + JavaScriptObfuscator.runCLI([ + 'node', + 'javascript-obfuscator', + fixtureFilePath, + '--output', + outputFilePath, + '--compact', + 'true', + '--selfDefending', + '0', + '--sourceMap', + 'true', + '--sourceMapBaseUrl', + 'http://localhost:9000/' + ]); - const content: string = fs.readFileSync(outputSourceMapPath, { encoding: 'utf8' }), - sourceMap: any = JSON.parse(content); + try { + const content: string = fs.readFileSync(outputSourceMapPath, { encoding: 'utf8' }); - assert.property(sourceMap, 'version'); - assert.property(sourceMap, 'sources'); - assert.property(sourceMap, 'names'); + isFileExist = true; + sourceMapObject = JSON.parse(content); + } catch (e) { + isFileExist = false; + } + }); + + it('should create file with source map in the same directory as output file', () => { + assert.equal(isFileExist, true); + }); + + it('source map from created file should contains property `version`', () => { + assert.property(sourceMapObject, 'version'); + }); + + it('source map from created file should contains property `sources`', () => { + assert.property(sourceMapObject, 'sources'); + }); + + it('source map from created file should contains property `names`', () => { + assert.property(sourceMapObject, 'names'); + }); + + after(() => { + fs.unlinkSync(outputFilePath); + fs.unlinkSync(outputSourceMapPath); + }); }); - afterEach(() => { - fs.unlinkSync(outputSourceMapPath); + describe('variant #3: `--sourceMapFileName` option is set', () => { + const sourceMapFileName: string = 'test'; + const sourceMapFilePath: string = `${sourceMapFileName}.js.map`; + const outputSourceMapFilePath: string = `${outputDirName}/${sourceMapFilePath}`; + + let isFileExist: boolean, + sourceMapObject: any; + + before(() => { + JavaScriptObfuscator.runCLI([ + 'node', + 'javascript-obfuscator', + fixtureFilePath, + '--output', + outputFilePath, + '--compact', + 'true', + '--selfDefending', + '0', + '--sourceMap', + 'true', + '--sourceMapFileName', + sourceMapFileName + ]); + + try { + const content: string = fs.readFileSync(outputSourceMapFilePath, { encoding: 'utf8' }); + + isFileExist = true; + sourceMapObject = JSON.parse(content); + } catch (e) { + isFileExist = false; + } + }); + + it('should create source map file with given name in the same directory as output file', () => { + assert.equal(isFileExist, true); + }); + + it('source map from created file should contains property `version`', () => { + assert.property(sourceMapObject, 'version'); + }); + + it('source map from created file should contains property `sources`', () => { + assert.property(sourceMapObject, 'sources'); + }); + + it('source map from created file should contains property `names`', () => { + assert.property(sourceMapObject, 'names'); + }); + + after(() => { + fs.unlinkSync(outputFilePath); + fs.unlinkSync(outputSourceMapFilePath); + }); }); }); - describe('--sourceMapFileName option is set', () => { - let sourceMapFileName: string = 'test', - sourceMapFilePath: string = `${sourceMapFileName}.js.map`, - outputSourceMapFilePath: string = `${outputDirName}/${sourceMapFilePath}`; + describe('variant #2: `--sourceMapMode` option is `inline`', () => { + let isFileExist: boolean; - it('should creates source map file with given name in the same directory as output file', () => { - JavaScriptObfuscator.runCLI([ - 'node', - 'javascript-obfuscator', - fixtureFilePath, - '--output', - outputFilePath, - '--compact', - 'true', - '--selfDefending', - '0', - '--sourceMap', - 'true', - '--sourceMapFileName', - sourceMapFileName - ]); - - assert.equal(fs.existsSync(outputSourceMapFilePath), true); - - const content: string = fs.readFileSync(outputSourceMapFilePath, { encoding: 'utf8' }), - sourceMap: any = JSON.parse(content); - - assert.property(sourceMap, 'version'); - assert.property(sourceMap, 'sources'); - assert.property(sourceMap, 'names'); - }); - - afterEach(() => { - fs.unlinkSync(outputSourceMapFilePath); - }); - }); - - describe('--sourceMapMode option is `inline`', () => { - it('shouldn\'t create file with source map if `sourceMapMode` is `inline`', () => { + before(() => { JavaScriptObfuscator.runCLI([ 'node', 'javascript-obfuscator', @@ -200,12 +308,16 @@ describe('JavaScriptObfuscatorCLI', function (): void { 'inline' ]); - assert.equal(fs.existsSync(outputSourceMapPath), false); + isFileExist = fs.existsSync(outputSourceMapPath); }); - }); - afterEach(() => { - fs.unlinkSync(outputFilePath); + it('shouldn\'t create file with source map', () => { + assert.equal(isFileExist, false); + }); + + after(() => { + fs.unlinkSync(outputFilePath); + }); }); }); @@ -218,32 +330,46 @@ describe('JavaScriptObfuscatorCLI', function (): void { stdoutWriteMock = new StdoutWriteMock(process.stdout.write); }); - it('should print `console.log` help if `--help` option is set', () => { - stdoutWriteMock.mute(); + describe('`--help` option is set', () => { + let isConsoleLogCalled: boolean; - JavaScriptObfuscator.runCLI([ - 'node', - 'javascript-obfuscator', - fixtureFilePath, - '--help' - ]); + beforeEach(() => { + stdoutWriteMock.mute(); - stdoutWriteMock.restore(); + JavaScriptObfuscator.runCLI([ + 'node', + 'javascript-obfuscator', + fixtureFilePath, + '--help' + ]); - assert.equal(callback.called, true); + stdoutWriteMock.restore(); + isConsoleLogCalled = callback.called; + }); + + it('should print `console.log` help', () => { + assert.equal(isConsoleLogCalled, true); + }); }); - it('should print `console.log` help if no options is passed', () => { - stdoutWriteMock.mute(); + describe('no arguments passed', () => { + let isConsoleLogCalled: boolean; - JavaScriptObfuscator.runCLI([ - 'node', - 'javascript-obfuscator' - ]); + beforeEach(() => { + stdoutWriteMock.mute(); - stdoutWriteMock.restore(); + JavaScriptObfuscator.runCLI([ + 'node', + 'javascript-obfuscator' + ]); - assert.equal(callback.called, true); + stdoutWriteMock.restore(); + isConsoleLogCalled = callback.called; + }); + + it('should print `console.log` help', () => { + assert.equal(isConsoleLogCalled, true); + }); }); afterEach(() => { diff --git a/test/functional-tests/javascript-obfuscator-internal/JavaScriptObfuscatorInternal.spec.ts b/test/functional-tests/javascript-obfuscator-internal/JavaScriptObfuscatorInternal.spec.ts index 51784a8d..e61d3fff 100644 --- a/test/functional-tests/javascript-obfuscator-internal/JavaScriptObfuscatorInternal.spec.ts +++ b/test/functional-tests/javascript-obfuscator-internal/JavaScriptObfuscatorInternal.spec.ts @@ -12,48 +12,72 @@ import { InversifyContainerFacade } from '../../../src/container/InversifyContai describe('JavaScriptObfuscatorInternal', () => { describe(`setSourceMapUrl (url: string)`, () => { + const code: string = 'var test = 1;'; + const sourceMapUrl: string = 'test.js.map'; + let inversifyContainerFacade: IInversifyContainerFacade, - javaScriptObfuscator: IJavaScriptObfuscator, - obfuscationResult: IObfuscationResult, - sourceMapUrl: string = 'test.js.map'; + javaScriptObfuscator: IJavaScriptObfuscator; - it('should link obfuscated code with source map', () => { - inversifyContainerFacade = new InversifyContainerFacade({ - ...NO_CUSTOM_NODES_PRESET, - sourceMap: true, - sourceMapFileName: sourceMapUrl + describe('variant #1: default behaviour', () => { + const regExp: RegExp = new RegExp(`sourceMappingURL=${sourceMapUrl}`); + + let obfuscatedCode: string, + sourceMapObject: any; + + before(() => { + inversifyContainerFacade = new InversifyContainerFacade({ + ...NO_CUSTOM_NODES_PRESET, + sourceMap: true, + sourceMapFileName: sourceMapUrl + }); + javaScriptObfuscator = inversifyContainerFacade + .get(ServiceIdentifiers.IJavaScriptObfuscator); + + const obfuscationResult: IObfuscationResult = javaScriptObfuscator.obfuscate(code); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + sourceMapObject = JSON.parse(obfuscationResult.getSourceMap()); }); - javaScriptObfuscator = inversifyContainerFacade - .get(ServiceIdentifiers.IJavaScriptObfuscator); - obfuscationResult = javaScriptObfuscator.obfuscate('var test = 1;'); + it('should link obfuscated code with source map', () => { + assert.match(obfuscatedCode, regExp); + }); - assert.match( - obfuscationResult.getObfuscatedCode(), - new RegExp(`sourceMappingURL=${sourceMapUrl}`)) - ; - assert.isOk(JSON.parse(obfuscationResult.getSourceMap()).mappings); + it('should return valid source map with `mappings` property', () => { + assert.isOk(sourceMapObject.mappings); + }); }); - it('should properly add base url to source map import inside obfuscated code if `sourceMapBaseUrl` is set', () => { + describe('variant #2: `sourceMapBaseUrl` is set', () => { const sourceMapBaseUrl: string = 'http://localhost:9000'; + const regExp: RegExp = new RegExp(`sourceMappingURL=${sourceMapBaseUrl}/${sourceMapUrl}$`); - inversifyContainerFacade = new InversifyContainerFacade({ - ...NO_CUSTOM_NODES_PRESET, - sourceMap: true, - sourceMapBaseUrl: sourceMapBaseUrl, - sourceMapFileName: sourceMapUrl + let obfuscatedCode: string, + sourceMapObject: any; + + before(() => { + inversifyContainerFacade = new InversifyContainerFacade({ + ...NO_CUSTOM_NODES_PRESET, + sourceMap: true, + sourceMapBaseUrl: sourceMapBaseUrl, + sourceMapFileName: sourceMapUrl + }); + javaScriptObfuscator = inversifyContainerFacade + .get(ServiceIdentifiers.IJavaScriptObfuscator); + + const obfuscationResult: IObfuscationResult = javaScriptObfuscator.obfuscate(code); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + sourceMapObject = JSON.parse(obfuscationResult.getSourceMap()); }); - javaScriptObfuscator = inversifyContainerFacade - .get(ServiceIdentifiers.IJavaScriptObfuscator); - obfuscationResult = javaScriptObfuscator.obfuscate('var test = 1;'); + it('should properly add base url to source map import inside obfuscated code', () => { + assert.match(obfuscatedCode, regExp); + }); - assert.match( - obfuscationResult.getObfuscatedCode(), - new RegExp(`sourceMappingURL=${sourceMapBaseUrl}/${sourceMapUrl}$`)) - ; - assert.isOk(JSON.parse(obfuscationResult.getSourceMap()).mappings); + it('should return valid source map with `mappings` property', () => { + assert.isOk(sourceMapObject.mappings); + }); }); }); }); diff --git a/test/functional-tests/javascript-obfuscator/JavaScriptObfuscator.spec.ts b/test/functional-tests/javascript-obfuscator/JavaScriptObfuscator.spec.ts index ff51c4cf..850428bd 100644 --- a/test/functional-tests/javascript-obfuscator/JavaScriptObfuscator.spec.ts +++ b/test/functional-tests/javascript-obfuscator/JavaScriptObfuscator.spec.ts @@ -16,210 +16,418 @@ describe('JavaScriptObfuscator', () => { RandomGeneratorUtils.initializeRandomGenerator(0); }); - describe('if `sourceMap` option is `false`', () => { - it('should returns object with obfuscated code and empty source map', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/simple-input-1.js'), + describe('correct source code', () => { + let obfuscatedCode: string, + sourceMap: string; + + beforeEach(() => { + const code: string = readFileAsString(__dirname + '/fixtures/simple-input-1.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, { ...NO_CUSTOM_NODES_PRESET } ); - assert.isOk(obfuscationResult.getObfuscatedCode()); - assert.isNotOk(obfuscationResult.getSourceMap()); + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + sourceMap = obfuscationResult.getSourceMap(); + }); + + it('should return correct obfuscated code', () => { + assert.isOk(obfuscatedCode); + }); + + it('should return empty source map', () => { + assert.isNotOk(sourceMap); }); }); - describe('if `sourceMap` option is `true`', () => { - it('should returns object with obfuscated code and source map', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/simple-input-1.js'), - { - ...NO_CUSTOM_NODES_PRESET, - sourceMap: true - } + describe('empty source code', () => { + let obfuscatedCode: string; + + beforeEach(() => { + const code: string = readFileAsString(__dirname + '/fixtures/empty-input.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, ); - assert.isOk(obfuscationResult.getObfuscatedCode()); - assert.isOk(JSON.parse(obfuscationResult.getSourceMap()).mappings); + obfuscatedCode = obfuscationResult.getObfuscatedCode(); }); - it('should returns object with obfuscated code with inline source map as Base64 string', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/simple-input-1.js'), - { - ...NO_CUSTOM_NODES_PRESET, - sourceMap: true, - sourceMapMode: 'inline' - } - ); - - assert.isOk(obfuscationResult.getObfuscatedCode()); - assert.match( - obfuscationResult.getObfuscatedCode(), - /sourceMappingURL=data:application\/json;base64/ - ); - assert.isOk(obfuscationResult.getSourceMap()); - }); - - it('should returns object with empty obfuscated code and source map with empty data if source code is empty', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/empty-input.js'), - { - sourceMap: true - } - ); - - assert.isNotOk(obfuscationResult.getObfuscatedCode()); - assert.deepEqual(JSON.parse(obfuscationResult.getSourceMap()).names, []); - assert.deepEqual(JSON.parse(obfuscationResult.getSourceMap()).sources, []); - assert.isNotOk(JSON.parse(obfuscationResult.getSourceMap()).mappings); + it('should return an empty obfuscated code', () => { + assert.isNotOk(obfuscatedCode); }); }); - it('should returns an empty string if source code is empty', () => { - assert.isNotOk( - JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/empty-input.js'), - ).getObfuscatedCode() - ); + describe('empty source code with comments', () => { + let obfuscatedCode: string; + + beforeEach(() => { + const code: string = readFileAsString(__dirname + '/fixtures/comments-only.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('should return an empty obfuscated code', () => { + assert.isNotOk(obfuscatedCode); + }); }); - it('should returns an empty string if source code contains only comments', () => { - assert.isNotOk( - JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/comments-only.js'), - ).getObfuscatedCode() - ); + describe('`sourceMap` option is `true`', () => { + describe('`sourceMapMode` is `separate`', () => { + let obfuscatedCode: string, + sourceMap: string; + + beforeEach(() => { + const code: string = readFileAsString(__dirname + '/fixtures/simple-input-1.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + sourceMap: true + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + sourceMap = JSON.parse(obfuscationResult.getSourceMap()).mappings; + }); + + it('should return correct obfuscated code', () => { + assert.isOk(obfuscatedCode); + }); + + it('should return correct source map', () => { + assert.isOk(sourceMap); + }); + }); + + describe('`sourceMapMode` is `inline`', () => { + const regExp: RegExp = /sourceMappingURL=data:application\/json;base64/; + + let obfuscatedCode: string, + sourceMap: string; + + beforeEach(() => { + const code: string = readFileAsString(__dirname + '/fixtures/simple-input-1.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + sourceMap: true, + sourceMapMode: 'inline' + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + sourceMap = JSON.parse(obfuscationResult.getSourceMap()).mappings; + }); + + it('should return correct obfuscated code', () => { + assert.isOk(obfuscatedCode); + }); + + it('should return obfuscated code with inline source map as Base64 string', () => { + assert.match(obfuscatedCode, regExp); + }); + + it('should return correct source map', () => { + assert.isOk(sourceMap); + }); + }); + + describe('empty source code', () => { + let obfuscatedCode: string, + sourceMapNames: string[], + sourceMapSources: string[], + sourceMapMappings: string; + + beforeEach(() => { + const code: string = readFileAsString(__dirname + '/fixtures/empty-input.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + sourceMap: true + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + + const sourceMapObject: any = JSON.parse(obfuscationResult.getSourceMap()); + + sourceMapNames = sourceMapObject.names; + sourceMapSources = sourceMapObject.sources; + sourceMapMappings = sourceMapObject.mappings; + }); + + it('should return empty obfuscated code', () => { + assert.isNotOk(obfuscatedCode); + }); + + it('should return empty source map property `names`', () => { + assert.deepEqual(sourceMapNames, []); + }); + + it('should return empty source map property `sources`', () => { + assert.deepEqual(sourceMapSources, []); + }); + + it('should return empty source map property `mappings`', () => { + assert.isNotOk(sourceMapMappings); + }); + }); }); - it('should obfuscate simple code with variable inside global scope', () => { - assert.match( - JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/simple-input-1.js'), + describe('variable inside global scope', () => { + const regExp: RegExp = /^var *test *= *0x\d+;$/; + + let obfuscatedCode: string; + + beforeEach(() => { + const code: string = readFileAsString(__dirname + '/fixtures/simple-input-1.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, { ...NO_CUSTOM_NODES_PRESET } - ).getObfuscatedCode(), - /^var *test *= *0x\d+;$/ - ); + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('should return correct obfuscated code', () => { + assert.match(obfuscatedCode, regExp); + }); }); - it('should obfuscate simple code with variable inside block-scope', () => { - assert.match( - JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/block-scope.js'), + describe('variable inside global scope', () => { + const regExp: RegExp = /^\(function *\(\) *\{ *var *_0x[\w]+ *= *0x\d+; *\}(\(\)\)|\)\(\));?$/; + + let obfuscatedCode: string; + + beforeEach(() => { + const code: string = readFileAsString(__dirname + '/fixtures/block-scope.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, { ...NO_CUSTOM_NODES_PRESET } - ).getObfuscatedCode(), - /^\(function *\(\) *\{ *var *_0x[\w]+ *= *0x\d+; *\}(\(\)\)|\)\(\));?$/ - ); + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('should return correct obfuscated code', () => { + assert.match(obfuscatedCode, regExp); + }); }); - it('should obfuscate simple code with latin literal variable value', () => { - let stringArrayLatinRegExp: RegExp = /^var _0x(\w){4} *= *\['abc'\];/, - stringArrayCallRegExp: RegExp = /var *test *= *_0x(\w){4}\('0x0'\);$/, - obfuscatedCode1: string = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/simple-input-2.js'), + describe('latin literal variable value', () => { + const stringArrayLatinRegExp: RegExp = /^var _0x(\w){4} *= *\['abc'\];/; + const stringArrayCallRegExp: RegExp = /var *test *= *_0x(\w){4}\('0x0'\);$/; + + let obfuscatedCode: string; + + beforeEach(() => { + const code: string = readFileAsString(__dirname + '/fixtures/simple-input-2.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, { ...NO_CUSTOM_NODES_PRESET, stringArray: true, stringArrayThreshold: 1 } - ).getObfuscatedCode(); + ); - assert.match(obfuscatedCode1, stringArrayLatinRegExp); - assert.match(obfuscatedCode1, stringArrayCallRegExp); + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('match #1: should return correct obfuscated code', () => { + assert.match(obfuscatedCode, stringArrayLatinRegExp); + }); + + it('match #2: should return correct obfuscated code', () => { + assert.match(obfuscatedCode, stringArrayCallRegExp); + }); }); - it('should obfuscate simple code with cyrillic literal variable value', () => { - let stringArrayCyrillicRegExp: RegExp = /^var _0x(\w){4} *= *\['(\\u\d+)+'\];/, - stringArrayCallRegExp: RegExp = /var *test *= *_0x(\w){4}\('0x0'\);$/, - obfuscatedCode2: string = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/simple-input-cyrillic.js'), + describe('cyrillic literal variable value', () => { + const stringArrayCyrillicRegExp: RegExp = /^var _0x(\w){4} *= *\['(\\u\d+)+'\];/; + const stringArrayCallRegExp: RegExp = /var *test *= *_0x(\w){4}\('0x0'\);$/; + + let obfuscatedCode: string; + + beforeEach(() => { + const code: string = readFileAsString(__dirname + '/fixtures/simple-input-cyrillic.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, { ...NO_CUSTOM_NODES_PRESET, stringArray: true, stringArrayThreshold: 1 } - ).getObfuscatedCode(); + ); - assert.match(obfuscatedCode2, stringArrayCyrillicRegExp); - assert.match(obfuscatedCode2, stringArrayCallRegExp); + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('match #1: should return correct obfuscated code', () => { + assert.match(obfuscatedCode, stringArrayCyrillicRegExp); + }); + + it('match #2: should return correct obfuscated code', () => { + assert.match(obfuscatedCode, stringArrayCallRegExp); + }); }); - it('should returns same code every time with same `seed`', function () { + describe('seed', function () { this.timeout(60000); - const code: string = readFileAsString('./test/fixtures/sample.js'); - const samples: number = 100; + describe('same seed on each run', () => { + const code: string = readFileAsString('./test/fixtures/sample.js'); + const samples: number = 100; - let seed: number = 12345, - equalsCount: number = 0; + let obfuscatedCode1: string, + obfuscatedCode2: string, + seed: number = 12345, + equalsCount: number = 0; - for (let i: number = 0; i < samples; i++) { - if (i % 20 === 0) { - seed++; - } + beforeEach(() => { + for (let i: number = 0; i < samples; i++) { + if (i % 20 === 0) { + seed++; + } - const obfuscationResult1: IObfuscationResult = JavaScriptObfuscator.obfuscate( - code, { seed: seed } - ); - const obfuscationResult2: IObfuscationResult = JavaScriptObfuscator.obfuscate( - code, { seed: seed } - ); + const obfuscationResult1: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + seed: seed + } + ); + const obfuscationResult2: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + seed: seed + } + ); - if (obfuscationResult1.getObfuscatedCode() === obfuscationResult2.getObfuscatedCode()) { - equalsCount++; - } - } + obfuscatedCode1 = obfuscationResult1.getObfuscatedCode(); + obfuscatedCode2 = obfuscationResult2.getObfuscatedCode(); - assert.equal(equalsCount, samples); + if (obfuscatedCode1 === obfuscatedCode2) { + equalsCount++; + } + } + }); + + it('should return same code every time with same `seed`', () => { + assert.equal(equalsCount, samples); + }); + }); + + describe('variant #1: different seed on each run', () => { + const code: string = readFileAsString('./test/fixtures/sample.js'); + + let obfuscatedCode1: string, + obfuscatedCode2: string; + + beforeEach(() => { + const obfuscationResult1: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + seed: 12345 + } + ); + const obfuscationResult2: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + seed: 12346 + } + ); + + obfuscatedCode1 = obfuscationResult1.getObfuscatedCode(); + obfuscatedCode2 = obfuscationResult2.getObfuscatedCode(); + }); + + it('should return different obfuscated code with different `seed` option value', () => { + assert.notEqual(obfuscatedCode1, obfuscatedCode2); + }); + }); + + describe('variant #2: different seed on each run', () => { + const code: string = readFileAsString('./test/fixtures/sample.js'); + + let obfuscatedCode1: string, + obfuscatedCode2: string; + + beforeEach(() => { + const obfuscationResult1: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + seed: 0 + } + ); + const obfuscationResult2: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + seed: 0 + } + ); + + obfuscatedCode1 = obfuscationResult1.getObfuscatedCode(); + obfuscatedCode2 = obfuscationResult2.getObfuscatedCode(); + }); + + it('should return different obfuscated code with different `seed` option value', () => { + assert.notEqual(obfuscatedCode1, obfuscatedCode2); + }); + }); }); - it('should returns different code with different `seed` option value', () => { - const code: string = readFileAsString('./test/fixtures/sample.js'); + describe('new.target MetaProperty', () => { + const regExp: RegExp = /new\.target *=== *Foo/; - const obfuscationResult1: IObfuscationResult = JavaScriptObfuscator.obfuscate( - code, { seed: 12345 } - ); - const obfuscationResult2: IObfuscationResult = JavaScriptObfuscator.obfuscate( - code, { seed: 12346 } - ); + let obfuscatedCode: string; - const obfuscationResult3: IObfuscationResult = JavaScriptObfuscator.obfuscate( - code, { seed: 0 } - ); - const obfuscationResult4: IObfuscationResult = JavaScriptObfuscator.obfuscate( - code, { seed: 0 } - ); - - assert.notEqual(obfuscationResult1.getObfuscatedCode(), obfuscationResult2.getObfuscatedCode()); - assert.notEqual(obfuscationResult3.getObfuscatedCode(), obfuscationResult4.getObfuscatedCode()); - }); - - it('should keep new.target MetaProperty', () => { - assert.match( - JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/new-target.js'), + beforeEach(() => { + const code: string = readFileAsString(__dirname + '/fixtures/new-target.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, { ...NO_CUSTOM_NODES_PRESET } - ).getObfuscatedCode(), - /new\.target *=== *Foo/ - ); + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('should keep new.target MetaProperty', () => { + assert.match(obfuscatedCode, regExp); + }); }); - it('should mangle obfuscated code', () => { - const code: string = readFileAsString(__dirname + '/fixtures/mangle.js'); + describe('mangle', () => { + const regExp: RegExp = /var *a *= *0x1/; - const obfuscationResult1: IObfuscationResult = JavaScriptObfuscator.obfuscate( - code, { mangle: true } - ); - const mangleMatch: RegExp = /var *a *= *0x1/; + let obfuscatedCode: string; - assert.match(obfuscationResult1.getObfuscatedCode(), mangleMatch); + beforeEach(() => { + const code: string = readFileAsString(__dirname + '/fixtures/mangle.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + mangle: true + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('should mangle obfuscated code', () => { + assert.match(obfuscatedCode, regExp); + }); }); afterEach(() => { diff --git a/test/functional-tests/node-transformers/control-flow-transformers/block-statement-control-flow-transformer/BlockStatementControlFlowTransformer.spec.ts b/test/functional-tests/node-transformers/control-flow-transformers/block-statement-control-flow-transformer/BlockStatementControlFlowTransformer.spec.ts index ea9512f6..529c8f2b 100644 --- a/test/functional-tests/node-transformers/control-flow-transformers/block-statement-control-flow-transformer/BlockStatementControlFlowTransformer.spec.ts +++ b/test/functional-tests/node-transformers/control-flow-transformers/block-statement-control-flow-transformer/BlockStatementControlFlowTransformer.spec.ts @@ -8,229 +8,384 @@ import { readFileAsString } from '../../../../helpers/readFileAsString'; import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscator'; -describe('BlockStatementControlFlowTransformer', () => { +/** + * @param hexNumber + * @return {RegExp} + */ +const getStatementRegExp: (hexNumber: string) => RegExp = (hexNumber) => { + return new RegExp(`console\\['log'\\]\\(${hexNumber}\\);`); +}; + +describe('BlockStatementControlFlowTransformer', function () { + this.timeout(100000); + describe('transformNode (blockStatementNode: ESTree.BlockStatement): ESTree.Node', () => { - const switchCaseMapStringRegExp: RegExp = /var *_0x(?:[a-f0-9]){4,6} *= *\{'.*' *: *'(.*)'\};/; - const switchCaseMapVariableRegExp: RegExp = /var *_0x(?:[a-f0-9]){4,6} *= *_0x(?:[a-f0-9]){4,6}\['.*'\]\['split'\]\('\\x7c'\)/; - describe('variant #1: 5 simple statements', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/input-1.js'), - { - ...NO_CUSTOM_NODES_PRESET, - controlFlowFlattening: true, - controlFlowFlatteningThreshold: 1 - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); + let obfuscatedCode: string; - const statementRegExp1: RegExp = /console\['log'\]\(0x1\);/; - const statementRegExp2: RegExp = /console\['log'\]\(0x2\);/; - const statementRegExp3: RegExp = /console\['log'\]\(0x3\);/; - const statementRegExp4: RegExp = /console\['log'\]\(0x4\);/; - const statementRegExp5: RegExp = /console\['log'\]\(0x5\);/; + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/input-1.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + controlFlowFlattening: true, + controlFlowFlatteningThreshold: 1 + } + ); - const switchCaseRegExp: RegExp = /switch *\(_0x([a-f0-9]){4,6}\[_0x([a-f0-9]){4,6}\+\+\]\) *\{/; - const switchCaseLengthRegExp: RegExp = /case *'[0-5]': *console\['log'\]\(0x[0-6]\);/g; - const switchCaseLength: number = obfuscatedCode.match(switchCaseLengthRegExp)!.length; - - const switchCaseMapStringMatches: RegExpMatchArray = obfuscatedCode.match(switchCaseMapStringRegExp); - const switchCaseMapMatch: string = switchCaseMapStringMatches[1]; - const switchCaseMap: string[] = switchCaseMapMatch.replace(/\\x7c/g, '|').split('|').sort(); - - it('should save all statements', () => { - assert.match(obfuscatedCode, statementRegExp1); - assert.match(obfuscatedCode, statementRegExp2); - assert.match(obfuscatedCode, statementRegExp3); - assert.match(obfuscatedCode, statementRegExp4); - assert.match(obfuscatedCode, statementRegExp5); + obfuscatedCode = obfuscationResult.getObfuscatedCode(); }); - it('should wrap block statement statements in switch case structure', () => { - assert.match(obfuscatedCode, switchCaseRegExp); - assert.equal(switchCaseLength, 5); + describe('`console.log` statements', ()=> { + const statementRegExp1: RegExp = getStatementRegExp('0x1'); + const statementRegExp2: RegExp = getStatementRegExp('0x2'); + const statementRegExp3: RegExp = getStatementRegExp('0x3'); + const statementRegExp4: RegExp = getStatementRegExp('0x4'); + const statementRegExp5: RegExp = getStatementRegExp('0x5'); + + it('should save statement', () => { + assert.match(obfuscatedCode, statementRegExp1); + }); + + it('should save statement', () => { + assert.match(obfuscatedCode, statementRegExp2); + }); + + it('should save statement', () => { + assert.match(obfuscatedCode, statementRegExp3); + }); + + it('should save statement', () => { + assert.match(obfuscatedCode, statementRegExp4); + }); + + it('should save statement', () => { + assert.match(obfuscatedCode, statementRegExp5); + }); }); - it('should create variable with order of switch cases sequence', () => { - assert.deepEqual(switchCaseMap, ['0', '1', '2', '3', '4']); - assert.match(obfuscatedCode, switchCaseMapVariableRegExp); + describe('block statement statements', () => { + const switchCaseRegExp: RegExp = /switch *\(_0x([a-f0-9]){4,6}\[_0x([a-f0-9]){4,6}\+\+\]\) *\{/; + const switchCaseLengthRegExp: RegExp = /case *'[0-5]': *console\['log'\]\(0x[0-6]\);/g; + const expectedSwitchCaseLength: number = 5; + + let switchCaseLength: number; + + before(() => { + switchCaseLength = obfuscatedCode.match(switchCaseLengthRegExp)!.length; + }); + + it('should wrap block statement statements in switch-case structure', () => { + assert.match(obfuscatedCode, switchCaseRegExp); + }); + + it('each statement should be wrapped by switch-case structure', () => { + assert.equal(switchCaseLength, expectedSwitchCaseLength); + }); + }); + + describe('switch-case map', () => { + const switchCaseMapVariableRegExp: RegExp = /var *_0x(?:[a-f0-9]){4,6} *= *_0x(?:[a-f0-9]){4,6}\['.*'\]\['split'\]\('\\x7c'\)/; + const expectedSwitchCasesSequence: string[] = ['0', '1', '2', '3', '4']; + + let switchCaseMap: string[]; + + before(() => { + const switchCaseMapStringRegExp: RegExp = /var *_0x(?:[a-f0-9]){4,6} *= *\{'.*' *: *'(.*)'\};/; + const switchCaseMapStringMatches: RegExpMatchArray = obfuscatedCode.match(switchCaseMapStringRegExp); + const switchCaseMapMatch: string = switchCaseMapStringMatches[1]; + + switchCaseMap = switchCaseMapMatch.replace(/\\x7c/g, '|').split('|').sort(); + }); + + it('should create switch-case map variable', () => { + assert.match(obfuscatedCode, switchCaseMapVariableRegExp); + }); + + it('should create valid switch-case map variable with order of switch cases sequence', () => { + assert.deepEqual(switchCaseMap, expectedSwitchCasesSequence); + }); }); }); describe('variant #2: 5 simple statements inside while loop without break or continue statement', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/input-2.js'), - { - ...NO_CUSTOM_NODES_PRESET, - controlFlowFlattening: true, - controlFlowFlatteningThreshold: 1, - unicodeEscapeSequence: false - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); + let obfuscatedCode: string; - const statementRegExp1: RegExp = /console\['log'\]\(0x1\);/; - const statementRegExp2: RegExp = /console\['log'\]\(0x2\);/; - const statementRegExp3: RegExp = /console\['log'\]\(0x3\);/; - const statementRegExp4: RegExp = /console\['log'\]\(0x4\);/; - const statementRegExp5: RegExp = /console\['log'\]\(0x5\);/; + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/input-2.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + controlFlowFlattening: true, + controlFlowFlatteningThreshold: 1, + unicodeEscapeSequence: false + } + ); - const switchCaseRegExp: RegExp = /switch *\(_0x([a-f0-9]){4,6}\[_0x([a-f0-9]){4,6}\+\+\]\) *\{/; - const switchCaseLengthRegExp: RegExp = /case *'[0-5]': *console\['log'\]\(0x[0-6]\);/g; - const switchCaseLength: number = obfuscatedCode.match(switchCaseLengthRegExp)!.length; - - const switchCaseMapStringMatches: RegExpMatchArray = obfuscatedCode.match(switchCaseMapStringRegExp); - const switchCaseMapMatch: string = switchCaseMapStringMatches[1]; - const switchCaseMap: string[] = switchCaseMapMatch.replace(/\\x7c/g, '|').split('|').sort(); - - it('should save all statements', () => { - assert.match(obfuscatedCode, statementRegExp1); - assert.match(obfuscatedCode, statementRegExp2); - assert.match(obfuscatedCode, statementRegExp3); - assert.match(obfuscatedCode, statementRegExp4); - assert.match(obfuscatedCode, statementRegExp5); + obfuscatedCode = obfuscationResult.getObfuscatedCode(); }); - it('should wrap block statement statements in switch case structure', () => { - assert.match(obfuscatedCode, switchCaseRegExp); - assert.equal(switchCaseLength, 5); + describe('`console.log` statements', ()=> { + const statementRegExp1: RegExp = getStatementRegExp('0x1'); + const statementRegExp2: RegExp = getStatementRegExp('0x2'); + const statementRegExp3: RegExp = getStatementRegExp('0x3'); + const statementRegExp4: RegExp = getStatementRegExp('0x4'); + const statementRegExp5: RegExp = getStatementRegExp('0x5'); + + it('should save statement', () => { + assert.match(obfuscatedCode, statementRegExp1); + }); + + it('should save statement', () => { + assert.match(obfuscatedCode, statementRegExp2); + }); + + it('should save statement', () => { + assert.match(obfuscatedCode, statementRegExp3); + }); + + it('should save statement', () => { + assert.match(obfuscatedCode, statementRegExp4); + }); + + it('should save statement', () => { + assert.match(obfuscatedCode, statementRegExp5); + }); }); - it('should create variable with order of switch cases sequence', () => { - assert.deepEqual(switchCaseMap, ['0', '1', '2', '3', '4']); - assert.match(obfuscatedCode, switchCaseMapVariableRegExp); + describe('block statement statements', () => { + const switchCaseRegExp: RegExp = /switch *\(_0x([a-f0-9]){4,6}\[_0x([a-f0-9]){4,6}\+\+\]\) *\{/; + const expectedSwitchCaseLength: number = 5; + + let switchCaseLength: number; + + before(() => { + const switchCaseLengthRegExp: RegExp = /case *'[0-5]': *console\['log'\]\(0x[0-6]\);/g; + + switchCaseLength = obfuscatedCode.match(switchCaseLengthRegExp)!.length; + }); + + it('should wrap block statement statements in switch-case structure', () => { + assert.match(obfuscatedCode, switchCaseRegExp); + }); + + it('each statement should be wrapped by switch-case structure', () => { + assert.equal(switchCaseLength, expectedSwitchCaseLength); + }); + }); + + describe('switch-case map', () => { + const switchCaseMapVariableRegExp: RegExp = /var *_0x(?:[a-f0-9]){4,6} *= *_0x(?:[a-f0-9]){4,6}\['.*'\]\['split'\]\('\\x7c'\)/; + const expectedSwitchCasesSequence: string[] = ['0', '1', '2', '3', '4']; + + let switchCaseMap: string[]; + + before(() => { + const switchCaseMapStringRegExp: RegExp = /var *_0x(?:[a-f0-9]){4,6} *= *\{'.*' *: *'(.*)'\};/; + const switchCaseMapStringMatches: RegExpMatchArray = obfuscatedCode.match(switchCaseMapStringRegExp); + const switchCaseMapMatch: string = switchCaseMapStringMatches[1]; + + switchCaseMap = switchCaseMapMatch.replace(/\\x7c/g, '|').split('|').sort(); + }); + + it('should create switch-case map variable', () => { + assert.match(obfuscatedCode, switchCaseMapVariableRegExp); + }); + + it('should create valid switch-case map variable with order of switch cases sequence', () => { + assert.deepEqual(switchCaseMap, expectedSwitchCasesSequence); + }); }); }); - describe('variant #3: less then 5 statements', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/one-statement.js'), - { - ...NO_CUSTOM_NODES_PRESET, - controlFlowFlattening: true, - controlFlowFlatteningThreshold: 1 - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); - + describe('variant #3: statements length less then 5 statements', () => { const statementRegExp: RegExp = /^\(function *\( *\) *\{ *console\['log'\]\(0x1\); *\} *\( *\) *\);$/; - it('shouldn\'t transform block statement if statements length less than 5', () => { + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/one-statement.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + controlFlowFlattening: true, + controlFlowFlatteningThreshold: 1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('shouldn\'t transform block statement', () => { assert.match(obfuscatedCode, statementRegExp); }); }); - describe('variant #4: const declaration inside block statement', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/const-declaration.js'), - { - ...NO_CUSTOM_NODES_PRESET, - controlFlowFlattening: true, - controlFlowFlatteningThreshold: 1 - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); - + describe('variant #4: block statement contain variable declaration with `const` kind', () => { const statementRegExp: RegExp = /^\(function *\( *\) *\{ *const *_0x([a-f0-9]){4,6} *= *0x1; *console\['log'\]\(0x1\);/; - it('shouldn\'t transform block statement if block statement contain variable declaration with `const` kind', () => { + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/const-declaration.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + controlFlowFlattening: true, + controlFlowFlatteningThreshold: 1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('shouldn\'t transform block statement', () => { assert.match(obfuscatedCode, statementRegExp); }); }); - describe('variant #5: let declaration inside block statement', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/let-declaration.js'), - { - ...NO_CUSTOM_NODES_PRESET, - controlFlowFlattening: true, - controlFlowFlatteningThreshold: 1 - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); - + describe('variant #5: block statement contain variable declaration with `let` kind', () => { const statementRegExp: RegExp = /^\(function *\( *\) *\{ *let *_0x([a-f0-9]){4,6} *= *0x1; *console\['log'\]\(0x1\);/; - it('shouldn\'t transform block statement if block statement contain variable declaration with `let` kind', () => { + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/let-declaration.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + controlFlowFlattening: true, + controlFlowFlatteningThreshold: 1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('shouldn\'t transform block statement', () => { assert.match(obfuscatedCode, statementRegExp); }); }); - describe('variant #6: break statement inside block statement', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/break-statement.js'), - { - ...NO_CUSTOM_NODES_PRESET, - controlFlowFlattening: true, - controlFlowFlatteningThreshold: 1 - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); - + describe('variant #6: block statement contain break statement', () => { const statementRegExp: RegExp = /^\(function *\( *\) *\{ *while *\(!!\[\]\) *\{ *break; *console\['log'\]\(0x1\);/; - it('shouldn\'t transform block statement if block statement contain break statement', () => { + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/break-statement.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + controlFlowFlattening: true, + controlFlowFlatteningThreshold: 1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('shouldn\'t transform block statement', () => { assert.match(obfuscatedCode, statementRegExp); }); }); - describe('variant #7: continue statement inside block statement', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/continue-statement.js'), - { - ...NO_CUSTOM_NODES_PRESET, - controlFlowFlattening: true, - controlFlowFlatteningThreshold: 1 - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); - + describe('variant #7: block statement contain continue statement', () => { const statementRegExp: RegExp = /^\(function *\( *\) *\{ *while *\(!!\[\]\) *\{ *continue; *console\['log'\]\(0x1\);/; - it('shouldn\'t transform block statement if block statement contain continue statement', () => { + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/continue-statement.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + controlFlowFlattening: true, + controlFlowFlatteningThreshold: 1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('shouldn\'t transform block statement', () => { assert.match(obfuscatedCode, statementRegExp); }); }); - describe('variant #8: function declaration inside block statement', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/function-declaration.js'), - { - ...NO_CUSTOM_NODES_PRESET, - controlFlowFlattening: true, - controlFlowFlatteningThreshold: 1 - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); + describe('variant #8: block statement contain function declaration', () => { + const statementRegExp: RegExp = /^\(function *\( *\) *\{ *function *_0x([a-f0-9]){4,6} *\( *\) *\{ *\} *console\['log'\]\(0x1\);/ - const statementRegExp: RegExp = /^\(function *\( *\) *\{ *function *_0x([a-f0-9]){4,6} *\( *\) *\{ *\} *console\['log'\]\(0x1\);/; + let obfuscatedCode: string; - it('shouldn\'t transform block statement if block statement contain function declaration', () => { + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/function-declaration.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + controlFlowFlattening: true, + controlFlowFlatteningThreshold: 1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('shouldn\'t transform block statement', () => { assert.match(obfuscatedCode, statementRegExp); }); }); describe('variant #9: `controlFlowFlatteningThreshold` chance', () => { const samples: number = 1000; - const controlFlowFlatteningThreshold: number = 0.5; const delta: number = 0.1; - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/input-1.js').repeat(samples), - { - ...NO_CUSTOM_NODES_PRESET, - controlFlowFlattening: true, - controlFlowFlatteningThreshold: controlFlowFlatteningThreshold, - } - ); + + const controlFlowFlatteningThreshold: number = 0.5; const regExp1: RegExp = /switch *\(_0x([a-f0-9]){4,6}\[_0x([a-f0-9]){4,6}\+\+\]\) *\{/g; const regExp2: RegExp = /\(function *\( *\) *\{ *console\['log'\]\(0x1\);/g; - const transformedStatementMatchesLength = obfuscationResult.getObfuscatedCode().match(regExp1)!.length; - const untouchedStatementMatchesLength = obfuscationResult.getObfuscatedCode().match(regExp2)!.length; + + let transformedStatementPercentage: number, + untouchedStatementPercentage: number; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/input-1.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code.repeat(samples), + { + ...NO_CUSTOM_NODES_PRESET, + controlFlowFlattening: true, + controlFlowFlatteningThreshold: controlFlowFlatteningThreshold, + } + ); + + const transformedStatementMatchesLength: number = obfuscationResult + .getObfuscatedCode() + .match(regExp1)! + .length; + const untouchedStatementMatchesLength: number = obfuscationResult + .getObfuscatedCode() + .match(regExp2)! + .length; + + transformedStatementPercentage = transformedStatementMatchesLength / samples; + untouchedStatementPercentage = untouchedStatementMatchesLength / samples; + }); it('should transform block statement with `controlFlowFlatteningThreshold` chance', () => { - assert.closeTo(transformedStatementMatchesLength / samples, controlFlowFlatteningThreshold, delta); - assert.closeTo(untouchedStatementMatchesLength / samples, controlFlowFlatteningThreshold, delta); + assert.closeTo(transformedStatementPercentage, controlFlowFlatteningThreshold, delta); + }); + + it('should keep block statement with (1 - `controlFlowFlatteningThreshold`) chance', () => { + assert.closeTo(untouchedStatementPercentage, controlFlowFlatteningThreshold, delta); }); }); }); diff --git a/test/functional-tests/node-transformers/control-flow-transformers/control-flow-replacers/binary-expression-control-flow-replacer/BinaryExpressionControlFlowReplacer.spec.ts b/test/functional-tests/node-transformers/control-flow-transformers/control-flow-replacers/binary-expression-control-flow-replacer/BinaryExpressionControlFlowReplacer.spec.ts index 1ec93446..14b7963d 100644 --- a/test/functional-tests/node-transformers/control-flow-transformers/control-flow-replacers/binary-expression-control-flow-replacer/BinaryExpressionControlFlowReplacer.spec.ts +++ b/test/functional-tests/node-transformers/control-flow-transformers/control-flow-replacers/binary-expression-control-flow-replacer/BinaryExpressionControlFlowReplacer.spec.ts @@ -8,63 +8,96 @@ import { readFileAsString } from '../../../../../helpers/readFileAsString'; import { JavaScriptObfuscator } from '../../../../../../src/JavaScriptObfuscator'; -describe('BinaryExpressionControlFlowReplacer', () => { +describe('BinaryExpressionControlFlowReplacer', function () { + this.timeout(100000); + describe('replace (binaryExpressionNode: ESTree.BinaryExpression,parentNode: ESTree.Node,controlFlowStorage: IStorage )', () => { describe('variant #1 - single binary expression', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/input-1.js'), - { - ...NO_CUSTOM_NODES_PRESET, - controlFlowFlattening: true, - controlFlowFlatteningThreshold: 1 - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); const controlFlowStorageCallRegExp: RegExp = /var *_0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\['\w{3}'\]\(0x1, *0x2\);/; - it('should replace binary expression node by call to control flow storage node', () => { + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/input-1.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + controlFlowFlattening: true, + controlFlowFlatteningThreshold: 1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('should replace binary expression node with call to control flow storage node', () => { assert.match(obfuscatedCode, controlFlowStorageCallRegExp); }); }); describe('variant #2 - multiple binary expressions with threshold = 1', () => { - it('should replace binary expression node by call to control flow storage node', function () { - this.timeout(60000); + const expectedMatchErrorsCount: number = 0; + const expectedChance: number = 0.5; - const samplesCount: number = 1000; - const expectedValue: number = 0.5; - const delta: number = 0.1; + const samplesCount: number = 1000; + const delta: number = 0.1; - let equalsValue: number = 0; + const controlFlowStorageCallRegExp1: RegExp = /var *_0x(?:[a-f0-9]){4,6} *= *(_0x([a-f0-9]){4,6}\['\w{3}'\])\(0x1, *0x2\);/; + const controlFlowStorageCallRegExp2: RegExp = /var *_0x(?:[a-f0-9]){4,6} *= *(_0x([a-f0-9]){4,6}\['\w{3}'\])\(0x2, *0x3\);/; + + let matchErrorsCount: number = 0, + usingExistingIdentifierChance: number; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/input-2.js'); + + let obfuscationResult: IObfuscationResult, + obfuscatedCode: string, + firstMatchArray: RegExpMatchArray | null, + secondMatchArray: RegExpMatchArray | null, + firstMatch: string | undefined, + secondMatch: string | undefined, + equalsValue: number = 0; for (let i = 0; i < samplesCount; i++) { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/input-2.js'), + obfuscationResult = JavaScriptObfuscator.obfuscate( + code, { ...NO_CUSTOM_NODES_PRESET, controlFlowFlattening: true, controlFlowFlatteningThreshold: 1 } ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); - const controlFlowStorageCallRegExp1: RegExp = /var *_0x([a-f0-9]){4,6} *= *(_0x([a-f0-9]){4,6}\['\w{3}'\])\(0x1, *0x2\);/; - const controlFlowStorageCallRegExp2: RegExp = /var *_0x([a-f0-9]){4,6} *= *(_0x([a-f0-9]){4,6}\['\w{3}'\])\(0x2, *0x3\);/; - const firstMatchArray: RegExpMatchArray | null = obfuscatedCode.match(controlFlowStorageCallRegExp1); - const secondMatchArray: RegExpMatchArray | null = obfuscatedCode.match(controlFlowStorageCallRegExp2); + obfuscatedCode = obfuscationResult.getObfuscatedCode(); - const firstMatch: string | undefined = firstMatchArray ? firstMatchArray[2] : undefined; - const secondMatch: string | undefined = secondMatchArray ? secondMatchArray[2] : undefined; + firstMatchArray = obfuscatedCode.match(controlFlowStorageCallRegExp1); + secondMatchArray = obfuscatedCode.match(controlFlowStorageCallRegExp2); - assert.match(obfuscatedCode, controlFlowStorageCallRegExp1); - assert.match(obfuscatedCode, controlFlowStorageCallRegExp2); + if (!firstMatchArray || !secondMatchArray) { + matchErrorsCount++; + + continue; + } + + firstMatch = firstMatchArray ? firstMatchArray[1] : undefined; + secondMatch = secondMatchArray ? secondMatchArray[1] : undefined; if (firstMatch === secondMatch) { equalsValue++; } } - assert.closeTo(equalsValue / samplesCount, expectedValue, delta); + usingExistingIdentifierChance = equalsValue / samplesCount; + }); + + it('should replace binary expression node with call to control flow storage node', () => { + assert.equal(matchErrorsCount, expectedMatchErrorsCount); + }); + + it('should use existing identifier for control flow storage with expected chance', () => { + assert.closeTo(usingExistingIdentifierChance, expectedChance, delta); }); }); }); diff --git a/test/functional-tests/node-transformers/control-flow-transformers/control-flow-replacers/call-expression-control-flow-replacer/CallExpressionControlFlowReplacer.spec.ts b/test/functional-tests/node-transformers/control-flow-transformers/control-flow-replacers/call-expression-control-flow-replacer/CallExpressionControlFlowReplacer.spec.ts index e1cad533..9a701a28 100644 --- a/test/functional-tests/node-transformers/control-flow-transformers/control-flow-replacers/call-expression-control-flow-replacer/CallExpressionControlFlowReplacer.spec.ts +++ b/test/functional-tests/node-transformers/control-flow-transformers/control-flow-replacers/call-expression-control-flow-replacer/CallExpressionControlFlowReplacer.spec.ts @@ -8,80 +8,120 @@ import { readFileAsString } from '../../../../../helpers/readFileAsString'; import { JavaScriptObfuscator } from '../../../../../../src/JavaScriptObfuscator'; -describe('CallExpressionControlFlowReplacer', () => { +describe('CallExpressionControlFlowReplacer', function () { + this.timeout(100000); + describe('replace (callExpressionNode: ESTree.CallExpression,parentNode: ESTree.Node,controlFlowStorage: IStorage )', () => { describe('variant #1 - single call expression', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/input-1.js'), - { - ...NO_CUSTOM_NODES_PRESET, - controlFlowFlattening: true, - controlFlowFlatteningThreshold: 1 - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); const controlFlowStorageCallRegExp: RegExp = /var *_0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\['\w{3}'\]\(_0x([a-f0-9]){4,6}, *0x1, *0x2\);/; - it('should replace call expression node by call to control flow storage node', () => { + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/input-1.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + controlFlowFlattening: true, + controlFlowFlatteningThreshold: 1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('should replace call expression node with call to control flow storage node', () => { assert.match(obfuscatedCode, controlFlowStorageCallRegExp); }); }); describe('variant #2 - multiple call expressions with threshold = 1', () => { - it('should replace call expression node by call to control flow storage node', function () { - this.timeout(60000); + const expectedMatchErrorsCount: number = 0; + const expectedChance: number = 0.5; - const samplesCount: number = 1000; - const expectedValue: number = 0.5; - const delta: number = 0.1; + const samplesCount: number = 1000; + const delta: number = 0.1; - let equalsValue: number = 0; + const controlFlowStorageCallRegExp1: RegExp = /var *_0x(?:[a-f0-9]){4,6} *= *(_0x([a-f0-9]){4,6}\['\w{3}'\])\(_0x([a-f0-9]){4,6}, *0x1, *0x2\);/; + const controlFlowStorageCallRegExp2: RegExp = /var *_0x(?:[a-f0-9]){4,6} *= *(_0x([a-f0-9]){4,6}\['\w{3}'\])\(_0x([a-f0-9]){4,6}, *0x2, *0x3\);/; + + let matchErrorsCount: number = 0, + usingExistingIdentifierChance: number; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/input-2.js'); + + let obfuscationResult: IObfuscationResult, + obfuscatedCode: string, + firstMatchArray: RegExpMatchArray | null, + secondMatchArray: RegExpMatchArray | null, + firstMatch: string | undefined, + secondMatch: string | undefined, + equalsValue: number = 0; for (let i = 0; i < samplesCount; i++) { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/input-2.js'), + obfuscationResult = JavaScriptObfuscator.obfuscate( + code, { ...NO_CUSTOM_NODES_PRESET, controlFlowFlattening: true, controlFlowFlatteningThreshold: 1 } ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); - const controlFlowStorageCallRegExp1: RegExp = /var *_0x([a-f0-9]){4,6} *= *(_0x([a-f0-9]){4,6}\['\w{3}'\])\(_0x([a-f0-9]){4,6}, *0x1, *0x2\);/; - const controlFlowStorageCallRegExp2: RegExp = /var *_0x([a-f0-9]){4,6} *= *(_0x([a-f0-9]){4,6}\['\w{3}'\])\(_0x([a-f0-9]){4,6}, *0x2, *0x3\);/; - const firstMatchArray: RegExpMatchArray | null = obfuscatedCode.match(controlFlowStorageCallRegExp1); - const secondMatchArray: RegExpMatchArray | null = obfuscatedCode.match(controlFlowStorageCallRegExp2); + obfuscatedCode = obfuscationResult.getObfuscatedCode(); - const firstMatch: string | undefined = firstMatchArray ? firstMatchArray[2] : undefined; - const secondMatch: string | undefined = secondMatchArray ? secondMatchArray[2] : undefined; + firstMatchArray = obfuscatedCode.match(controlFlowStorageCallRegExp1); + secondMatchArray = obfuscatedCode.match(controlFlowStorageCallRegExp2); - assert.match(obfuscatedCode, controlFlowStorageCallRegExp1); - assert.match(obfuscatedCode, controlFlowStorageCallRegExp2); + if (!firstMatchArray || !secondMatchArray) { + matchErrorsCount++; + + continue; + } + + firstMatch = firstMatchArray ? firstMatchArray[1] : undefined; + secondMatch = secondMatchArray ? secondMatchArray[1] : undefined; if (firstMatch === secondMatch) { equalsValue++; } } - assert.closeTo(equalsValue / samplesCount, expectedValue, delta); + usingExistingIdentifierChance = equalsValue / samplesCount; + }); + + it('should replace call expression node by call to control flow storage node', () => { + assert.equal(matchErrorsCount, expectedMatchErrorsCount); + }); + + it('should use existing identifier for control flow storage with expected chance', () => { + assert.closeTo(usingExistingIdentifierChance, expectedChance, delta); }); }); - describe('variant #3 - callee - member expression', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/input-3.js'), - { - ...NO_CUSTOM_NODES_PRESET, - controlFlowFlattening: true, - controlFlowFlatteningThreshold: 1 - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); - const controlFlowStorageCallRegExp: RegExp = /var *_0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\['sum'\]\(0x1, *0x2\);/; + describe('variant #3 - call expression callee is member expression node', () => { + const regExp: RegExp = /var *_0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\['sum'\]\(0x1, *0x2\);/; - it('shouldn\'t replace call expression node by call to control flow storage node if call expression callee is member expression node', () => { - assert.match(obfuscatedCode, controlFlowStorageCallRegExp); + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/input-3.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + controlFlowFlattening: true, + controlFlowFlatteningThreshold: 1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('shouldn\'t replace call expression node with call to control flow storage node', () => { + assert.match(obfuscatedCode, regExp); }); }); }); diff --git a/test/functional-tests/node-transformers/control-flow-transformers/control-flow-replacers/logical-expression-control-flow-replacer/LogicalExpressionControlFlowReplacer.spec.ts b/test/functional-tests/node-transformers/control-flow-transformers/control-flow-replacers/logical-expression-control-flow-replacer/LogicalExpressionControlFlowReplacer.spec.ts index f81a8658..1c35fbcc 100644 --- a/test/functional-tests/node-transformers/control-flow-transformers/control-flow-replacers/logical-expression-control-flow-replacer/LogicalExpressionControlFlowReplacer.spec.ts +++ b/test/functional-tests/node-transformers/control-flow-transformers/control-flow-replacers/logical-expression-control-flow-replacer/LogicalExpressionControlFlowReplacer.spec.ts @@ -8,95 +8,142 @@ import { readFileAsString } from '../../../../../helpers/readFileAsString'; import { JavaScriptObfuscator } from '../../../../../../src/JavaScriptObfuscator'; -describe('LogicalExpressionControlFlowReplacer', () => { +describe('LogicalExpressionControlFlowReplacer', function () { + this.timeout(100000); + describe('replace (logicalExpressionNode: ESTree.LogicalExpression,parentNode: ESTree.Node,controlFlowStorage: IStorage )', () => { describe('variant #1 - single logical expression', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/input-1.js'), - { - ...NO_CUSTOM_NODES_PRESET, - controlFlowFlattening: true, - controlFlowFlatteningThreshold: 1 - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); const controlFlowStorageCallRegExp: RegExp = /var *_0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\['\w{3}'\]\(!!\[\], *!\[\]\);/; - it('should replace logical expression node by call to control flow storage node', () => { + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/input-1.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + controlFlowFlattening: true, + controlFlowFlatteningThreshold: 1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('should replace logical expression node with call to control flow storage node', () => { assert.match(obfuscatedCode, controlFlowStorageCallRegExp); }); }); describe('variant #2 - multiple logical expressions with threshold = 1', () => { - it('should replace logical expression node by call to control flow storage node', function () { - this.timeout(60000); + const expectedMatchErrorsCount: number = 0; + const expectedChance: number = 0.5; - const samplesCount: number = 1000; - const expectedValue: number = 0.5; - const delta: number = 0.1; + const samplesCount: number = 1000; + const delta: number = 0.1; - let equalsValue: number = 0; + const controlFlowStorageCallRegExp1: RegExp = /var *_0x(?:[a-f0-9]){4,6} *= *(_0x([a-f0-9]){4,6}\['\w{3}'\])\(!!\[\], *!\[\]\);/; + const controlFlowStorageCallRegExp2: RegExp = /var *_0x(?:[a-f0-9]){4,6} *= *(_0x([a-f0-9]){4,6}\['\w{3}'\])\(!\[\], *!!\[\]\);/; + + let matchErrorsCount: number = 0, + usingExistingIdentifierChance: number; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/input-2.js'); + + let obfuscationResult: IObfuscationResult, + obfuscatedCode: string, + firstMatchArray: RegExpMatchArray | null, + secondMatchArray: RegExpMatchArray | null, + firstMatch: string | undefined, + secondMatch: string | undefined, + equalsValue: number = 0; for (let i = 0; i < samplesCount; i++) { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/input-2.js'), + obfuscationResult = JavaScriptObfuscator.obfuscate( + code, { ...NO_CUSTOM_NODES_PRESET, controlFlowFlattening: true, controlFlowFlatteningThreshold: 1 } ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); - const controlFlowStorageCallRegExp1: RegExp = /var *_0x([a-f0-9]){4,6} *= *(_0x([a-f0-9]){4,6}\['\w{3}'\])\(!!\[\], *!\[\]\);/; - const controlFlowStorageCallRegExp2: RegExp = /var *_0x([a-f0-9]){4,6} *= *(_0x([a-f0-9]){4,6}\['\w{3}'\])\(!\[\], *!!\[\]\);/; - const firstMatchArray: RegExpMatchArray | null = obfuscatedCode.match(controlFlowStorageCallRegExp1); - const secondMatchArray: RegExpMatchArray | null = obfuscatedCode.match(controlFlowStorageCallRegExp2); + obfuscatedCode = obfuscationResult.getObfuscatedCode(); - const firstMatch: string | undefined = firstMatchArray ? firstMatchArray[2] : undefined; - const secondMatch: string | undefined = secondMatchArray ? secondMatchArray[2] : undefined; + firstMatchArray = obfuscatedCode.match(controlFlowStorageCallRegExp1); + secondMatchArray = obfuscatedCode.match(controlFlowStorageCallRegExp2); - assert.match(obfuscatedCode, controlFlowStorageCallRegExp1); - assert.match(obfuscatedCode, controlFlowStorageCallRegExp2); + if (!firstMatchArray || !secondMatchArray) { + matchErrorsCount++; + + continue; + } + + firstMatch = firstMatchArray ? firstMatchArray[1] : undefined; + secondMatch = secondMatchArray ? secondMatchArray[1] : undefined; if (firstMatch === secondMatch) { equalsValue++; } } - assert.closeTo(equalsValue / samplesCount, expectedValue, delta); + usingExistingIdentifierChance = equalsValue / samplesCount; + }); + + it('should replace logical expression node by call to control flow storage node', () => { + assert.equal(matchErrorsCount, expectedMatchErrorsCount); + }); + + it('should use existing identifier for control flow storage with expected chance', () => { + assert.closeTo(usingExistingIdentifierChance, expectedChance, delta); }); }); describe('variant #3 - single logical expression with unary expression', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/input-3.js'), - { - ...NO_CUSTOM_NODES_PRESET, - controlFlowFlattening: true, - controlFlowFlatteningThreshold: 1 - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); const controlFlowStorageCallRegExp: RegExp = /var *_0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\['\w{3}'\]\(!_0x([a-f0-9]){4,6}, *!_0x([a-f0-9]){4,6}\);/; - it('should replace logical expression node with unary expression by call to control flow storage node', () => { + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/input-3.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + controlFlowFlattening: true, + controlFlowFlatteningThreshold: 1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('should replace logical unary expression with call to control flow storage node', () => { assert.match(obfuscatedCode, controlFlowStorageCallRegExp); }); }); describe('prohibited nodes variant #1', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/prohibited-nodes.js'), - { - ...NO_CUSTOM_NODES_PRESET, - controlFlowFlattening: true, - controlFlowFlatteningThreshold: .1 - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); const regExp: RegExp = /var *_0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\[_0x([a-f0-9]){4,6}\] *&& *!\[\];/; + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/prohibited-nodes.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + controlFlowFlattening: true, + controlFlowFlatteningThreshold: .1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + it('shouldn\'t replace prohibited expression nodes', () => { assert.match(obfuscatedCode, regExp); }); diff --git a/test/functional-tests/node-transformers/control-flow-transformers/control-flow-replacers/string-litertal-control-flow-replacer/StringLiteralControlFlowReplacer.spec.ts b/test/functional-tests/node-transformers/control-flow-transformers/control-flow-replacers/string-litertal-control-flow-replacer/StringLiteralControlFlowReplacer.spec.ts index 1264afda..a5141986 100644 --- a/test/functional-tests/node-transformers/control-flow-transformers/control-flow-replacers/string-litertal-control-flow-replacer/StringLiteralControlFlowReplacer.spec.ts +++ b/test/functional-tests/node-transformers/control-flow-transformers/control-flow-replacers/string-litertal-control-flow-replacer/StringLiteralControlFlowReplacer.spec.ts @@ -10,23 +10,30 @@ import { JavaScriptObfuscator } from '../../../../../../src/JavaScriptObfuscator describe('StringLiteralControlFlowReplacer', () => { describe('replace (literalNode: ESTree.Literal,parentNode: ESTree.Node,controlFlowStorage: IStorage )', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/input-1.js'), - { - ...NO_CUSTOM_NODES_PRESET, - controlFlowFlattening: true, - controlFlowFlatteningThreshold: 1 - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); const controlFlowStorageStringLiteralRegExp: RegExp = /var *_0x([a-f0-9]){4,6} *= *\{'\w{3}' *: *'test'\};/; const controlFlowStorageCallRegExp: RegExp = /var *_0x([a-f0-9]){4,6} *= *_0x([a-f0-9]){4,6}\['\w{3}'\];/; + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/input-1.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + controlFlowFlattening: true, + controlFlowFlatteningThreshold: 1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + it('should add string literal node as property of control flow storage node', () => { assert.match(obfuscatedCode, controlFlowStorageStringLiteralRegExp); }); - it('should replace string literal node by call to control flow storage node', () => { + it('should replace string literal node with call to control flow storage node', () => { assert.match(obfuscatedCode, controlFlowStorageCallRegExp); }); }); diff --git a/test/functional-tests/node-transformers/control-flow-transformers/function-control-flow-transformer/FunctionControlFlowTransformer.spec.ts b/test/functional-tests/node-transformers/control-flow-transformers/function-control-flow-transformer/FunctionControlFlowTransformer.spec.ts index 4b609f31..06ca86ee 100644 --- a/test/functional-tests/node-transformers/control-flow-transformers/function-control-flow-transformer/FunctionControlFlowTransformer.spec.ts +++ b/test/functional-tests/node-transformers/control-flow-transformers/function-control-flow-transformer/FunctionControlFlowTransformer.spec.ts @@ -8,7 +8,9 @@ import { readFileAsString } from '../../../../helpers/readFileAsString'; import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscator'; -describe('FunctionControlFlowTransformer', () => { +describe('FunctionControlFlowTransformer', function () { + this.timeout(100000); + const variableMatch: string = '_0x([a-f0-9]){4,6}'; const rootControlFlowStorageNodeMatch: string = `` + `var *${variableMatch} *= *\\{` + @@ -27,26 +29,35 @@ describe('FunctionControlFlowTransformer', () => { describe('transformNode (functionNode: ESTree.Function): ESTree.Node', () => { describe('variant #1 - single `control flow storage` node with single item', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/input-1.js'), - { - ...NO_CUSTOM_NODES_PRESET, - controlFlowFlattening: true, - controlFlowFlatteningThreshold: 1 - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); const regexp: RegExp = new RegExp(rootControlFlowStorageNodeMatch); + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/input-1.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + controlFlowFlattening: true, + controlFlowFlatteningThreshold: 1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + it('should add `control flow storage` node to the obfuscated code', () => { assert.match(obfuscatedCode, regexp); }); }); describe('variant #2 - two `control flow storage` nodes: root and inner', () => { + const expectedAppendToScopeThreshold: number = 0.5; + const samplesCount: number = 1000; const delta: number = 0.1; - const expectedValue: number = 0.5; + const regExp1: RegExp = new RegExp( `\\(function\\(\\) *\\{ *${rootControlFlowStorageNodeMatch}`, 'g' @@ -56,43 +67,44 @@ describe('FunctionControlFlowTransformer', () => { 'g' ); - let totalValue: number = 0; + let appendToScopeThreshold: number = 0; - for (let i = 0; i < samplesCount; i++) { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/input-2.js'), - { - ...NO_CUSTOM_NODES_PRESET, - controlFlowFlattening: true, - controlFlowFlatteningThreshold: 1 - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/input-2.js'); - if (regExp1.test(obfuscatedCode)) { - totalValue += obfuscatedCode.match(regExp1)!.length; + let obfuscationResult: IObfuscationResult, + obfuscatedCode: string, + totalValue: number = 0; - if (regExp2.test(obfuscatedCode)) { - totalValue += obfuscatedCode.match(regExp2)!.length; + for (let i = 0; i < samplesCount; i++) { + obfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + controlFlowFlattening: true, + controlFlowFlatteningThreshold: 1 + } + ); + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + + if (regExp1.test(obfuscatedCode)) { + totalValue += obfuscatedCode.match(regExp1)!.length; + + if (regExp2.test(obfuscatedCode)) { + totalValue += obfuscatedCode.match(regExp2)!.length; + } } } - } + + appendToScopeThreshold = (totalValue - samplesCount) / samplesCount; + }); it('should add two `control flow storage` nodes (root and inner) to the obfuscated code in different scopes', () => { - assert.closeTo((totalValue - samplesCount) / samplesCount, expectedValue, delta); + assert.closeTo(appendToScopeThreshold, expectedAppendToScopeThreshold, delta); }); }); describe('variant #3 - single `control flow storage` node with multiple items', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/multiple-items.js'), - { - ...NO_CUSTOM_NODES_PRESET, - controlFlowFlattening: true, - controlFlowFlatteningThreshold: 1 - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); const regexp: RegExp = new RegExp( `var *${variableMatch} *= *\\{` + `'\\w{3}' *: *function *${variableMatch} *\\(${variableMatch}, *${variableMatch}\\) *\\{` + @@ -104,30 +116,55 @@ describe('FunctionControlFlowTransformer', () => { `\\};` ); + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/multiple-items.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + controlFlowFlattening: true, + controlFlowFlatteningThreshold: 1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + it('should add `control flow storage` node with multiple items to the obfuscated code', () => { assert.match(obfuscatedCode, regexp); }); }); - describe('variant #4 - no `control flow storage` node to the root block scope', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/root-block-scope-1.js'), - { - ...NO_CUSTOM_NODES_PRESET, - controlFlowFlattening: true, - controlFlowFlatteningThreshold: 1 - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); + describe('variant #4 - transformed node in the root block scope', () => { + const regExp: RegExp = /^var *test *= *0x1 *\+ *0x2;$/; - it('should\'t add control flow storage node when transformed node in the root block scope', () => { - assert.match(obfuscatedCode, /^var *test *= *0x1 *\+ *0x2;$/); + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/root-block-scope-1.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + controlFlowFlattening: true, + controlFlowFlatteningThreshold: 1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('should\'t add control flow storage node', () => { + assert.match(obfuscatedCode, regExp); }); }); - describe('variant #5 - no `control flow storage` node in the root block scope', () => { - const samplesCount: number = 20; + describe('variant #5 - transformed nodes not in the root block scope', () => { const expectedValue: number = 0; + const samplesCount: number = 20; + const regExp: RegExp = new RegExp( `var *[a-zA-Z]{6} *= *\\{` + `'\\w{3}' *: *function *_0x[0-9] *\\(${variableMatch}, *${variableMatch}\\) *\\{` + @@ -136,13 +173,14 @@ describe('FunctionControlFlowTransformer', () => { `\\};` ); + const code: string = readFileAsString(__dirname + '/fixtures/root-block-scope-2.js'); - it('should\'t add control flow storage node to the root block scope when transformed nodes not in the root block scope', () => { - let totalValue: number = 0; + let totalValue: number = 0; + before(() => { for (let i = 0; i < samplesCount; i++) { const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/root-block-scope-2.js'), + code, { ...NO_CUSTOM_NODES_PRESET, controlFlowFlattening: true, @@ -155,60 +193,86 @@ describe('FunctionControlFlowTransformer', () => { totalValue++; } } + }); + it('should\'t add control flow storage node to the root block scope', () => { assert.equal(totalValue, expectedValue); }); }); - describe('variant #6 - no single `control flow storage` node when threshold is 0', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/zero-threshold.js'), - { - ...NO_CUSTOM_NODES_PRESET, - controlFlowFlattening: true, - controlFlowFlatteningThreshold: 0 - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); - const controlFlowStorageMatch: RegExp = new RegExp(rootControlFlowStorageNodeMatch); + describe('variant #6 - threshold is `0`', () => { const regexp: RegExp = /var *_0x([a-f0-9]){4,6} *= *0x1 *\+ *0x2;/; + const controlFlowStorageRegExp: RegExp = new RegExp(rootControlFlowStorageNodeMatch); - it('shouldn\'t add `control flow storage` node to the obfuscated code when threshold is 0', () => { + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/zero-threshold.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + controlFlowFlattening: true, + controlFlowFlatteningThreshold: 0 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('shouldn\'t add call to control flow storage node to the obfuscated code', () => { assert.match(obfuscatedCode, regexp); - assert.notMatch(obfuscatedCode, controlFlowStorageMatch); + }); + + it('shouldn\'t add `control flow storage` node to the obfuscated code', () => { + assert.notMatch(obfuscatedCode, controlFlowStorageRegExp); }); }); describe('arrow function expression', () => { describe('variant #1 - arrow function expression with body', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/arrow-function-expression-with-body.js'), - { - ...NO_CUSTOM_NODES_PRESET, - controlFlowFlattening: true, - controlFlowFlatteningThreshold: 1 - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); const regexp: RegExp = new RegExp(rootControlFlowStorageNodeMatch); + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/arrow-function-expression-with-body.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + controlFlowFlattening: true, + controlFlowFlatteningThreshold: 1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + it('should add `control flow storage` node to the obfuscated code', () => { assert.match(obfuscatedCode, regexp); }); }); describe('variant #2 - arrow function expression without body', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/arrow-function-expression-without-body.js'), - { - ...NO_CUSTOM_NODES_PRESET, - controlFlowFlattening: true, - controlFlowFlatteningThreshold: 1 - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); const regexp: RegExp = new RegExp(`var *${variableMatch} *= *\\(\\) *=> *0x1 *\\+ *0x2;`); + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/arrow-function-expression-without-body.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + controlFlowFlattening: true, + controlFlowFlatteningThreshold: 1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + it('shouldn\'t add `control flow storage` node to the obfuscated code', () => { assert.match(obfuscatedCode, regexp); }); diff --git a/test/functional-tests/node-transformers/converting-transformers/member-expression-transformer/MemberExpressionTransformer.spec.ts b/test/functional-tests/node-transformers/converting-transformers/member-expression-transformer/MemberExpressionTransformer.spec.ts index 31c118dd..3bd0e027 100644 --- a/test/functional-tests/node-transformers/converting-transformers/member-expression-transformer/MemberExpressionTransformer.spec.ts +++ b/test/functional-tests/node-transformers/converting-transformers/member-expression-transformer/MemberExpressionTransformer.spec.ts @@ -10,56 +10,108 @@ import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscator'; describe('MemberExpressionTransformer', () => { describe('transformation of member expression node with dot notation', () => { - it('should replace member expression dot notation call by square brackets call with unicode literal value', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/dot-notation-call.js'), - { - ...NO_CUSTOM_NODES_PRESET - } - ); + describe('`stringArray` option is disabled', () => { + const regExp: RegExp = /var *test *= *console\['log'\];/; - assert.match(obfuscationResult.getObfuscatedCode(), /var *test *= *console\['log'\];/); + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/dot-notation-call.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('should replace member expression dot notation call with literal value', () => { + assert.match(obfuscatedCode, regExp); + }); }); - it('should replace member expression dot notation call by square brackets call to unicode array', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/dot-notation-call.js'), - { - ...NO_CUSTOM_NODES_PRESET, - stringArray: true, - stringArrayThreshold: 1 - } - ); + describe('`stringArray` option is enabled', () => { + const stringArrayRegExp: RegExp = /var *_0x([a-f0-9]){4} *= *\['log'\];/; + const stringArrayCallRegExp: RegExp = /var *test *= *console\[_0x([a-f0-9]){4}\('0x0'\)\];/; - assert.match(obfuscationResult.getObfuscatedCode(), /var *_0x([a-f0-9]){4} *= *\['log'\];/); - assert.match(obfuscationResult.getObfuscatedCode(), /var *test *= *console\[_0x([a-f0-9]){4}\('0x0'\)\];/); + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/dot-notation-call.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + stringArray: true, + stringArrayThreshold: 1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('should add member expression identifier to string array', () => { + assert.match(obfuscatedCode, stringArrayRegExp); + }); + + it('should replace member expression dot notation call with call to string array', () => { + assert.match(obfuscatedCode, stringArrayCallRegExp); + }); }); }); - describe('transformation of member expression node without dot notation', () => { - it('should replace member expression square brackets call by square brackets call to unicode array', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/square-brackets-call.js'), - { - ...NO_CUSTOM_NODES_PRESET, - stringArray: true, - stringArrayThreshold: 1 - } - ); + describe('transformation of member expression node with square brackets', () => { + describe('variant #1: square brackets literal ', () => { + const stringArrayRegExp: RegExp = /var *_0x([a-f0-9]){4} *= *\['log'\];/; + const stringArrayCallRegExp: RegExp = /var *test *= *console\[_0x([a-f0-9]){4}\('0x0'\)\];/; - assert.match(obfuscationResult.getObfuscatedCode(), /var *_0x([a-f0-9]){4} *= *\['log'\];/); - assert.match(obfuscationResult.getObfuscatedCode(), /var *test *= *console\[_0x([a-f0-9]){4}\('0x0'\)\];/); + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/square-brackets-call.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + stringArray: true, + stringArrayThreshold: 1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('should add member expression square brackets literal to string array', () => { + assert.match(obfuscatedCode, stringArrayRegExp); + }); + + it('should replace member expression square brackets identifier with call to string array', () => { + assert.match(obfuscatedCode, stringArrayCallRegExp); + }); }); - it('should ignore square brackets call with identifier value', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/square-brackets-with-identifier-call.js'), - { - ...NO_CUSTOM_NODES_PRESET - } - ); + describe('variant #2: square brackets identifier', () => { + const regExp: RegExp = /var *test *= *console\[identifier\];/; - assert.match(obfuscationResult.getObfuscatedCode(), /var *test *= *console\[identifier\];/); + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/square-brackets-with-identifier-call.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('should ignore square brackets call with identifier value', () => { + assert.match(obfuscatedCode, regExp); + }); }); }); }); diff --git a/test/functional-tests/node-transformers/converting-transformers/method-definition-transformer/MethodDefinitionTransformer.spec.ts b/test/functional-tests/node-transformers/converting-transformers/method-definition-transformer/MethodDefinitionTransformer.spec.ts index be6d0028..728eb5e4 100644 --- a/test/functional-tests/node-transformers/converting-transformers/method-definition-transformer/MethodDefinitionTransformer.spec.ts +++ b/test/functional-tests/node-transformers/converting-transformers/method-definition-transformer/MethodDefinitionTransformer.spec.ts @@ -9,41 +9,75 @@ import { readFileAsString } from '../../../../helpers/readFileAsString'; import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscator'; describe('MethodDefinitionTransformer', () => { - let code: string = readFileAsString(__dirname + '/fixtures/input.js'); + const code: string = readFileAsString(__dirname + '/fixtures/input.js'); - it('should replace method definition node `key` property with unicode value', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - code, - { - ...NO_CUSTOM_NODES_PRESET - } - ); + describe('variant #1: default behaviour', () => { + const regExp: RegExp = /\['bar'\]\(\)\{\}/; - assert.match(obfuscationResult.getObfuscatedCode(), /\['bar'\]\(\)\{\}/); + let obfuscatedCode: string; + + before(() => { + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('should replace method definition node `key` property with square brackets literal', () => { + assert.match(obfuscatedCode, regExp); + }); }); - it('should replace method definition node `key` property with unicode array call', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - code, - { - ...NO_CUSTOM_NODES_PRESET, - stringArray: true, - stringArrayThreshold: 1 - } - ); + describe('variant #2: `stringArray` option is enabled', () => { + const stringArrayRegExp: RegExp = /var *_0x([a-f0-9]){4} *= *\['bar'\];/; + const stringArrayCallRegExp: RegExp = /\[_0x([a-f0-9]){4}\('0x0'\)\]\(\)\{\}/; - assert.match(obfuscationResult.getObfuscatedCode(), /var *_0x([a-f0-9]){4} *= *\['bar'\];/); - assert.match(obfuscationResult.getObfuscatedCode(), /\[_0x([a-f0-9]){4}\('0x0'\)\]\(\)\{\}/); + let obfuscatedCode: string; + + before(() => { + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + stringArray: true, + stringArrayThreshold: 1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('should add method definition node `key` property to string array', () => { + assert.match(obfuscatedCode, stringArrayRegExp); + }); + + it('should replace method definition node `key` property with call to string array', () => { + assert.match(obfuscatedCode, stringArrayCallRegExp); + }); }); - it('should not transform method definition node with `constructor` key', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - code, - { - ...NO_CUSTOM_NODES_PRESET - } - ); + describe('variant #3: `constructor` key', () => { + const regExp: RegExp = /constructor\(\)\{\}/; - assert.match(obfuscationResult.getObfuscatedCode(), /constructor\(\)\{\}/); + let obfuscatedCode: string; + + before(() => { + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('shouldn\'t transform method definition node with `constructor` key', () => { + assert.match(obfuscatedCode, regExp); + }); }); }); diff --git a/test/functional-tests/node-transformers/converting-transformers/template-literal-transformer/TemplateLiteralTransformer.spec.ts b/test/functional-tests/node-transformers/converting-transformers/template-literal-transformer/TemplateLiteralTransformer.spec.ts index 27b33d90..23fefe28 100644 --- a/test/functional-tests/node-transformers/converting-transformers/template-literal-transformer/TemplateLiteralTransformer.spec.ts +++ b/test/functional-tests/node-transformers/converting-transformers/template-literal-transformer/TemplateLiteralTransformer.spec.ts @@ -10,57 +10,61 @@ import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscator'; describe('TemplateLiteralTransformer', () => { describe('variant #1: simple template literal', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/simple-input.js'), - { - ...NO_CUSTOM_NODES_PRESET, - unicodeEscapeSequence: false - } - ); - it('should transform es6 template literal to es5', () => { + const code: string = readFileAsString(__dirname + '/fixtures/simple-input.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + unicodeEscapeSequence: false + } + ); + assert.match(obfuscationResult.getObfuscatedCode(), /^var *test *= *'abc\\x20' *\+ *foo;$/); }); }); describe('variant #1: simple template literal with expression only', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/expression-only.js'), - { - ...NO_CUSTOM_NODES_PRESET, - unicodeEscapeSequence: false - } - ); - it('should transform es6 template literal to es5 and add empty literal node before expression node', () => { + const code: string = readFileAsString(__dirname + '/fixtures/expression-only.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + unicodeEscapeSequence: false + } + ); + assert.match(obfuscationResult.getObfuscatedCode(), /^var *test *= *'' *\+ *foo;$/); }); }); describe('variant #3: literal node inside expression', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/literal-inside-expression.js'), - { - ...NO_CUSTOM_NODES_PRESET, - unicodeEscapeSequence: false - } - ); - it('should transform es6 template literal to es5', () => { + const code: string = readFileAsString(__dirname + '/fixtures/literal-inside-expression.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + unicodeEscapeSequence: false + } + ); + assert.match(obfuscationResult.getObfuscatedCode(), /^var *test *= *'abc';$/); }); }); describe('variant #4: multiple expressions', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/multiple-expressions.js'), - { - ...NO_CUSTOM_NODES_PRESET, - unicodeEscapeSequence: false - } - ); - it('should transform es6 template literal to es5', () => { + const code: string = readFileAsString(__dirname + '/fixtures/multiple-expressions.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + unicodeEscapeSequence: false + } + ); + assert.match(obfuscationResult.getObfuscatedCode(), /^var *test *= *0x1 *\+ *0x1 *\+ *'\\x20abc\\x20' *\+ *\(0x1 *\+ *0x1\);$/); }); }); diff --git a/test/functional-tests/node-transformers/dead-code-injection-transformers/DeadCodeInjectionTransformer.spec.ts b/test/functional-tests/node-transformers/dead-code-injection-transformers/DeadCodeInjectionTransformer.spec.ts index d6cd8b04..de13f87e 100644 --- a/test/functional-tests/node-transformers/dead-code-injection-transformers/DeadCodeInjectionTransformer.spec.ts +++ b/test/functional-tests/node-transformers/dead-code-injection-transformers/DeadCodeInjectionTransformer.spec.ts @@ -12,130 +12,176 @@ describe('DeadCodeInjectionTransformer', () => { const variableMatch: string = '_0x([a-f0-9]){4,6}'; const hexMatch: string = '0x[a-f0-9]'; - describe('transformNode (programNode: ESTree.Program, parentNode: ESTree.Node): ESTree.Node', () => { + describe('transformNode (programNode: ESTree.Program, parentNode: ESTree.Node): ESTree.Node', function () { + this.timeout(100000); + describe('variant #1 - 5 simple block statements', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/input-1.js'), - { - ...NO_CUSTOM_NODES_PRESET, - deadCodeInjection: true, - deadCodeInjectionThreshold: 1, - stringArray: true, - stringArrayThreshold: 1 - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); - const deadCodeMatch: string = `` + + const regExp: RegExp = new RegExp( `if *\\(${variableMatch}\\('${hexMatch}'\\) *[=|!]== *${variableMatch}\\('${hexMatch}'\\)\\) *\\{`+ `console\\[${variableMatch}\\('${hexMatch}'\\)\\]\\(${variableMatch}\\('${hexMatch}'\\)\\);` + `\\} *else *\\{`+ `console\\[${variableMatch}\\('${hexMatch}'\\)\\]\\(${variableMatch}\\('${hexMatch}'\\)\\);` + - `\\}` + - ``; - const regexp: RegExp = new RegExp(deadCodeMatch, 'g'); - const matches: RegExpMatchArray = obfuscatedCode.match(regexp); + `\\}`, + 'g' + ); + const expectedMatchesLength: number = 5; + + let matchesLength: number = 0; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/input-1.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + deadCodeInjection: true, + deadCodeInjectionThreshold: 1, + stringArray: true, + stringArrayThreshold: 1 + } + ); + const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); + const matches: RegExpMatchArray = obfuscatedCode.match(regExp); + + if (matches) { + matchesLength = matches.length; + } + }); it('should replace block statements with condition with original block statements and dead code', () => { - assert.isNotNull(matches); - assert.equal(matches.length, 5); + assert.equal(matchesLength, expectedMatchesLength); }); }); - describe('variant #2 - 4 simple block statements', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/block-statements-min-count.js'), - { - ...NO_CUSTOM_NODES_PRESET, - deadCodeInjection: true, - deadCodeInjectionThreshold: 1, - stringArray: true, - stringArrayThreshold: 1 - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); - const codeMatch: string = `` + + describe('variant #2 - block statements count is less than `5`', () => { + const regexp: RegExp = new RegExp( `var *${variableMatch} *= *function *\\(\\) *\\{` + `console\\[${variableMatch}\\('${hexMatch}'\\)\\]\\(${variableMatch}\\('${hexMatch}'\\)\\);` + - `\\};` + - ``; - const regexp: RegExp = new RegExp(codeMatch, 'g'); - const matches: RegExpMatchArray = obfuscatedCode.match(regexp); + `\\};`, + 'g' + ); + const expectedMatchesLength: number = 4; - it('shouldn\'t add dead code if block statements count is less than 5', () => { - assert.isNotNull(matches); - assert.equal(matches.length, 4); + let matchesLength: number = 0; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/block-statements-min-count.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + deadCodeInjection: true, + deadCodeInjectionThreshold: 1, + stringArray: true, + stringArrayThreshold: 1 + } + ); + const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); + const matches: RegExpMatchArray = obfuscatedCode.match(regexp); + + if (matches) { + matchesLength = matches.length; + } + }); + + it('shouldn\'t add dead code', () => { + assert.equal(matchesLength, expectedMatchesLength); }); }); describe('variant #3 - deadCodeInjectionThreshold: 0', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/input-1.js'), - { - ...NO_CUSTOM_NODES_PRESET, - deadCodeInjection: true, - deadCodeInjectionThreshold: 0, - stringArray: true, - stringArrayThreshold: 1 - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); - const codeMatch: string = `` + + const regexp: RegExp = new RegExp( `var *${variableMatch} *= *function *\\(\\) *\\{` + `console\\[${variableMatch}\\('${hexMatch}'\\)\\]\\(${variableMatch}\\('${hexMatch}'\\)\\);` + - `\\};` + - ``; - const regexp: RegExp = new RegExp(codeMatch, 'g'); - const matches: RegExpMatchArray = obfuscatedCode.match(regexp); + `\\};`, + 'g' + ); + const expectedMatchesLength: number = 5; - it('shouldn\'t add dead code if `deadCodeInjectionThreshold` option value is `0`', () => { - assert.isNotNull(matches); - assert.equal(matches.length, 5); + let matchesLength: number = 0; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/input-1.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + deadCodeInjection: true, + deadCodeInjectionThreshold: 0, + stringArray: true, + stringArrayThreshold: 1 + } + ); + const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); + const matches: RegExpMatchArray = obfuscatedCode.match(regexp); + + if (matches) { + matchesLength = matches.length; + } + }); + + it('shouldn\'t add dead code', () => { + assert.equal(matchesLength, expectedMatchesLength); }); }); describe('variant #4 - break or continue statement in block statement', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/break-continue-statement.js'), - { - ...NO_CUSTOM_NODES_PRESET, - deadCodeInjection: true, - deadCodeInjectionThreshold: 1, - stringArray: true, - stringArrayThreshold: 1 - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); - - const functionMatch: string = `` + + const functionRegExp: RegExp = new RegExp( `var *${variableMatch} *= *function *\\(\\) *\\{` + `console\\[${variableMatch}\\('${hexMatch}'\\)\\]\\(${variableMatch}\\('${hexMatch}'\\)\\);` + - `\\};` + - ``; - const loopMatch: string = `` + + `\\};`, + 'g' + ); + const loopRegExp: RegExp = new RegExp( `for *\\(var *${variableMatch} *= *${hexMatch}; *${variableMatch} *< *${hexMatch}; *${variableMatch}\\+\\+\\) *\\{` + `(?:continue|break);` + - `\\}` + - ``; + `\\}`, + 'g' + ); + const expectedFunctionMatchesLength: number = 4; + const expectedLoopMatchesLength: number = 2; - const functionRegExp: RegExp = new RegExp(functionMatch, 'g'); - const loopRegExp: RegExp = new RegExp(loopMatch, 'g'); + let functionMatchesLength: number = 0, + loopMatchesLength: number = 0; - const functionMatches: RegExpMatchArray = obfuscatedCode.match(functionRegExp); - const loopMatches: RegExpMatchArray = obfuscatedCode.match(loopRegExp); + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/break-continue-statement.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + deadCodeInjection: true, + deadCodeInjectionThreshold: 1, + stringArray: true, + stringArrayThreshold: 1 + } + ); + const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); + const functionMatches: RegExpMatchArray = obfuscatedCode.match(functionRegExp); + const loopMatches: RegExpMatchArray = obfuscatedCode.match(loopRegExp); - it('shouldn\'t add dead code if block statement contains `continue` or `break` statements', () => { - assert.isNotNull(functionMatches); - assert.isNotNull(loopMatches); + if (functionMatches) { + functionMatchesLength = functionMatches.length; + } - assert.equal(functionMatches.length, 4); - assert.equal(loopMatches.length, 2); + if (loopMatches) { + loopMatchesLength = loopMatches.length; + } + }); + + it('match #1: shouldn\'t add dead code', () => { + assert.equal(functionMatchesLength, expectedFunctionMatchesLength); + }); + + it('match #2: shouldn\'t add dead code', () => { + assert.equal(loopMatchesLength, expectedLoopMatchesLength); }); }); describe('variant #5 - chance of `IfStatement` variant', () => { const samplesCount: number = 1000; const delta: number = 0.1; - const expectedValue: number = 0.25; + const expectedDistribution: number = 0.25; const ifMatch: string = `if *\\(!!\\[\\]\\) *\\{`; const functionMatch: string = `var *${variableMatch} *= *function *\\(\\) *\\{`; @@ -169,45 +215,68 @@ describe('DeadCodeInjectionTransformer', () => { `\\}` + ``; - const regExp1: RegExp = new RegExp(`${ifMatch}${functionMatch}${match1}`); - const regExp2: RegExp = new RegExp(`${ifMatch}${functionMatch}${match2}`); - const regExp3: RegExp = new RegExp(`${ifMatch}${functionMatch}${match3}`); - const regExp4: RegExp = new RegExp(`${ifMatch}${functionMatch}${match4}`); + let distribution1: number = 0, + distribution2: number = 0, + distribution3: number = 0, + distribution4: number = 0; - let count1: number = 0; - let count2: number = 0; - let count3: number = 0; - let count4: number = 0; + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/if-statement-variants-distribution.js'); - for (let i = 0; i < samplesCount; i++) { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/if-statement-variants-distribution.js'), - { - ...NO_CUSTOM_NODES_PRESET, - deadCodeInjection: true, - deadCodeInjectionThreshold: 1, - stringArray: true, - stringArrayThreshold: 1 + const regExp1: RegExp = new RegExp(`${ifMatch}${functionMatch}${match1}`); + const regExp2: RegExp = new RegExp(`${ifMatch}${functionMatch}${match2}`); + const regExp3: RegExp = new RegExp(`${ifMatch}${functionMatch}${match3}`); + const regExp4: RegExp = new RegExp(`${ifMatch}${functionMatch}${match4}`); + + let count1: number = 0; + let count2: number = 0; + let count3: number = 0; + let count4: number = 0; + + for (let i = 0; i < samplesCount; i++) { + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + deadCodeInjection: true, + deadCodeInjectionThreshold: 1, + stringArray: true, + stringArrayThreshold: 1 + } + ); + const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); + + if (regExp1.test(obfuscatedCode)) { + count1++; + } else if (regExp2.test(obfuscatedCode)) { + count2++; + } else if (regExp3.test(obfuscatedCode)) { + count3++; + } else if (regExp4.test(obfuscatedCode)) { + count4++; } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); - - if (regExp1.test(obfuscatedCode)) { - count1++; - } else if (regExp2.test(obfuscatedCode)) { - count2++; - } else if (regExp3.test(obfuscatedCode)) { - count3++; - } else if (regExp4.test(obfuscatedCode)) { - count4++; } - } - it('each of four `IfStatement` variant should have distribution close to `0.25`', () => { - assert.closeTo(count1 / samplesCount, expectedValue, delta); - assert.closeTo(count2 / samplesCount, expectedValue, delta); - assert.closeTo(count3 / samplesCount, expectedValue, delta); - assert.closeTo(count4 / samplesCount, expectedValue, delta); + distribution1 = count1 / samplesCount; + distribution2 = count2 / samplesCount; + distribution3 = count3 / samplesCount; + distribution4 = count4 / samplesCount; + }); + + it('variant #1: `IfStatement` variant should have distribution close to `0.25`', () => { + assert.closeTo(distribution1, expectedDistribution, delta); + }); + + it('variant #2: `IfStatement` variant should have distribution close to `0.25`', () => { + assert.closeTo(distribution2, expectedDistribution, delta); + }); + + it('variant #3: `IfStatement` variant should have distribution close to `0.25`', () => { + assert.closeTo(distribution3, expectedDistribution, delta); + }); + + it('variant #4: `IfStatement` variant should have distribution close to `0.25`', () => { + assert.closeTo(distribution4, expectedDistribution, delta); }); }); }); diff --git a/test/functional-tests/node-transformers/obfuscating-transformers/catch-clause-transformer/CatchClauseTransformer.spec.ts b/test/functional-tests/node-transformers/obfuscating-transformers/catch-clause-transformer/CatchClauseTransformer.spec.ts index 827efe9f..85b08401 100644 --- a/test/functional-tests/node-transformers/obfuscating-transformers/catch-clause-transformer/CatchClauseTransformer.spec.ts +++ b/test/functional-tests/node-transformers/obfuscating-transformers/catch-clause-transformer/CatchClauseTransformer.spec.ts @@ -9,49 +9,67 @@ import { readFileAsString } from '../../../../helpers/readFileAsString'; import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscator'; describe('CatchClauseTransformer', () => { + let obfuscatedCode: string; + describe('changeControlFlow (catchClauseNode: ESTree.CatchClause): void', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/input.js'), - { - ...NO_CUSTOM_NODES_PRESET - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); const paramNameRegExp: RegExp = /catch *\((_0x([a-f0-9]){4,6})\) *\{/; const bodyParamNameRegExp: RegExp = /console\['log'\]\((_0x([a-f0-9]){4,6})\);/; - it('should transform catch clause node', () => { + let firstMatch: string | undefined, + secondMatch: string | undefined; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/input.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + + const firstMatchArray: RegExpMatchArray | null = obfuscatedCode.match(paramNameRegExp); + const secondMatchArray: RegExpMatchArray | null = obfuscatedCode.match(bodyParamNameRegExp); + + firstMatch = firstMatchArray ? firstMatchArray[1] : undefined; + secondMatch = secondMatchArray ? secondMatchArray[1] : undefined; + }); + + it('match #1: should transform catch clause node', () => { assert.match(obfuscatedCode, paramNameRegExp); + }); + + it('match #2: should transform catch clause node', () => { assert.match(obfuscatedCode, bodyParamNameRegExp); }); it('catch clause arguments param name and param name in body should be same', () => { - const firstMatchArray: RegExpMatchArray | null = obfuscatedCode.match(paramNameRegExp); - const secondMatchArray: RegExpMatchArray | null = obfuscatedCode.match(bodyParamNameRegExp); - - const firstMatch: string | undefined = firstMatchArray ? firstMatchArray[1] : undefined; - const secondMatch: string | undefined = secondMatchArray ? secondMatchArray[1] : undefined; - - assert.isOk(firstMatch); - assert.isOk(secondMatch); assert.equal(firstMatch, secondMatch); }); }); describe('object pattern as parameter', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/object-pattern-as-parameter.js'), - { - ...NO_CUSTOM_NODES_PRESET - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); + const functionParameterMatch: RegExp = /\} *catch *\(\{ *name *\}\) *\{/; + const functionBodyMatch: RegExp = /return *name;/; - it('shouldn\'t transform function parameter object pattern identifier', () => { - const functionParameterMatch: RegExp = /\} *catch *\(\{ *name *\}\) *\{/; - const functionBodyMatch: RegExp = /return *name;/; + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/object-pattern-as-parameter.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET + } + ); + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('match #1: shouldn\'t transform function parameter object pattern identifier', () => { assert.match(obfuscatedCode, functionParameterMatch); + }); + + it('match #2: shouldn\'t transform function parameter object pattern identifier', () => { assert.match(obfuscatedCode, functionBodyMatch); }); }); diff --git a/test/functional-tests/node-transformers/obfuscating-transformers/function-declaration-transformer/FunctionDeclarationTransformer.spec.ts b/test/functional-tests/node-transformers/obfuscating-transformers/function-declaration-transformer/FunctionDeclarationTransformer.spec.ts index f7bbcd1d..4ba82397 100644 --- a/test/functional-tests/node-transformers/obfuscating-transformers/function-declaration-transformer/FunctionDeclarationTransformer.spec.ts +++ b/test/functional-tests/node-transformers/obfuscating-transformers/function-declaration-transformer/FunctionDeclarationTransformer.spec.ts @@ -10,36 +10,62 @@ import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscator'; describe('FunctionDeclarationTransformer', () => { describe('transformation of `functionDeclaration` node names', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/input.js'), - { - ...NO_CUSTOM_NODES_PRESET - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); + let obfuscatedCode: string; - it('shouldn\'t transform function name if `functionDeclaration` parent block scope is a `ProgramNode`', () => { - const functionNameIdentifierMatch: RegExpMatchArray|null = obfuscatedCode - .match(/function *foo *\(\) *\{/); - const functionCallIdentifierMatch: RegExpMatchArray|null = obfuscatedCode - .match(/foo *\( *\);/); + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/input.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET + } + ); - const functionParamIdentifierName: string = (functionNameIdentifierMatch)[1]; - const functionBodyIdentifierName: string = (functionCallIdentifierMatch)[1]; - - assert.equal(functionParamIdentifierName, functionBodyIdentifierName); + obfuscatedCode = obfuscationResult.getObfuscatedCode(); }); - it('should transform function name if `functionDeclaration` parent block scope is not a `ProgramNode`', () => { - const functionNameIdentifierMatch: RegExpMatchArray|null = obfuscatedCode - .match(/function *_0x[a-f0-9]{4,6} *\(\) *\{/); - const functionCallIdentifierMatch: RegExpMatchArray|null = obfuscatedCode - .match(/_0x[a-f0-9]{4,6} *\( *\);/); + describe('variant #1: `functionDeclaration` parent block scope is not a `ProgramNode`', () => { + const functionNameIdentifierRegExp: RegExp = /function *_0x[a-f0-9]{4,6} *\(\) *\{/; + const functionCallIdentifierRegExp: RegExp = /_0x[a-f0-9]{4,6} *\( *\);/; - const functionParamIdentifierName: string = (functionNameIdentifierMatch)[1]; - const functionBodyIdentifierName: string = (functionCallIdentifierMatch)[1]; + let functionParamIdentifierName: string, + functionBodyIdentifierName: string; - assert.equal(functionParamIdentifierName, functionBodyIdentifierName); + before(() => { + const functionNameIdentifierMatch: RegExpMatchArray|null = obfuscatedCode + .match(functionNameIdentifierRegExp); + const functionCallIdentifierMatch: RegExpMatchArray|null = obfuscatedCode + .match(functionCallIdentifierRegExp); + + functionParamIdentifierName = (functionNameIdentifierMatch)[1]; + functionBodyIdentifierName = (functionCallIdentifierMatch)[1]; + }); + + it('should transform function name', () => { + assert.equal(functionParamIdentifierName, functionBodyIdentifierName); + }); + }); + + describe('variant #2: `functionDeclaration` parent block scope is a `ProgramNode`', () => { + const functionNameIdentifierRegExp: RegExp = /function *foo *\(\) *\{/; + const functionCallIdentifierRegExp: RegExp = /foo *\( *\);/; + + let functionParamIdentifierName: string, + functionBodyIdentifierName: string; + + before(() => { + const functionNameIdentifierMatch: RegExpMatchArray|null = obfuscatedCode + .match(functionNameIdentifierRegExp); + const functionCallIdentifierMatch: RegExpMatchArray|null = obfuscatedCode + .match(functionCallIdentifierRegExp); + + functionParamIdentifierName = (functionNameIdentifierMatch)[1]; + functionBodyIdentifierName = (functionCallIdentifierMatch)[1]; + }); + + it('shouldn\'t transform function name', () => { + assert.equal(functionParamIdentifierName, functionBodyIdentifierName); + }); }); }); }); diff --git a/test/functional-tests/node-transformers/obfuscating-transformers/function-transformer/FunctionTransformer.spec.ts b/test/functional-tests/node-transformers/obfuscating-transformers/function-transformer/FunctionTransformer.spec.ts index 77383098..857dc7c0 100644 --- a/test/functional-tests/node-transformers/obfuscating-transformers/function-transformer/FunctionTransformer.spec.ts +++ b/test/functional-tests/node-transformers/obfuscating-transformers/function-transformer/FunctionTransformer.spec.ts @@ -10,91 +10,136 @@ import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscator'; describe('FunctionTransformer', () => { describe('identifiers transformation inside `FunctionDeclaration` and `FunctionExpression` node body', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/input.js'), - { - ...NO_CUSTOM_NODES_PRESET - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); + const functionParamIdentifierRegExp: RegExp = /var _0x[a-f0-9]{4,6} *= *function *\((_0x[a-f0-9]{4,6})\) *\{/; + const functionBodyIdentifierRegExp: RegExp = /console\['log'\]\((_0x[a-f0-9]{4,6})\)/; + const variableRegExp: RegExp = /variable *= *0x6;/; + + let obfuscatedCode: string, + functionParamIdentifierName: string, + functionBodyIdentifierName: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/input.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); - it('should correct transform both function parameter identifier and function body identifier with same name', () => { const functionParamIdentifierMatch: RegExpMatchArray|null = obfuscatedCode - .match(/var _0x[a-f0-9]{4,6} *= *function *\((_0x[a-f0-9]{4,6})\) *\{/); + .match(functionParamIdentifierRegExp); const functionBodyIdentifierMatch: RegExpMatchArray|null = obfuscatedCode - .match(/console\['log'\]\((_0x[a-f0-9]{4,6})\)/); + .match(functionBodyIdentifierRegExp); - const functionParamIdentifierName: string = (functionParamIdentifierMatch)[1]; - const functionBodyIdentifierName: string = (functionBodyIdentifierMatch)[1]; + functionParamIdentifierName = (functionParamIdentifierMatch)[1]; + functionBodyIdentifierName = (functionBodyIdentifierMatch)[1]; + }); + it('should correctly transform both function parameter identifier and function body identifier with same name', () => { assert.equal(functionParamIdentifierName, functionBodyIdentifierName); }); it('shouldn\'t transform other variables in function body', () => { - assert.equal(/variable *= *0x6;/.test(obfuscatedCode), true); + assert.match(obfuscatedCode, variableRegExp); }); }); describe('object pattern as parameter', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/object-pattern-as-parameter.js'), - { - ...NO_CUSTOM_NODES_PRESET - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); + const functionParameterRegExp: RegExp = /function *\(\{ *bar *\}\) *\{/; + const functionBodyRegExp: RegExp = /return *bar;/; - it('shouldn\'t transform function parameter object pattern identifier', () => { - const functionParameterMatch: RegExp = /function *\(\{ *bar *\}\) *\{/; - const functionBodyMatch: RegExp = /return *bar;/; + let obfuscatedCode: string; - assert.match(obfuscatedCode, functionParameterMatch); - assert.match(obfuscatedCode, functionBodyMatch); + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/object-pattern-as-parameter.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('match #1: shouldn\'t transform function parameter object pattern identifier', () => { + assert.match(obfuscatedCode, functionParameterRegExp); + }); + + it('match #2: shouldn\'t transform function parameter object pattern identifier', () => { + assert.match(obfuscatedCode, functionBodyRegExp); }); }); describe('assignment pattern as parameter', () => { - describe('literal as right value', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/assignment-pattern-as-parameter-1.js'), - { - ...NO_CUSTOM_NODES_PRESET - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); + describe('variant #1: literal as right value', () => { + const functionParameterRegExp: RegExp = /function *\(_0x[a-f0-9]{4,6} *= *0x1\) *\{/; + const functionBodyRegExp: RegExp = /return *_0x[a-f0-9]{4,6};/; - it('should transform function parameter assignment pattern identifier', () => { - const functionParameterMatch: RegExp = /function *\(_0x[a-f0-9]{4,6} *= *0x1\) *\{/; - const functionBodyMatch: RegExp = /return *_0x[a-f0-9]{4,6};/; + let obfuscatedCode: string; - assert.match(obfuscatedCode, functionParameterMatch); - assert.match(obfuscatedCode, functionBodyMatch); + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/assignment-pattern-as-parameter-1.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('match #1: should transform function parameter assignment pattern identifier', () => { + assert.match(obfuscatedCode, functionParameterRegExp); + }); + + it('match #2: should transform function parameter assignment pattern identifier', () => { + assert.match(obfuscatedCode, functionBodyRegExp); }); }); - describe('identifier as right value', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/assignment-pattern-as-parameter-2.js'), - { - ...NO_CUSTOM_NODES_PRESET - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); + describe('variant #2: identifier as right value', () => { + const variableDeclarationRegExp: RegExp = /var *(_0x[a-f0-9]{4,6}) *= *0x1;/; + const functionParameterRegExp: RegExp = /function *\((_0x[a-f0-9]{4,6}) *= *(_0x[a-f0-9]{4,6})\) *\{/; + const functionBodyRegExp: RegExp = /return *(_0x[a-f0-9]{4,6});/; - const variableDeclarationMatch: RegExp = /var *(_0x[a-f0-9]{4,6}) *= *0x1;/; - const functionParameterMatch: RegExp = /function *\((_0x[a-f0-9]{4,6}) *= *(_0x[a-f0-9]{4,6})\) *\{/; - const functionBodyMatch: RegExp = /return *(_0x[a-f0-9]{4,6});/; + let obfuscatedCode: string, + variableDeclarationIdentifierName: string, + functionParameterIdentifierName: string, + functionDefaultParameterIdentifierName: string, + functionBodyIdentifierName: string; - const variableDeclarationIdentifierName: string = obfuscatedCode.match(variableDeclarationMatch)![1]; - const functionParameterIdentifierName: string = obfuscatedCode.match(functionParameterMatch)![1]; - const functionDefaultParameterIdentifierName: string = obfuscatedCode.match(functionParameterMatch)![2]; + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/assignment-pattern-as-parameter-2.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET + } + ); - const functionBodyIdentifierName: string = obfuscatedCode.match(functionBodyMatch)![1]; + obfuscatedCode = obfuscationResult.getObfuscatedCode(); - it('should transform function parameter assignment pattern identifier', () => { - assert.match(obfuscatedCode, variableDeclarationMatch); - assert.match(obfuscatedCode, functionParameterMatch); - assert.match(obfuscatedCode, functionBodyMatch); + variableDeclarationIdentifierName = obfuscatedCode.match(variableDeclarationRegExp)![1]; + functionParameterIdentifierName = obfuscatedCode.match(functionParameterRegExp)![1]; + functionDefaultParameterIdentifierName = obfuscatedCode.match(functionParameterRegExp)![2]; + functionBodyIdentifierName = obfuscatedCode.match(functionBodyRegExp)![1]; + }); + + it('match #1: should transform function parameter assignment pattern identifier', () => { + assert.match(obfuscatedCode, variableDeclarationRegExp); + }); + + it('match #2: should transform function parameter assignment pattern identifier', () => { + assert.match(obfuscatedCode, functionParameterRegExp); + }); + + it('match #3: should transform function parameter assignment pattern identifier', () => { + assert.match(obfuscatedCode, functionBodyRegExp); }); it('should keep same names for identifier in variable declaration and default value identifier of function parameter', () => { @@ -106,36 +151,60 @@ describe('FunctionTransformer', () => { }); }); - describe('identifier as right value', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/assignment-pattern-as-parameter-3.js'), - { - ...NO_CUSTOM_NODES_PRESET - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); + describe('variant #3: identifier as right value', () => { + const variableDeclarationRegExp: RegExp = /var *(_0x[a-f0-9]{4,6}) *= *0x1;/; + const functionParameterRegExp: RegExp = /function *\((_0x[a-f0-9]{4,6}), *(_0x[a-f0-9]{4,6}) *= *(_0x[a-f0-9]{4,6})\) *\{/; + const functionBodyRegExp: RegExp = /return *(_0x[a-f0-9]{4,6}) *\+ *(_0x[a-f0-9]{4,6});/; - const variableDeclarationMatch: RegExp = /var *(_0x[a-f0-9]{4,6}) *= *0x1;/; - const functionParameterMatch: RegExp = /function *\((_0x[a-f0-9]{4,6}), *(_0x[a-f0-9]{4,6}) *= *(_0x[a-f0-9]{4,6})\) *\{/; - const functionBodyMatch: RegExp = /return *(_0x[a-f0-9]{4,6}) *\+ *(_0x[a-f0-9]{4,6});/; + let obfuscatedCode: string, + variableDeclarationIdentifierName: string, + functionParameterIdentifierName: string, + functionDefaultParameterIdentifierName1: string, + functionDefaultParameterIdentifierName2: string, + functionBodyIdentifierName1: string, + functionBodyIdentifierName2: string; - const variableDeclarationIdentifierName: string = obfuscatedCode.match(variableDeclarationMatch)![1]; - const functionParameterIdentifierName: string = obfuscatedCode.match(functionParameterMatch)![1]; - const functionDefaultParameterIdentifierName1: string = obfuscatedCode.match(functionParameterMatch)![2]; - const functionDefaultParameterIdentifierName2: string = obfuscatedCode.match(functionParameterMatch)![3]; + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/assignment-pattern-as-parameter-3.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET + } + ); - const functionBodyIdentifierName1: string = obfuscatedCode.match(functionBodyMatch)![1]; - const functionBodyIdentifierName2: string = obfuscatedCode.match(functionBodyMatch)![2]; + obfuscatedCode = obfuscationResult.getObfuscatedCode(); - it('should transform function parameter assignment pattern identifier', () => { - assert.match(obfuscatedCode, variableDeclarationMatch); - assert.match(obfuscatedCode, functionParameterMatch); - assert.match(obfuscatedCode, functionBodyMatch); + variableDeclarationIdentifierName = obfuscatedCode.match(variableDeclarationRegExp)![1]; + functionParameterIdentifierName = obfuscatedCode.match(functionParameterRegExp)![1]; + functionDefaultParameterIdentifierName1 = obfuscatedCode.match(functionParameterRegExp)![2]; + functionDefaultParameterIdentifierName2 = obfuscatedCode.match(functionParameterRegExp)![3]; + + functionBodyIdentifierName1 = obfuscatedCode.match(functionBodyRegExp)![1]; + functionBodyIdentifierName2 = obfuscatedCode.match(functionBodyRegExp)![2]; }); - it('shouldn\'t keep same names variable declaration identifier and function parameters identifiers', () => { + it('match #1: should transform function parameter assignment pattern identifier', () => { + assert.match(obfuscatedCode, variableDeclarationRegExp); + }); + + it('match #2: should transform function parameter assignment pattern identifier', () => { + assert.match(obfuscatedCode, functionParameterRegExp); + }); + + it('match #3: should transform function parameter assignment pattern identifier', () => { + assert.match(obfuscatedCode, functionBodyRegExp); + }); + + it('equal #1: shouldn\'t keep same names variable declaration identifier and function parameters identifiers', () => { assert.notEqual(variableDeclarationIdentifierName, functionParameterIdentifierName); + }); + + it('equal #2: shouldn\'t keep same names variable declaration identifier and function parameters identifiers', () => { assert.notEqual(variableDeclarationIdentifierName, functionDefaultParameterIdentifierName1); + }); + + it('equal #3: shouldn\'t keep same names variable declaration identifier and function parameters identifiers', () => { assert.notEqual(variableDeclarationIdentifierName, functionDefaultParameterIdentifierName2); }); @@ -143,32 +212,46 @@ describe('FunctionTransformer', () => { assert.equal(functionParameterIdentifierName, functionDefaultParameterIdentifierName2); }); - it('should keep same names for identifiers in function params and function body', () => { + it('equal #1: should keep same names for identifiers in function params and function body', () => { assert.equal(functionParameterIdentifierName, functionBodyIdentifierName1); + }); + + it('equal #2: should keep same names for identifiers in function params and function body', () => { assert.equal(functionDefaultParameterIdentifierName1, functionBodyIdentifierName2); }); }); }); describe('array pattern as parameter', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/array-pattern-as-parameter.js'), - { - ...NO_CUSTOM_NODES_PRESET - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); + const functionParameterRegExp: RegExp = /function *\(\[(_0x[a-f0-9]{4,6}), *(_0x[a-f0-9]{4,6})\]\) *\{/; + const functionBodyRegExp: RegExp = /return *(_0x[a-f0-9]{4,6}) *\+ *(_0x[a-f0-9]{4,6});/; - const functionParameterMatch: RegExp = /function *\(\[(_0x[a-f0-9]{4,6}), *(_0x[a-f0-9]{4,6})\]\) *\{/; - const functionBodyMatch: RegExp = /return *(_0x[a-f0-9]{4,6}) *\+ *(_0x[a-f0-9]{4,6});/; + let arrayPatternIdentifierName1: string, + arrayPatternIdentifierName2: string, + functionBodyIdentifierName1: string, + functionBodyIdentifierName2: string; - const arrayPatternIdentifierName1: string = obfuscatedCode.match(functionParameterMatch)![1]; - const arrayPatternIdentifierName2: string = obfuscatedCode.match(functionParameterMatch)![2]; - const functionBodyIdentifierName1: string = obfuscatedCode.match(functionBodyMatch)![1]; - const functionBodyIdentifierName2: string = obfuscatedCode.match(functionBodyMatch)![2]; + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/array-pattern-as-parameter.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET + } + ); + const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); - it('should keep same names for identifiers in function parameter array pattern and function body', () => { + arrayPatternIdentifierName1 = obfuscatedCode.match(functionParameterRegExp)![1]; + arrayPatternIdentifierName2 = obfuscatedCode.match(functionParameterRegExp)![2]; + functionBodyIdentifierName1 = obfuscatedCode.match(functionBodyRegExp)![1]; + functionBodyIdentifierName2 = obfuscatedCode.match(functionBodyRegExp)![2]; + }); + + it('equal #1: should keep same names for identifiers in function parameter array pattern and function body', () => { assert.equal(arrayPatternIdentifierName1, functionBodyIdentifierName1); + }); + + it('equal #2: should keep same names for identifiers in function parameter array pattern and function body', () => { assert.equal(arrayPatternIdentifierName2, functionBodyIdentifierName2); }); }); diff --git a/test/functional-tests/node-transformers/obfuscating-transformers/labeled-statement-transformer/LabeledStatementTransformer.spec.ts b/test/functional-tests/node-transformers/obfuscating-transformers/labeled-statement-transformer/LabeledStatementTransformer.spec.ts index e8a56b92..14974c0b 100644 --- a/test/functional-tests/node-transformers/obfuscating-transformers/labeled-statement-transformer/LabeledStatementTransformer.spec.ts +++ b/test/functional-tests/node-transformers/obfuscating-transformers/labeled-statement-transformer/LabeledStatementTransformer.spec.ts @@ -10,17 +10,35 @@ import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscator'; describe('LabeledStatementTransformer', () => { describe('changeControlFlow (labeledStatementNode: ESTree.LabeledStatement): void', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/input.js'), - { - ...NO_CUSTOM_NODES_PRESET - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); const labeledStatementRegExp: RegExp = /(_0x([a-f0-9]){4,6}): *\{/; const continueStatementRegExp: RegExp = /continue *(_0x([a-f0-9]){4,6});/; const breakStatementRegExp: RegExp = /break *(_0x([a-f0-9]){4,6});/; + let obfuscatedCode: string, + firstMatch: string|undefined, + secondMatch: string|undefined, + thirdMatch: string|undefined; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/input.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + + const firstMatchArray: RegExpMatchArray|null = obfuscatedCode.match(labeledStatementRegExp); + const secondMatchArray: RegExpMatchArray|null = obfuscatedCode.match(continueStatementRegExp); + const thirdMatchArray: RegExpMatchArray|null = obfuscatedCode.match(breakStatementRegExp); + + firstMatch = firstMatchArray ? firstMatchArray[1] : undefined; + secondMatch = secondMatchArray ? secondMatchArray[1] : undefined; + thirdMatch = thirdMatchArray ? thirdMatchArray[1] : undefined; + }); + it('should transform `labeledStatement` identifier', () => { assert.match(obfuscatedCode, labeledStatementRegExp); }); @@ -33,19 +51,11 @@ describe('LabeledStatementTransformer', () => { assert.match(obfuscatedCode, breakStatementRegExp); }); - it('`labeledStatement` identifier name and `labeledStatement` body `breakStatement` should be same', () => { - const firstMatchArray: RegExpMatchArray|null = obfuscatedCode.match(labeledStatementRegExp); - const secondMatchArray: RegExpMatchArray|null = obfuscatedCode.match(continueStatementRegExp); - const thirdMatchArray: RegExpMatchArray|null = obfuscatedCode.match(breakStatementRegExp); - - const firstMatch: string|undefined = firstMatchArray ? firstMatchArray[1] : undefined; - const secondMatch: string|undefined = secondMatchArray ? secondMatchArray[1] : undefined; - const thirdMatch: string|undefined = thirdMatchArray ? thirdMatchArray[1] : undefined; - - assert.isOk(firstMatch); - assert.isOk(secondMatch); - assert.isOk(thirdMatchArray); + it('equal #1: `labeledStatement` identifier name and `labeledStatement` body `breakStatement` should be same', () => { assert.equal(firstMatch, secondMatch); + }); + + it('equal #2: `labeledStatement` identifier name and `labeledStatement` body `breakStatement` should be same', () => { assert.equal(secondMatch, thirdMatch); }); }); diff --git a/test/functional-tests/node-transformers/obfuscating-transformers/literal-transformer/LiteralTransformer.spec.ts b/test/functional-tests/node-transformers/obfuscating-transformers/literal-transformer/LiteralTransformer.spec.ts index a467e1c8..bb5d6035 100644 --- a/test/functional-tests/node-transformers/obfuscating-transformers/literal-transformer/LiteralTransformer.spec.ts +++ b/test/functional-tests/node-transformers/obfuscating-transformers/literal-transformer/LiteralTransformer.spec.ts @@ -10,203 +10,354 @@ import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscator'; describe('LiteralTransformer', () => { describe('transformation of literal node with string value', () => { - it('should replace literal node value with value from string array', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/simple-input.js'), - { - ...NO_CUSTOM_NODES_PRESET, - stringArray: true, - stringArrayThreshold: 1 - } - ); + describe('variant #1: default behaviour', () => { + const stringArrayRegExp: RegExp = /^var *_0x([a-f0-9]){4} *= *\['test'\];/; + const stringArrayCallRegExp: RegExp = /var *test *= *_0x([a-f0-9]){4}\('0x0'\);/; - assert.match( - obfuscationResult.getObfuscatedCode(), - /^var *_0x([a-f0-9]){4} *= *\['test'\];/ - ); - assert.match(obfuscationResult.getObfuscatedCode(), /var *test *= *_0x([a-f0-9]){4}\('0x0'\);/); + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/simple-input.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + stringArray: true, + stringArrayThreshold: 1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('match #1: should replace literal node value with value from string array', () => { + assert.match(obfuscatedCode, stringArrayRegExp); + }); + + it('match #2: should replace literal node value with value from string array', () => { + assert.match(obfuscatedCode, stringArrayCallRegExp); + }); }); - it('shouldn\'t replace literal node value with value from string array if `stringArray` option is disabled', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/simple-input.js'), - { - ...NO_CUSTOM_NODES_PRESET - } - ); + describe('variant #2: `stringArray` option is disabled', () => { + const regExp: RegExp = /^var *test *= *'test';/; - assert.match( - obfuscationResult.getObfuscatedCode(), - /^var *test *= *'test';/ - ); + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/simple-input.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('shouldn\'t replace literal node value with value from string array', () => { + assert.match(obfuscatedCode, regExp); + }); }); - it('should\'t throw an error when string contains non-latin and non-digit characters and `unicodeEscapeSequence` is disabled', () => { - assert.doesNotThrow(() => JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/error-when-non-latin.js'), - { - ...NO_CUSTOM_NODES_PRESET, - stringArray: true, - stringArrayThreshold: 1 - } - )); + describe('variant #3: string contains non-latin and non-digit characters and `unicodeEscapeSequence` is disabled', () => { + let testFunc: () => void; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/error-when-non-latin.js'); + + testFunc = () => JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + stringArray: true, + stringArrayThreshold: 1 + } + ); + }); + + it('should\'t throw an error', () => { + assert.doesNotThrow(testFunc); + }); }); - it('should create only one item in string array for same literal node values', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/same-literal-values.js'), - { - ...NO_CUSTOM_NODES_PRESET, - stringArray: true, - stringArrayThreshold: 1 - } - ); + describe('variant #4: same literal node values', () => { + const stringArrayRegExp: RegExp = /^var *_0x([a-f0-9]){4} *= *\['test'\];/; + const stringArrayCallRegExp: RegExp = /var *test *= *_0x([a-f0-9]){4}\('0x0'\);/; - assert.match( - obfuscationResult.getObfuscatedCode(), - /^var *_0x([a-f0-9]){4} *= *\['test'\];/ - ); - assert.match(obfuscationResult.getObfuscatedCode(), /var *test *= *_0x([a-f0-9]){4}\('0x0'\);/); + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/same-literal-values.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + stringArray: true, + stringArrayThreshold: 1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('match #1: should create only one item in string array for same literal node values', () => { + assert.match(obfuscatedCode, stringArrayRegExp); + }); + + it('match #2: should create only one item in string array for same literal node values', () => { + assert.match(obfuscatedCode, stringArrayCallRegExp); + }); }); - it('should replace literal node value with unicode escape sequence if `unicodeEscapeSequence` is enabled', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/simple-input.js'), - { - ...NO_CUSTOM_NODES_PRESET, - unicodeEscapeSequence: true + describe('variant #5: `unicodeEscapeSequence` option is enabled', () => { + const regExp: RegExp = /^var *test *= *'\\x74\\x65\\x73\\x74';$/; - } - ); + let obfuscatedCode: string; - assert.match(obfuscationResult.getObfuscatedCode(), /^var *test *= *'\\x74\\x65\\x73\\x74';$/); + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/simple-input.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + unicodeEscapeSequence: true + + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('should replace literal node value with unicode escape sequence', () => { + assert.match(obfuscatedCode, regExp); + }); }); - it('should replace literal node value with unicode escape sequence from string array if `unicodeEscapeSequence` is enabled', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/simple-input.js'), - { - ...NO_CUSTOM_NODES_PRESET, - stringArray: true, - stringArrayThreshold: 1, - unicodeEscapeSequence: true - } - ); + describe('variant #6: `unicodeEscapeSequence` and `stringArray` options are enabled', () => { + const stringArrayRegExp: RegExp = /^var *_0x([a-f0-9]){4} *= *\['\\x74\\x65\\x73\\x74'\];/; + const stringArrayCallRegExp: RegExp = /var *test *= *_0x([a-f0-9]){4}\('0x0'\);/; - assert.match( - obfuscationResult.getObfuscatedCode(), - /^var *_0x([a-f0-9]){4} *= *\['\\x74\\x65\\x73\\x74'\];/ - ); - assert.match(obfuscationResult.getObfuscatedCode(), /var *test *= *_0x([a-f0-9]){4}\('0x0'\);/); + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/simple-input.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + stringArray: true, + stringArrayThreshold: 1, + unicodeEscapeSequence: true + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('match #1: should replace literal node value with unicode escape sequence from string array', () => { + assert.match(obfuscatedCode, stringArrayRegExp); + }); + + it('match #1: should replace literal node value with unicode escape sequence from string array', () => { + assert.match(obfuscatedCode, stringArrayCallRegExp); + }); }); - it('shouldn\'t replace short literal node value with value from string array', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/short-literal-value.js'), - { - ...NO_CUSTOM_NODES_PRESET, - stringArray: true, - stringArrayThreshold: 1 - } - ); + describe('variant #7: short literal node value', () => { + const regExp: RegExp = /var *test *= *'te';/; - assert.match(obfuscationResult.getObfuscatedCode(), /var *test *= *'te';/); + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/short-literal-value.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + stringArray: true, + stringArrayThreshold: 1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('shouldn\'t replace short literal node value with value from string array', () => { + assert.match(obfuscatedCode, regExp); + }); }); - it('should replace literal node value with value from string array encoded using base64', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/simple-input.js'), - { - ...NO_CUSTOM_NODES_PRESET, - stringArray: true, - stringArrayEncoding: 'base64', - stringArrayThreshold: 1 - } - ); + describe('variant #8: base64 encoding', () => { + const stringArrayRegExp: RegExp = /^var *_0x([a-f0-9]){4} *= *\['dGVzdA\\x3d\\x3d'\];/; + const stringArrayCallRegExp: RegExp = /var *test *= *_0x([a-f0-9]){4}\('0x0'\);/; - assert.match( - obfuscationResult.getObfuscatedCode(), - /^var *_0x([a-f0-9]){4} *= *\['dGVzdA\\x3d\\x3d'\];/ - ); - assert.match(obfuscationResult.getObfuscatedCode(), /var *test *= *_0x([a-f0-9]){4}\('0x0'\);/); + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/simple-input.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + stringArray: true, + stringArrayEncoding: 'base64', + stringArrayThreshold: 1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('match #1: should replace literal node value with value from string array encoded using base64', () => { + assert.match(obfuscatedCode, stringArrayRegExp); + }); + + it('match #2: should replace literal node value with value from string array encoded using base64', () => { + assert.match(obfuscatedCode, stringArrayCallRegExp); + }); }); - it('should replace literal node value with value from string array encoded using rc4', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/simple-input.js'), - { - ...NO_CUSTOM_NODES_PRESET, - stringArray: true, - stringArrayEncoding: 'rc4', - stringArrayThreshold: 1 - } - ); + describe('variant #9: rc4 encoding', () => { + const regExp: RegExp = /var *test *= *_0x([a-f0-9]){4}\('0x0', *'(?:\w|(?:\\x[a-f0-9]*)){4}'\);/; - assert.match( - obfuscationResult.getObfuscatedCode(), - /var *test *= *_0x([a-f0-9]){4}\('0x0', *'(?:\w|(?:\\x[a-f0-9]*)){4}'\);/ - ); + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/simple-input.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + stringArray: true, + stringArrayEncoding: 'rc4', + stringArrayThreshold: 1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('should replace literal node value with value from string array encoded using rc4', () => { + assert.match(obfuscatedCode, regExp); + }); }); - it('should replace literal node value with value from string array with `stringArrayThreshold` chance', () => { + describe('variant #10: `stringArrayThreshold` option value', () => { const samples: number = 1000; const stringArrayThreshold: number = 0.5; const delta: number = 0.1; - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - `${readFileAsString(__dirname + '/fixtures/simple-input.js')}\n`.repeat(samples), - { - ...NO_CUSTOM_NODES_PRESET, - stringArray: true, - stringArrayThreshold: stringArrayThreshold - } - ); const regExp1: RegExp = /var *test *= *_0x([a-f0-9]){4}\('0x0'\);/g; const regExp2: RegExp = /var *test *= *'test';/g; - const stringArrayMatchesLength = obfuscationResult.getObfuscatedCode().match(regExp1)!.length; - const noStringArrayMatchesLength = obfuscationResult.getObfuscatedCode().match(regExp2)!.length; - assert.closeTo(stringArrayMatchesLength / samples, stringArrayThreshold, delta); - assert.closeTo(noStringArrayMatchesLength / samples, stringArrayThreshold, delta); + let stringArrayProbability: number, + noStringArrayProbability: number; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/simple-input.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + `${code}\n`.repeat(samples), + { + ...NO_CUSTOM_NODES_PRESET, + stringArray: true, + stringArrayThreshold: stringArrayThreshold + } + ); + + const stringArrayMatchesLength: number = obfuscationResult + .getObfuscatedCode() + .match(regExp1)! + .length; + const noStringArrayMatchesLength: number = obfuscationResult + .getObfuscatedCode() + .match(regExp2)! + .length; + + stringArrayProbability = stringArrayMatchesLength / samples; + noStringArrayProbability = noStringArrayMatchesLength / samples; + }); + + it('variant #1: should replace literal node value with value from string array with `stringArrayThreshold` chance', () => { + assert.closeTo(stringArrayProbability, stringArrayThreshold, delta); + }); + + it('variant #2: shouldn\'t replace literal node value with value from string array with `(1 - stringArrayThreshold)` chance', () => { + assert.closeTo(noStringArrayProbability, stringArrayThreshold, delta); + }); }); }); - it('should transform literal node with boolean value', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/boolean-value.js'), - { - ...NO_CUSTOM_NODES_PRESET, - stringArray: true, - stringArrayThreshold: 1 - } - ); + describe('transformation of literal node with boolean value', () => { + const regExp: RegExp = /^var *test *= *!!\[\];$/; - assert.match(obfuscationResult.getObfuscatedCode(), /^var *test *= *!!\[\];$/); + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/boolean-value.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + stringArray: true, + stringArrayThreshold: 1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('should transform literal node', () => { + assert.match(obfuscatedCode, regExp); + }); }); - it('should transform literal node with number value', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/number-value.js'), - { - ...NO_CUSTOM_NODES_PRESET, - stringArray: true, - stringArrayThreshold: 1 - } - ); + describe('transformation of literal node with number value', () => { + const regExp: RegExp = /^var *test *= *0x0;$/; - assert.match(obfuscationResult.getObfuscatedCode(), /^var *test *= *0x0;$/); + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/number-value.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + stringArray: true, + stringArrayThreshold: 1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('should transform literal node', () => { + assert.match(obfuscatedCode, regExp); + }); }); - it('should keep safe value of RegExp literal', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/regexp-literal.js'), - { - ...NO_CUSTOM_NODES_PRESET, - stringArray: true, - stringArrayThreshold: 1 - } - ); + describe('RegExp literal', () => { + const regExp: RegExp = /^var *regExp *= *\/\(\\d\+\)\/;$/; - assert.match(obfuscationResult.getObfuscatedCode(), /^var *regExp *= *\/\(\\d\+\)\/;$/); + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/regexp-literal.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET, + stringArray: true, + stringArrayThreshold: 1 + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('should keep safe value of RegExp literal', () => { + assert.match(obfuscatedCode, regExp); + }); }); }); diff --git a/test/functional-tests/node-transformers/obfuscating-transformers/object-expression-transformer/ObjectExpressionTransformer.spec.ts b/test/functional-tests/node-transformers/obfuscating-transformers/object-expression-transformer/ObjectExpressionTransformer.spec.ts index 6c633ed4..aaae47e6 100644 --- a/test/functional-tests/node-transformers/obfuscating-transformers/object-expression-transformer/ObjectExpressionTransformer.spec.ts +++ b/test/functional-tests/node-transformers/obfuscating-transformers/object-expression-transformer/ObjectExpressionTransformer.spec.ts @@ -9,28 +9,47 @@ import { readFileAsString } from '../../../../helpers/readFileAsString'; import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscator'; describe('ObjectExpressionTransformer', () => { - it('should replace object expression node `key` property with identifier value by property with literal value', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/property-with-identifier-value.js'), - { - ...NO_CUSTOM_NODES_PRESET - } - ); + describe('default behaviour', () => { + const regExp: RegExp = /var *test *= *\{'foo':0x0\};/; - assert.match(obfuscationResult.getObfuscatedCode(), /var *test *= *\{'foo':0x0\};/); + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/property-with-identifier-value.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('should replace object expression node `key` property with identifier value by property with literal value', () => { + assert.match(obfuscatedCode, regExp); + }); }); - it('should correct convert shorthand ES6 object expression to non-shorthand object expression', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/shorthand-object-expression.js'), - { - ...NO_CUSTOM_NODES_PRESET - } - ); + describe('shorthand ES6 object expression', () => { + const regExp: RegExp = /var *_0x[a-f0-9]{4,6} *= *\{'a': *_0x[a-f0-9]{4,6}\, *'b': *_0x[a-f0-9]{4,6}\};/; - assert.match( - obfuscationResult.getObfuscatedCode(), - /var *_0x[a-f0-9]{4,6} *= *\{'a': *_0x[a-f0-9]{4,6}\, *'b': *_0x[a-f0-9]{4,6}\};/ - ); + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/shorthand-object-expression.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('should correct convert shorthand ES6 object expression to non-shorthand object expression', () => { + assert.match(obfuscatedCode, regExp); + }); }); }); diff --git a/test/functional-tests/node-transformers/obfuscating-transformers/variable-declaration-transformer/VariableDeclarationTransformer.spec.ts b/test/functional-tests/node-transformers/obfuscating-transformers/variable-declaration-transformer/VariableDeclarationTransformer.spec.ts index 4d3d6f94..27a7f967 100644 --- a/test/functional-tests/node-transformers/obfuscating-transformers/variable-declaration-transformer/VariableDeclarationTransformer.spec.ts +++ b/test/functional-tests/node-transformers/obfuscating-transformers/variable-declaration-transformer/VariableDeclarationTransformer.spec.ts @@ -9,106 +9,185 @@ import { readFileAsString } from '../../../../helpers/readFileAsString'; import { JavaScriptObfuscator } from '../../../../../src/JavaScriptObfuscator'; describe('VariableDeclarationTransformer', () => { - it('should transform `variableDeclaration` node', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/simple-declaration.js'), - { - ...NO_CUSTOM_NODES_PRESET - } - ); + describe('variant #1: default behaviour', () => { + const variableDeclarationRegExp: RegExp = /var *_0x([a-f0-9]){4,6} *= *'abc';/; + const variableCallRegExp: RegExp = /console\['log'\]\(_0x([a-f0-9]){4,6}\);/; - assert.match(obfuscationResult.getObfuscatedCode(), /var *_0x([a-f0-9]){4,6} *= *'abc';/); - assert.match(obfuscationResult.getObfuscatedCode(), /console\['log'\]\(_0x([a-f0-9]){4,6}\);/); - }); + let obfuscatedCode: string; - it('should not transform `variableDeclaration` node if parent block scope node is `Program` node', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/parent-block-scope-is-program-node.js'), - { - ...NO_CUSTOM_NODES_PRESET - } - ); - - assert.match(obfuscationResult.getObfuscatedCode(), /var *test *= *0xa;/); - assert.match(obfuscationResult.getObfuscatedCode(), /console\['log'\]\(test\);/); - }); - - it('should transform variable call (`identifier` node) outside of block scope of node in which this variable was declared with `var` kind', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/var-kind.js'), - { - ...NO_CUSTOM_NODES_PRESET - } - ); - - assert.match(obfuscationResult.getObfuscatedCode(), /console\['log'\]\(_0x([a-f0-9]){4,6}\);/); - }); - - it('should not transform variable call (`identifier` node) outside of block scope of node in which this variable was declared with `let` kind', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/let-kind.js'), - { - ...NO_CUSTOM_NODES_PRESET - } - ); - - assert.match(obfuscationResult.getObfuscatedCode(), /console\['log'\]\(test\);/); - }); - - describe(`variable calls before variable declaration`, () => { - let obfuscationResult: IObfuscationResult; - - beforeEach(() => { - obfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/variable-call-before-variable-declaration-1.js'), + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/simple-declaration.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, { ...NO_CUSTOM_NODES_PRESET } ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); }); - it('should transform variable call (`identifier` node name) before variable declaration if this call is inside function body', () => { - assert.match(obfuscationResult.getObfuscatedCode(), /console\['log'\]\(_0x([a-f0-9]){4,6}\['item'\]\);/); + it('match #1: should transform `variableDeclaration` node', () => { + assert.match(obfuscatedCode, variableDeclarationRegExp); }); - it('should transform variable call (`identifier` node name) before variable declaration', () => { - assert.match(obfuscationResult.getObfuscatedCode(), /console\['log'\]\(_0x([a-f0-9]){4,6}\);/); + it('match #2: should transform `variableDeclaration` node', () => { + assert.match(obfuscatedCode, variableCallRegExp); }); }); - describe(`variable calls before variable declaration when function param has the same name as variables name`, () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/variable-call-before-variable-declaration-2.js'), - { - ...NO_CUSTOM_NODES_PRESET - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); + describe('variant #2: parent block scope node is `Program` node', () => { + const variableDeclarationRegExp: RegExp = /var *test *= *0xa;/; + const variableCallRegExp: RegExp = /console\['log'\]\(test\);/; - const functionParamIdentifierMatch: RegExpMatchArray|null = obfuscatedCode - .match(/function *_0x[a-f0-9]{4,6} *\((_0x[a-f0-9]{4,6})\,(_0x[a-f0-9]{4,6})\) *\{/); - const innerFunctionParamIdentifierMatch: RegExpMatchArray|null = obfuscatedCode - .match(/function _0x[a-f0-9]{4,6} *\((_0x[a-f0-9]{4,6})\) *\{/); - const constructorIdentifierMatch: RegExpMatchArray|null = obfuscatedCode - .match(/console\['log'\]\((_0x[a-f0-9]{4,6})\)/); - const objectIdentifierMatch: RegExpMatchArray|null = obfuscatedCode - .match(/return\{'t':(_0x[a-f0-9]{4,6})\}/); - const variableDeclarationIdentifierMatch: RegExpMatchArray|null = obfuscatedCode - .match(/var *(_0x[a-f0-9]{4,6});/); + let obfuscatedCode: string; - const outerFunctionParamIdentifierName: string|null = (functionParamIdentifierMatch)[1]; - const innerFunctionParamIdentifierName: string|null = (innerFunctionParamIdentifierMatch)[1]; - const constructorIdentifierName: string|null = (constructorIdentifierMatch)[1]; - const objectIdentifierName: string|null = (objectIdentifierMatch)[1]; - const variableDeclarationIdentifierName: string|null = (variableDeclarationIdentifierMatch)[1]; + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/parent-block-scope-is-program-node.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET + } + ); - it('should\'t name variables inside inner function with names from outer function params', () => { + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('match #1: shouldn\'t transform `variableDeclaration` node', () => { + assert.match(obfuscatedCode, variableDeclarationRegExp); + }); + + it('match #2: shouldn\'t transform `variableDeclaration` node', () => { + assert.match(obfuscatedCode, variableCallRegExp); + }); + }); + + describe('variant #3: scope of `var` kind', () => { + const regExp: RegExp = /console\['log'\]\(_0x([a-f0-9]){4,6}\);/; + + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/var-kind.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('should transform variable call (`identifier` node) outside of block scope of node in which this variable was declared with `var` kind', () => { + assert.match(obfuscatedCode, regExp); + }); + }); + + describe('variant #4: scope of `let` kind', () => { + const regExp: RegExp = /console\['log'\]\(test\);/; + + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/let-kind.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('shouldn\'t transform variable call (`identifier` node) outside of block scope of node in which this variable was declared with `let` kind', () => { + assert.match(obfuscatedCode, regExp); + }); + }); + + describe(`variant #5: variable calls before variable declaration`, () => { + const functionBodyVariableCallRegExp: RegExp = /console\['log'\]\(_0x([a-f0-9]){4,6}\['item'\]\);/; + const variableCallBeforeDeclarationRegExp: RegExp = /console\['log'\]\(_0x([a-f0-9]){4,6}\);/; + + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/variable-call-before-variable-declaration-1.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('should transform variable call (`identifier` node name) before variable declaration if this call is inside function body', () => { + assert.match(obfuscatedCode, functionBodyVariableCallRegExp); + }); + + it('should transform variable call (`identifier` node name) before variable declaration', () => { + assert.match(obfuscatedCode, variableCallBeforeDeclarationRegExp); + }); + }); + + describe(`variant #6: variable calls before variable declaration when function param has the same name as variables name`, () => { + const functionParamIdentifierRegExp: RegExp = /function *_0x[a-f0-9]{4,6} *\((_0x[a-f0-9]{4,6})\,(_0x[a-f0-9]{4,6})\) *\{/; + const innerFunctionParamIdentifierRegExp: RegExp = /function _0x[a-f0-9]{4,6} *\((_0x[a-f0-9]{4,6})\) *\{/; + const constructorIdentifierRegExp: RegExp = /console\['log'\]\((_0x[a-f0-9]{4,6})\)/; + const objectIdentifierRegExp: RegExp = /return\{'t':(_0x[a-f0-9]{4,6})\}/; + const variableDeclarationIdentifierRegExp: RegExp = /var *(_0x[a-f0-9]{4,6});/; + + let outerFunctionParamIdentifierName: string|null, + innerFunctionParamIdentifierName: string|null, + constructorIdentifierName: string|null, + objectIdentifierName: string|null, + variableDeclarationIdentifierName: string|null; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/variable-call-before-variable-declaration-2.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET + } + ); + const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); + + const functionParamIdentifierMatch: RegExpMatchArray|null = obfuscatedCode + .match(functionParamIdentifierRegExp); + const innerFunctionParamIdentifierMatch: RegExpMatchArray|null = obfuscatedCode + .match(innerFunctionParamIdentifierRegExp); + const constructorIdentifierMatch: RegExpMatchArray|null = obfuscatedCode + .match(constructorIdentifierRegExp); + const objectIdentifierMatch: RegExpMatchArray|null = obfuscatedCode + .match(objectIdentifierRegExp); + const variableDeclarationIdentifierMatch: RegExpMatchArray|null = obfuscatedCode + .match(variableDeclarationIdentifierRegExp); + + outerFunctionParamIdentifierName = (functionParamIdentifierMatch)[1]; + innerFunctionParamIdentifierName = (innerFunctionParamIdentifierMatch)[1]; + constructorIdentifierName = (constructorIdentifierMatch)[1]; + objectIdentifierName = (objectIdentifierMatch)[1]; + variableDeclarationIdentifierName = (variableDeclarationIdentifierMatch)[1]; + }); + + it('match #1: should\'t name variables inside inner function with names from outer function params', () => { assert.notEqual(outerFunctionParamIdentifierName, constructorIdentifierName); + }); + + it('match #2: should\'t name variables inside inner function with names from outer function params', () => { assert.notEqual(outerFunctionParamIdentifierName, innerFunctionParamIdentifierName); }); - it('should correct transform variables inside outer function body', () => { + it('match #1: should correct transform variables inside outer function body', () => { assert.equal(outerFunctionParamIdentifierName, objectIdentifierName); + }); + + it('match #2: should correct transform variables inside outer function body', () => { assert.equal(outerFunctionParamIdentifierName, variableDeclarationIdentifierName); }); @@ -121,40 +200,61 @@ describe('VariableDeclarationTransformer', () => { }); }); - describe(`variable calls before variable declaration when catch clause param has the same name as variables name`, () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/variable-call-before-variable-declaration-3.js'), - { - ...NO_CUSTOM_NODES_PRESET - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); + describe(`variant #7: variable calls before variable declaration when catch clause param has the same name as variables name`, () => { + const catchClauseParamIdentifierRegExp: RegExp = /catch *\((_0x[a-f0-9]{4,6})\) *\{/; + const innerFunctionParamIdentifierRegExp: RegExp = /function _0x[a-f0-9]{4,6} *\((_0x[a-f0-9]{4,6})\) *\{/; + const constructorIdentifierRegExp: RegExp = /console\['log'\]\((_0x[a-f0-9]{4,6})\)/; + const objectIdentifierRegExp: RegExp = /return\{'t':(_0x[a-f0-9]{4,6})\}/; + const variableDeclarationIdentifierRegExp: RegExp = /var *(_0x[a-f0-9]{4,6});/; - const catchClauseParamIdentifierMatch: RegExpMatchArray|null = obfuscatedCode - .match(/catch *\((_0x[a-f0-9]{4,6})\) *\{/); - const innerFunctionParamIdentifierMatch: RegExpMatchArray|null = obfuscatedCode - .match(/function _0x[a-f0-9]{4,6} *\((_0x[a-f0-9]{4,6})\) *\{/); - const constructorIdentifierMatch: RegExpMatchArray|null = obfuscatedCode - .match(/console\['log'\]\((_0x[a-f0-9]{4,6})\)/); - const objectIdentifierMatch: RegExpMatchArray|null = obfuscatedCode - .match(/return\{'t':(_0x[a-f0-9]{4,6})\}/); - const variableDeclarationIdentifierMatch: RegExpMatchArray|null = obfuscatedCode - .match(/var *(_0x[a-f0-9]{4,6});/); + let catchClauseParamIdentifierName: string|null, + innerFunctionParamIdentifierName: string|null, + constructorIdentifierName: string|null, + objectIdentifierName: string|null, + variableDeclarationIdentifierName: string|null; - const functionParamIdentifierName: string|null = (catchClauseParamIdentifierMatch)[1]; - const innerFunctionParamIdentifierName: string|null = (innerFunctionParamIdentifierMatch)[1]; - const constructorIdentifierName: string|null = (constructorIdentifierMatch)[1]; - const objectIdentifierName: string|null = (objectIdentifierMatch)[1]; - const variableDeclarationIdentifierName: string|null = (variableDeclarationIdentifierMatch)[1]; + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/variable-call-before-variable-declaration-3.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET + } + ); + const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); - it('should\'t name variables inside inner function with names from catch clause param', () => { - assert.notEqual(functionParamIdentifierName, constructorIdentifierName); - assert.notEqual(functionParamIdentifierName, innerFunctionParamIdentifierName); + const catchClauseParamIdentifierMatch: RegExpMatchArray|null = obfuscatedCode + .match(catchClauseParamIdentifierRegExp); + const innerFunctionParamIdentifierMatch: RegExpMatchArray|null = obfuscatedCode + .match(innerFunctionParamIdentifierRegExp); + const constructorIdentifierMatch: RegExpMatchArray|null = obfuscatedCode + .match(constructorIdentifierRegExp); + const objectIdentifierMatch: RegExpMatchArray|null = obfuscatedCode + .match(objectIdentifierRegExp); + const variableDeclarationIdentifierMatch: RegExpMatchArray|null = obfuscatedCode + .match(variableDeclarationIdentifierRegExp); + + catchClauseParamIdentifierName = (catchClauseParamIdentifierMatch)[1]; + innerFunctionParamIdentifierName = (innerFunctionParamIdentifierMatch)[1]; + constructorIdentifierName = (constructorIdentifierMatch)[1]; + objectIdentifierName = (objectIdentifierMatch)[1]; + variableDeclarationIdentifierName = (variableDeclarationIdentifierMatch)[1]; }); - it('should correct transform variables inside catch clause body', () => { - assert.equal(functionParamIdentifierName, objectIdentifierName); - assert.equal(functionParamIdentifierName, variableDeclarationIdentifierName); + it('match #1: should\'t name variables inside inner function with names from catch clause param', () => { + assert.notEqual(catchClauseParamIdentifierName, constructorIdentifierName); + }); + + it('match #2: should\'t name variables inside inner function with names from catch clause param', () => { + assert.notEqual(catchClauseParamIdentifierName, innerFunctionParamIdentifierName); + }); + + it('equal #1: should correct transform variables inside catch clause body', () => { + assert.equal(catchClauseParamIdentifierName, objectIdentifierName); + }); + + it('equal #2: should correct transform variables inside catch clause body', () => { + assert.equal(catchClauseParamIdentifierName, variableDeclarationIdentifierName); }); it('should correct transform variables inside inner function body', () => { @@ -166,72 +266,119 @@ describe('VariableDeclarationTransformer', () => { }); }); - describe('wrong replacement', () => { - it('shouldn\'t replace property node identifier', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/property-identifier.js'), + describe('variant #8: wrong replacement', () => { + describe('variant #1: property node identifier', () => { + const regExp: RegExp = /var _0x([a-f0-9]){4,6} *= *\{'test/; + + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/property-identifier.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('shouldn\'t replace property node identifier', () => { + assert.match(obfuscatedCode, regExp); + }); + }); + + describe('variant #2: computed member expression identifier', () => { + const regExp: RegExp = /_0x([a-f0-9]){4,6}\['test'\]/; + + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/member-expression-identifier.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, + { + ...NO_CUSTOM_NODES_PRESET + } + ); + + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('shouldn\'t replace computed member expression identifier', () => { + assert.match(obfuscatedCode, regExp); + }); + }); + }); + + describe('variant #9: object pattern as variable declarator', () => { + const objectPatternVariableDeclaratorRegExp: RegExp = /var *\{ *bar *\} *= *\{ *'bar' *: *'foo' *\};/; + const variableUsageRegExp: RegExp = /console\['log'\]\(bar\);/; + + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/object-pattern.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, { ...NO_CUSTOM_NODES_PRESET } ); - assert.match(obfuscationResult.getObfuscatedCode(), /var _0x([a-f0-9]){4,6} *= *\{'test/); + obfuscatedCode = obfuscationResult.getObfuscatedCode(); }); - it('shouldn\'t replace computed member expression identifier', () => { - let obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/member-expression-identifier.js'), + it('match #1: shouldn\'t transform object pattern variable declarator', () => { + assert.match(obfuscatedCode, objectPatternVariableDeclaratorRegExp); + }); + + it('match #2: shouldn\'t transform object pattern variable declarator', () => { + assert.match(obfuscatedCode, variableUsageRegExp); + }); + }); + + describe('variant #10: array pattern as variable declarator', () => { + const objectPatternVariableDeclaratorRegExp: RegExp = /var *\[ *(_0x([a-f0-9]){4,6}), *(_0x([a-f0-9]){4,6}) *\] *= *\[0x1, *0x2\];/; + const variableUsageRegExp: RegExp = /console\['log'\]\((_0x([a-f0-9]){4,6}), *(_0x([a-f0-9]){4,6})\);/; + + let obfuscatedCode: string, + objectPatternIdentifierName1: string, + objectPatternIdentifierName2: string, + identifierName1: string, + identifierName2: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/array-pattern.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( + code, { ...NO_CUSTOM_NODES_PRESET } ); - assert.match(obfuscationResult.getObfuscatedCode(), /_0x([a-f0-9]){4,6}\['test'\]/); - }); - }); + obfuscatedCode = obfuscationResult.getObfuscatedCode(); - describe('object pattern as variable declarator', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/object-pattern.js'), - { - ...NO_CUSTOM_NODES_PRESET - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); - - it('shouldn\'t transform object pattern variable declarator', () => { - const objectPatternVariableDeclaratorMatch: RegExp = /var *\{ *bar *\} *= *\{ *'bar' *: *'foo' *\};/; - const variableUsageMatch: RegExp = /console\['log'\]\(bar\);/; - - assert.match(obfuscatedCode, objectPatternVariableDeclaratorMatch); - assert.match(obfuscatedCode, variableUsageMatch); - }); - }); - - describe('array pattern as variable declarator', () => { - const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( - readFileAsString(__dirname + '/fixtures/array-pattern.js'), - { - ...NO_CUSTOM_NODES_PRESET - } - ); - const obfuscatedCode: string = obfuscationResult.getObfuscatedCode(); - - const objectPatternVariableDeclaratorMatch: RegExp = /var *\[ *(_0x([a-f0-9]){4,6}), *(_0x([a-f0-9]){4,6}) *\] *= *\[0x1, *0x2\];/; - const variableUsageMatch: RegExp = /console\['log'\]\((_0x([a-f0-9]){4,6}), *(_0x([a-f0-9]){4,6})\);/; - - const objectPatternIdentifierName1: string = obfuscatedCode.match(objectPatternVariableDeclaratorMatch)![1]; - const objectPatternIdentifierName2: string = obfuscatedCode.match(objectPatternVariableDeclaratorMatch)![2]; - const identifierName1: string = obfuscatedCode.match(variableUsageMatch)![1]; - const identifierName2: string = obfuscatedCode.match(variableUsageMatch)![2]; - - it('should transform array pattern variable declarator', () => { - assert.match(obfuscatedCode, objectPatternVariableDeclaratorMatch); - assert.match(obfuscatedCode, variableUsageMatch); + objectPatternIdentifierName1 = obfuscatedCode.match(objectPatternVariableDeclaratorRegExp)![1]; + objectPatternIdentifierName2 = obfuscatedCode.match(objectPatternVariableDeclaratorRegExp)![2]; + identifierName1 = obfuscatedCode.match(variableUsageRegExp)![1]; + identifierName2 = obfuscatedCode.match(variableUsageRegExp)![2]; }); - it('should keep same identifier names same for identifiers in variable declaration and after variable declaration', () => { + it('match #1: should transform array pattern variable declarator', () => { + assert.match(obfuscatedCode, objectPatternVariableDeclaratorRegExp); + }); + + it('match #2: should transform array pattern variable declarator', () => { + assert.match(obfuscatedCode, variableUsageRegExp); + }); + + it('equal #1: should keep same identifier names same for identifiers in variable declaration and after variable declaration', () => { assert.equal(objectPatternIdentifierName1, identifierName1); + }); + + it('equal #2: should keep same identifier names same for identifiers in variable declaration and after variable declaration', () => { assert.equal(objectPatternIdentifierName2, identifierName2); }); }); diff --git a/test/functional-tests/stack-trace-analyzer/stack-trace-analyzer/StackTraceAnalyzer.spec.ts b/test/functional-tests/stack-trace-analyzer/stack-trace-analyzer/StackTraceAnalyzer.spec.ts index e6341608..387def2b 100644 --- a/test/functional-tests/stack-trace-analyzer/stack-trace-analyzer/StackTraceAnalyzer.spec.ts +++ b/test/functional-tests/stack-trace-analyzer/stack-trace-analyzer/StackTraceAnalyzer.spec.ts @@ -152,308 +152,337 @@ describe('StackTraceAnalyzer', () => { const stackTraceAnalyzer: IStackTraceAnalyzer = inversifyContainerFacade .get(ServiceIdentifiers.IStackTraceAnalyzer); - let astTree: TNodeWithBlockStatement, - stackTraceData: IStackTraceData[], - expectedStackTraceData: IStackTraceData[]; + let expectedStackTraceData: IStackTraceData[], + stackTraceData: IStackTraceData[]; - it('should returns correct IStackTraceData - variant #1: basic-1', () => { - astTree = Nodes.getProgramNode( - NodeUtils.convertCodeToStructure( - readFileAsString(__dirname + '/fixtures/basic-1.js') - ) - ); + describe('variant #1: basic-1', () => { + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/basic-1.js'); + const astTree: TNodeWithBlockStatement = Nodes.getProgramNode( + NodeUtils.convertCodeToStructure(code) + ); - expectedStackTraceData = [ - { - name: 'baz', - callee: (getFunctionDeclarationByName(astTree, 'baz')).body, - stackTrace: [] - }, - { - name: 'foo', - callee: (getFunctionDeclarationByName(astTree, 'foo')).body, - stackTrace: [] - }, - { - name: 'bar', - callee: (getFunctionDeclarationByName(astTree, 'bar')).body, - stackTrace: [ - { - name: 'inner2', - callee: (getFunctionDeclarationByName(astTree, 'inner2')).body, - stackTrace: [ - { - name: 'inner3', - callee: (getFunctionExpressionByName(astTree, 'inner3')).body, - stackTrace: [] - }, - ] - }, - { - name: 'inner1', - callee: (getFunctionDeclarationByName(astTree, 'inner1')).body, - stackTrace: [] - }, - ] - } - ]; + expectedStackTraceData = [ + { + name: 'baz', + callee: (getFunctionDeclarationByName(astTree, 'baz')).body, + stackTrace: [] + }, + { + name: 'foo', + callee: (getFunctionDeclarationByName(astTree, 'foo')).body, + stackTrace: [] + }, + { + name: 'bar', + callee: (getFunctionDeclarationByName(astTree, 'bar')).body, + stackTrace: [ + { + name: 'inner2', + callee: (getFunctionDeclarationByName(astTree, 'inner2')).body, + stackTrace: [ + { + name: 'inner3', + callee: (getFunctionExpressionByName(astTree, 'inner3')).body, + stackTrace: [] + }, + ] + }, + { + name: 'inner1', + callee: (getFunctionDeclarationByName(astTree, 'inner1')).body, + stackTrace: [] + }, + ] + } + ]; - stackTraceData = stackTraceAnalyzer.analyze(astTree.body); + stackTraceData = stackTraceAnalyzer.analyze(astTree.body); + }); - assert.deepEqual(stackTraceData, expectedStackTraceData); + it('should return correct stack trace data', () => { + assert.deepEqual(stackTraceData, expectedStackTraceData); + }); }); - it('should returns correct IStackTraceData - variant #2: basic-2', () => { - astTree = Nodes.getProgramNode( - NodeUtils.convertCodeToStructure( - readFileAsString(__dirname + '/fixtures/basic-2.js') - ) - ); + describe('variant #2: basic-2', () => { + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/basic-2.js'); + const astTree: TNodeWithBlockStatement = Nodes.getProgramNode( + NodeUtils.convertCodeToStructure(code) + ); - expectedStackTraceData = [ - { - name: 'bar', - callee: (getFunctionDeclarationByName(astTree, 'bar')).body, - stackTrace: [] - }, - { - name: 'baz', - callee: (getFunctionDeclarationByName(astTree, 'baz')).body, - stackTrace: [ - { - name: 'inner1', - callee: (getFunctionDeclarationByName(astTree, 'inner1')).body, - stackTrace: [] - }, - ] - }, - { - name: 'foo', - callee: (getFunctionDeclarationByName(astTree, 'foo')).body, - stackTrace: [] - } - ]; + expectedStackTraceData = [ + { + name: 'bar', + callee: (getFunctionDeclarationByName(astTree, 'bar')).body, + stackTrace: [] + }, + { + name: 'baz', + callee: (getFunctionDeclarationByName(astTree, 'baz')).body, + stackTrace: [ + { + name: 'inner1', + callee: (getFunctionDeclarationByName(astTree, 'inner1')).body, + stackTrace: [] + }, + ] + }, + { + name: 'foo', + callee: (getFunctionDeclarationByName(astTree, 'foo')).body, + stackTrace: [] + } + ]; - stackTraceData = stackTraceAnalyzer.analyze(astTree.body); + stackTraceData = stackTraceAnalyzer.analyze(astTree.body); + }); - assert.deepEqual(stackTraceData, expectedStackTraceData); + it('should return correct stack trace data', () => { + assert.deepEqual(stackTraceData, expectedStackTraceData); + }); }); - it('should returns correct IStackTraceData - variant #3: deep conditions nesting', () => { - astTree = Nodes.getProgramNode( - NodeUtils.convertCodeToStructure( - readFileAsString(__dirname + '/fixtures/deep-conditions-nesting.js') - ) - ); + describe('variant #3: deep conditions nesting', () => { + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/deep-conditions-nesting.js'); + const astTree: TNodeWithBlockStatement = Nodes.getProgramNode( + NodeUtils.convertCodeToStructure(code) + ); - expectedStackTraceData = [ - { - name: 'bar', - callee: (getFunctionDeclarationByName(astTree, 'bar')).body, - stackTrace: [] - }, - { - name: 'baz', - callee: (getFunctionDeclarationByName(astTree, 'baz')).body, - stackTrace: [ - { - name: 'inner1', - callee: (getFunctionDeclarationByName(astTree, 'inner1')).body, - stackTrace: [] - }, - ] - }, - { - name: 'foo', - callee: (getFunctionDeclarationByName(astTree, 'foo')).body, - stackTrace: [] - } - ]; + expectedStackTraceData = [ + { + name: 'bar', + callee: (getFunctionDeclarationByName(astTree, 'bar')).body, + stackTrace: [] + }, + { + name: 'baz', + callee: (getFunctionDeclarationByName(astTree, 'baz')).body, + stackTrace: [ + { + name: 'inner1', + callee: (getFunctionDeclarationByName(astTree, 'inner1')).body, + stackTrace: [] + }, + ] + }, + { + name: 'foo', + callee: (getFunctionDeclarationByName(astTree, 'foo')).body, + stackTrace: [] + } + ]; - stackTraceData = stackTraceAnalyzer.analyze(astTree.body); + stackTraceData = stackTraceAnalyzer.analyze(astTree.body); + }); - assert.deepEqual(stackTraceData, expectedStackTraceData); + it('should return correct stack trace data', () => { + assert.deepEqual(stackTraceData, expectedStackTraceData); + }); }); - it('should returns correct IStackTraceData - variant #4: call before declaration', () => { - astTree = Nodes.getProgramNode( - NodeUtils.convertCodeToStructure( - readFileAsString(__dirname + '/fixtures/call-before-declaration.js') - ) - ); + describe('variant #4: call before declaration', () => { + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/call-before-declaration.js'); + const astTree: TNodeWithBlockStatement = Nodes.getProgramNode( + NodeUtils.convertCodeToStructure(code) + ); - expectedStackTraceData = [ - { - name: 'bar', - callee: (getFunctionDeclarationByName(astTree, 'bar')).body, - stackTrace: [] - } - ]; + expectedStackTraceData = [ + { + name: 'bar', + callee: (getFunctionDeclarationByName(astTree, 'bar')).body, + stackTrace: [] + } + ]; - stackTraceData = stackTraceAnalyzer.analyze(astTree.body); + stackTraceData = stackTraceAnalyzer.analyze(astTree.body); + }); - assert.deepEqual(stackTraceData, expectedStackTraceData); + it('should return correct stack trace data', () => { + assert.deepEqual(stackTraceData, expectedStackTraceData); + }); }); - it('should returns correct IStackTraceData - variant #5: call expression of object member #1', () => { - astTree = Nodes.getProgramNode( - NodeUtils.convertCodeToStructure( - readFileAsString(__dirname + '/fixtures/call-expression-of-object-member-1.js') - ) - ); + describe('variant #5: call expression of object member #1', () => { + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/call-expression-of-object-member-1.js'); + const astTree: TNodeWithBlockStatement = Nodes.getProgramNode( + NodeUtils.convertCodeToStructure(code) + ); - expectedStackTraceData = [ - { - name: 'baz', - callee: (getObjectFunctionExpressionByName(astTree, 'object1', 'baz')).body, - stackTrace: [] - }, - { - name: 'baz', - callee: (getObjectFunctionExpressionByName(astTree, 'object1', 'baz')).body, - stackTrace: [] - }, - { - name: 'func', - callee: (getObjectFunctionExpressionByName(astTree, 'object1', 'func')).body, - stackTrace: [] - }, - { - name: 'bar', - callee: (getObjectFunctionExpressionByName(astTree, 'object1', 'bar')).body, - stackTrace: [ - { - name: 'inner1', - callee: (getFunctionDeclarationByName(astTree, 'inner1')).body, - stackTrace: [ + expectedStackTraceData = [ + { + name: 'baz', + callee: (getObjectFunctionExpressionByName(astTree, 'object1', 'baz')).body, + stackTrace: [] + }, + { + name: 'baz', + callee: (getObjectFunctionExpressionByName(astTree, 'object1', 'baz')).body, + stackTrace: [] + }, + { + name: 'func', + callee: (getObjectFunctionExpressionByName(astTree, 'object1', 'func')).body, + stackTrace: [] + }, + { + name: 'bar', + callee: (getObjectFunctionExpressionByName(astTree, 'object1', 'bar')).body, + stackTrace: [ + { + name: 'inner1', + callee: (getFunctionDeclarationByName(astTree, 'inner1')).body, + stackTrace: [ - ] - }, - ] - }, - { - name: 'bar', - callee: (getObjectFunctionExpressionByName(astTree, 'object', 'bar')).body, - stackTrace: [ - { - name: 'inner', - callee: (getFunctionDeclarationByName(astTree, 'inner')).body, - stackTrace: [ - - ] - }, - ] - } - ]; - - stackTraceData = stackTraceAnalyzer.analyze(astTree.body); - - assert.deepEqual(stackTraceData, expectedStackTraceData); - }); - - it('should returns correct IStackTraceData - variant #5: call expression of object member #2', () => { - astTree = Nodes.getProgramNode( - NodeUtils.convertCodeToStructure( - readFileAsString(__dirname + '/fixtures/call-expression-of-object-member-2.js') - ) - ); - - expectedStackTraceData = [ - { - name: 'baz', - callee: (getObjectFunctionExpressionByName(astTree, 'object', 'baz')).body, - stackTrace: [] - }, - { - name: 1, - callee: (getObjectFunctionExpressionByName(astTree, 'object1', 1)).body, - stackTrace: [] - }, - ]; - - stackTraceData = stackTraceAnalyzer.analyze(astTree.body); - - assert.deepEqual(stackTraceData, expectedStackTraceData); - }); - - it('should returns correct IStackTraceData - variant #6: no call expressions', () => { - astTree = Nodes.getProgramNode( - NodeUtils.convertCodeToStructure( - readFileAsString(__dirname + '/fixtures/no-call-expressions.js') - ) - ); - - expectedStackTraceData = []; - - stackTraceData = stackTraceAnalyzer.analyze(astTree.body); - - assert.deepEqual(stackTraceData, expectedStackTraceData); - }); - - it('should returns correct IStackTraceData - variant #7: only call expression', () => { - astTree = Nodes.getProgramNode( - NodeUtils.convertCodeToStructure( - readFileAsString(__dirname + '/fixtures/only-call-expression.js') - ) - ); - - expectedStackTraceData = []; - - stackTraceData = stackTraceAnalyzer.analyze(astTree.body); - - assert.deepEqual(stackTraceData, expectedStackTraceData); - }); - - it('should returns correct IStackTraceData - variant #8: self-invoking functions', () => { - astTree = Nodes.getProgramNode( - NodeUtils.convertCodeToStructure( - readFileAsString(__dirname + '/fixtures/self-invoking-functions.js') - ) - ); - - expectedStackTraceData = [ - { - name: null, - callee: (getFunctionExpressionById(astTree, 'foo')).body, - stackTrace: [{ - name: null, - callee: (getFunctionExpressionById(astTree, 'bar')).body, - stackTrace: [{ - name: null, - callee: (getFunctionExpressionById(astTree, 'baz')).body, - stackTrace: [{ + ] + }, + ] + }, + { + name: 'bar', + callee: (getObjectFunctionExpressionByName(astTree, 'object', 'bar')).body, + stackTrace: [ + { name: 'inner', callee: (getFunctionDeclarationByName(astTree, 'inner')).body, - stackTrace: [] - }] - }] - }] - } - ]; + stackTrace: [ - stackTraceData = stackTraceAnalyzer.analyze(astTree.body); + ] + }, + ] + } + ]; - assert.deepEqual(stackTraceData, expectedStackTraceData); + stackTraceData = stackTraceAnalyzer.analyze(astTree.body); + }); + + it('should return correct stack trace data', () => { + assert.deepEqual(stackTraceData, expectedStackTraceData); + }); }); - it('should returns correct IStackTraceData - variant #9: no recursion', () => { - astTree = Nodes.getProgramNode( - NodeUtils.convertCodeToStructure( - readFileAsString(__dirname + '/fixtures/no-recursion.js') - ) - ); + describe('variant #5: call expression of object member #2', () => { + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/call-expression-of-object-member-2.js'); + const astTree: TNodeWithBlockStatement = Nodes.getProgramNode( + NodeUtils.convertCodeToStructure(code) + ); - expectedStackTraceData = [ - { - name: 'bar', - callee: (getFunctionExpressionByName(astTree, 'bar')).body, - stackTrace: [] - } - ]; + expectedStackTraceData = [ + { + name: 'baz', + callee: (getObjectFunctionExpressionByName(astTree, 'object', 'baz')).body, + stackTrace: [] + }, + { + name: 1, + callee: (getObjectFunctionExpressionByName(astTree, 'object1', 1)).body, + stackTrace: [] + }, + ]; - stackTraceData = stackTraceAnalyzer.analyze(astTree.body); + stackTraceData = stackTraceAnalyzer.analyze(astTree.body); + }); - assert.deepEqual(stackTraceData, expectedStackTraceData); + it('should return correct stack trace data', () => { + assert.deepEqual(stackTraceData, expectedStackTraceData); + }); + }); + + describe('variant #6: no call expressions', () => { + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/no-call-expressions.js'); + const astTree: TNodeWithBlockStatement = Nodes.getProgramNode( + NodeUtils.convertCodeToStructure(code) + ); + + expectedStackTraceData = []; + + stackTraceData = stackTraceAnalyzer.analyze(astTree.body); + }); + + it('should return correct stack trace data', () => { + assert.deepEqual(stackTraceData, expectedStackTraceData); + }); + }); + + describe('variant #7: only call expression', () => { + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/only-call-expression.js'); + const astTree: TNodeWithBlockStatement = Nodes.getProgramNode( + NodeUtils.convertCodeToStructure(code) + ); + + expectedStackTraceData = []; + + stackTraceData = stackTraceAnalyzer.analyze(astTree.body); + }); + + it('should return correct stack trace data', () => { + assert.deepEqual(stackTraceData, expectedStackTraceData); + }); + }); + + describe('variant #8: self-invoking functions', () => { + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/self-invoking-functions.js'); + const astTree: TNodeWithBlockStatement = Nodes.getProgramNode( + NodeUtils.convertCodeToStructure(code) + ); + + expectedStackTraceData = [ + { + name: null, + callee: (getFunctionExpressionById(astTree, 'foo')).body, + stackTrace: [{ + name: null, + callee: (getFunctionExpressionById(astTree, 'bar')).body, + stackTrace: [{ + name: null, + callee: (getFunctionExpressionById(astTree, 'baz')).body, + stackTrace: [{ + name: 'inner', + callee: (getFunctionDeclarationByName(astTree, 'inner')).body, + stackTrace: [] + }] + }] + }] + } + ]; + + stackTraceData = stackTraceAnalyzer.analyze(astTree.body); + }); + + it('should return correct stack trace data', () => { + assert.deepEqual(stackTraceData, expectedStackTraceData); + }); + }); + + describe('variant #9: no recursion', () => { + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/no-recursion.js'); + const astTree: TNodeWithBlockStatement = Nodes.getProgramNode( + NodeUtils.convertCodeToStructure(code) + ); + + expectedStackTraceData = [ + { + name: 'bar', + callee: (getFunctionExpressionByName(astTree, 'bar')).body, + stackTrace: [] + } + ]; + + stackTraceData = stackTraceAnalyzer.analyze(astTree.body); + }); + + it('should return correct stack trace data', () => { + assert.deepEqual(stackTraceData, expectedStackTraceData); + }); }); }); }); diff --git a/test/functional-tests/templates/custom-nodes/domain-lock-nodes/DomainLockNodeTemplate.spec.ts b/test/functional-tests/templates/custom-nodes/domain-lock-nodes/DomainLockNodeTemplate.spec.ts index 2063917c..480da5df 100644 --- a/test/functional-tests/templates/custom-nodes/domain-lock-nodes/DomainLockNodeTemplate.spec.ts +++ b/test/functional-tests/templates/custom-nodes/domain-lock-nodes/DomainLockNodeTemplate.spec.ts @@ -13,7 +13,7 @@ import { CryptUtils } from '../../../../../src/utils/CryptUtils'; * @returns {Function} */ function getFunctionFromTemplate (templateData: any, callsControllerFunctionName: string, currentDomain: string) { - let domainLockTemplate: string = format(DomainLockNodeTemplate(), templateData); + const domainLockTemplate: string = format(DomainLockNodeTemplate(), templateData); return Function(` document = { @@ -33,57 +33,80 @@ function getFunctionFromTemplate (templateData: any, callsControllerFunctionName } describe('DomainLockNodeTemplate (): string', () => { - let domainsString: string, - currentDomain: string, - hiddenDomainsString: string, - diff: string, - singleNodeCallControllerFunctionName: string = 'callsController'; + const singleNodeCallControllerFunctionName: string = 'callsController'; - it('should correctly runs code inside template if current domain matches with `domainsString`', () => { - domainsString = ['www.example.com'].join(';'); - currentDomain = 'www.example.com'; - [ - hiddenDomainsString, - diff - ] = CryptUtils.hideString(domainsString, domainsString.length * 3); + describe('variant #1: current domain matches with `domainsString`', () => { + const domainsString: string = ['www.example.com'].join(';'); + const currentDomain: string = 'www.example.com'; - assert.doesNotThrow(() => getFunctionFromTemplate({ - domainLockFunctionName: 'domainLockFunction', - diff: diff, - domains: hiddenDomainsString, - singleNodeCallControllerFunctionName - }, singleNodeCallControllerFunctionName, currentDomain)); + let testFunc: () => void; + + before(() => { + const [ + hiddenDomainsString, + diff + ] = CryptUtils.hideString(domainsString, domainsString.length * 3); + + testFunc = () => getFunctionFromTemplate({ + domainLockFunctionName: 'domainLockFunction', + diff: diff, + domains: hiddenDomainsString, + singleNodeCallControllerFunctionName + }, singleNodeCallControllerFunctionName, currentDomain); + }); + + it('should correctly runs code inside template', () => { + assert.doesNotThrow(testFunc); + }); }); - it('should correctly runs code inside template if current domain matches with base domain of `domainsString` item', () => { - domainsString = ['www.test.com', '.example.com'].join(';'); - currentDomain = 'subdomain.example.com'; - [ - hiddenDomainsString, - diff - ] = CryptUtils.hideString(domainsString, domainsString.length * 3); + describe('variant #2: urrent domain matches with base domain of `domainsString` item', () => { + const domainsString: string = ['www.test.com', '.example.com'].join(';'); + const currentDomain: string = 'subdomain.example.com'; - assert.doesNotThrow(() => getFunctionFromTemplate({ - domainLockFunctionName: 'domainLockFunction', - diff: diff, - domains: hiddenDomainsString, - singleNodeCallControllerFunctionName - }, singleNodeCallControllerFunctionName, currentDomain)); + let testFunc: () => void; + + before(() => { + const [ + hiddenDomainsString, + diff + ] = CryptUtils.hideString(domainsString, domainsString.length * 3); + + testFunc = () => getFunctionFromTemplate({ + domainLockFunctionName: 'domainLockFunction', + diff: diff, + domains: hiddenDomainsString, + singleNodeCallControllerFunctionName + }, singleNodeCallControllerFunctionName, currentDomain); + }); + + it('should correctly runs code inside template', () => { + assert.doesNotThrow(testFunc); + }); }); - it('should throw an error if current domain doesn\'t match with `domainsString`', () => { - domainsString = ['www.example.com'].join(';'); - currentDomain = 'www.test.com'; - [ - hiddenDomainsString, - diff - ] = CryptUtils.hideString(domainsString, domainsString.length * 3); + describe('variant #3: current domain doesn\'t match with `domainsString`', () => { + const domainsString: string = ['www.example.com'].join(';'); + const currentDomain: string = 'www.test.com'; - assert.throws(() => getFunctionFromTemplate({ - domainLockFunctionName: 'domainLockFunction', - diff: diff, - domains: hiddenDomainsString, - singleNodeCallControllerFunctionName - }, singleNodeCallControllerFunctionName, currentDomain)); + let testFunc: () => void; + + before(() => { + const [ + hiddenDomainsString, + diff + ] = CryptUtils.hideString(domainsString, domainsString.length * 3); + + testFunc = () => getFunctionFromTemplate({ + domainLockFunctionName: 'domainLockFunction', + diff: diff, + domains: hiddenDomainsString, + singleNodeCallControllerFunctionName + }, singleNodeCallControllerFunctionName, currentDomain); + }); + + it('should throw an error', () => { + assert.throws(testFunc); + }); }); }); diff --git a/test/functional-tests/templates/custom-nodes/string-array-nodes/StringArrayCallsWrapperNodeTemplate.spec.ts b/test/functional-tests/templates/custom-nodes/string-array-nodes/StringArrayCallsWrapperNodeTemplate.spec.ts index e77cda34..5f0ffbd7 100644 --- a/test/functional-tests/templates/custom-nodes/string-array-nodes/StringArrayCallsWrapperNodeTemplate.spec.ts +++ b/test/functional-tests/templates/custom-nodes/string-array-nodes/StringArrayCallsWrapperNodeTemplate.spec.ts @@ -23,7 +23,7 @@ function getFunctionFromTemplateBase64Encoding ( stringArrayCallsWrapperName: string, index: string ) { - let stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), templateData); + const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), templateData); return Function(` var ${stringArrayName} = ['${CryptUtils.btoa('test1')}']; @@ -49,7 +49,7 @@ function getFunctionFromTemplateRc4Encoding ( index: string, key: string ) { - let stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), templateData); + const stringArrayCallsWrapperTemplate: string = format(StringArrayCallsWrapperTemplate(), templateData); return Function(` var ${stringArrayName} = ['${CryptUtils.btoa(CryptUtils.rc4('test1', key))}']; @@ -61,33 +61,56 @@ function getFunctionFromTemplateRc4Encoding ( } describe('StringArrayCallsWrapperNodeTemplate (): string', () => { - let stringArrayName: string = 'stringArrayName', - stringArrayCallsWrapperName: string = 'stringArrayCallsWrapperName', - atobDecodeNodeTemplate: string = format(StringArrayBase64DecodeNodeTemplate(), { + const stringArrayName: string = 'stringArrayName'; + const stringArrayCallsWrapperName: string = 'stringArrayCallsWrapperName'; + + describe('variant #1: `base64` encoding', () => { + const atobDecodeNodeTemplate: string = format(StringArrayBase64DecodeNodeTemplate(), { atobPolyfill: AtobTemplate(), selfDefendingCode: '', stringArrayCallsWrapperName - }), - rc4DecodeNodeTemplate: string = format(StringArrayRc4DecodeNodeTemplate(), { + }); + const index: string = '0x0'; + const expectedDecodedValue: string = 'test1'; + + let decodedValue: string; + + before(() => { + decodedValue = getFunctionFromTemplateBase64Encoding({ + decodeNodeTemplate: atobDecodeNodeTemplate, + stringArrayCallsWrapperName, + stringArrayName + }, stringArrayName, stringArrayCallsWrapperName, index); + }); + + it('should correctly return decoded value', () => { + assert.deepEqual(decodedValue, expectedDecodedValue); + }); + }); + + describe('variant #2: `rc4` encoding', () => { + const rc4DecodeNodeTemplate: string = format(StringArrayRc4DecodeNodeTemplate(), { atobPolyfill: AtobTemplate(), rc4Polyfill: Rc4Template(), selfDefendingCode: '', stringArrayCallsWrapperName }); + const index: string = '0x0'; + const key: string = 'key'; + const expectedDecodedValue: string = 'test1'; - it('should correctly returns decoded value with base64 encoding', () => { - assert.deepEqual(getFunctionFromTemplateBase64Encoding({ - decodeNodeTemplate: atobDecodeNodeTemplate, - stringArrayCallsWrapperName, - stringArrayName - }, stringArrayName, stringArrayCallsWrapperName, '0x0'), 'test1'); - }); + let decodedValue: string; - it('should correctly returns decoded value with rc4 encoding', () => { - assert.deepEqual(getFunctionFromTemplateRc4Encoding({ - decodeNodeTemplate: rc4DecodeNodeTemplate, - stringArrayCallsWrapperName, - stringArrayName - }, stringArrayName, stringArrayCallsWrapperName, '0x0', 'key'), 'test1'); + before(() => { + decodedValue = getFunctionFromTemplateRc4Encoding({ + decodeNodeTemplate: rc4DecodeNodeTemplate, + stringArrayCallsWrapperName, + stringArrayName + }, stringArrayName, stringArrayCallsWrapperName, index, key); + }); + + it('should correctly return decoded value', () => { + assert.deepEqual(decodedValue, expectedDecodedValue); + }); }); }); diff --git a/test/performance-tests/JavaScriptObfuscatorPerformance.spec.ts b/test/performance-tests/JavaScriptObfuscatorPerformance.spec.ts index 73f565b2..af76b56a 100644 --- a/test/performance-tests/JavaScriptObfuscatorPerformance.spec.ts +++ b/test/performance-tests/JavaScriptObfuscatorPerformance.spec.ts @@ -4,13 +4,13 @@ import { readFileAsString } from '../helpers/readFileAsString'; import { JavaScriptObfuscator } from '../../src/JavaScriptObfuscator'; -describe('JavaScriptObfuscator performance', () => { +describe('JavaScriptObfuscator performance', function () { const iterationsCount: number = 500; - describe('performance: multiple calls', () => { - it('shows performance time with multiple obfuscator calls', function (): void { - this.timeout(100000); + this.timeout(100000); + describe('performance: multiple calls', () => { + it('shows performance time with multiple obfuscator calls', () => { for (let i: number = 0; i < iterationsCount; i++) { JavaScriptObfuscator.obfuscate(readFileAsString('./test/fixtures/sample.js')); } @@ -20,9 +20,7 @@ describe('JavaScriptObfuscator performance', () => { }); describe('performance: large source code', () => { - it('shows performance time with large code size', function (): void { - this.timeout(100000); - + it('shows performance time with large code size', () => { JavaScriptObfuscator.obfuscate(readFileAsString('./test/fixtures/sample.js').repeat(iterationsCount)); assert.isOk(true); diff --git a/test/runtime-tests/JavaScriptObfuscatorRuntime.spec.ts b/test/runtime-tests/JavaScriptObfuscatorRuntime.spec.ts index b4f38865..137e646d 100644 --- a/test/runtime-tests/JavaScriptObfuscatorRuntime.spec.ts +++ b/test/runtime-tests/JavaScriptObfuscatorRuntime.spec.ts @@ -6,11 +6,14 @@ import { readFileAsString } from '../helpers/readFileAsString'; import { JavaScriptObfuscator } from '../../src/JavaScriptObfuscator'; -describe('JavaScriptObfuscator runtime eval', () => { - it('should obfuscate code without any runtime errors after obfuscation: variant #1 sha256', () => { - const code: string = readFileAsString(__dirname + '/fixtures/sha256.js'); +describe('JavaScriptObfuscator runtime eval', function () { + this.timeout(100000); - const obfuscationResult1: IObfuscationResult = JavaScriptObfuscator.obfuscate( + let obfuscatedCode: string; + + before(() => { + const code: string = readFileAsString(__dirname + '/fixtures/sha256.js'); + const obfuscationResult: IObfuscationResult = JavaScriptObfuscator.obfuscate( code, { controlFlowFlattening: true, @@ -21,8 +24,12 @@ describe('JavaScriptObfuscator runtime eval', () => { } ); + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('should obfuscate code without any runtime errors after obfuscation: variant #1 sha256', () => { assert.equal( - eval(`${obfuscationResult1.getObfuscatedCode()} sha256('test');`), + eval(`${obfuscatedCode} sha256('test');`), '9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08' ); }); diff --git a/test/unit-tests/cli/cli-utils/CLIUtils.spec.ts b/test/unit-tests/cli/cli-utils/CLIUtils.spec.ts index d8a40a0a..ef95e5e7 100644 --- a/test/unit-tests/cli/cli-utils/CLIUtils.spec.ts +++ b/test/unit-tests/cli/cli-utils/CLIUtils.spec.ts @@ -3,11 +3,11 @@ import * as mkdirp from 'mkdirp'; import { assert } from 'chai'; -import { CLIUtils } from '../../../../src/cli/CLIUtils'; +import { CLIUtils } from '../../../../src/cli/utils/CLIUtils'; describe('CLIUtils', () => { - const fileContent: string = 'test', - tmpDir: string = 'test/tmp'; + const fileContent: string = 'test'; + const tmpDir: string = 'test/tmp'; before(() => { mkdirp.sync(tmpDir); @@ -37,41 +37,57 @@ describe('CLIUtils', () => { }); describe('getPackageConfig (): IPackageConfig', () => { - it('should return `package.json` content for current CLI program as object', () => { + it('should return `package.json` `name` field for current CLI program as object', () => { assert.property(CLIUtils.getPackageConfig(), 'name'); + }); + + it('should return `package.json` `version` field for current CLI program as object', () => { assert.property(CLIUtils.getPackageConfig(), 'version'); }); }); describe('validateInputPath (inputPath: string): void', () => { - let inputPath: string, - tmpFileName: string; + describe('`inputPath` is a valid path', () => { + const tmpFileName: string = 'test.js'; + const inputPath: string = `${tmpDir}/${tmpFileName}`; - it('shouldn\'t throw an error if `inputPath` is a valid path', () => { - tmpFileName = 'test.js'; - inputPath = `${tmpDir}/${tmpFileName}`; - fs.writeFileSync(inputPath, fileContent); + before(() => { + fs.writeFileSync(inputPath, fileContent); + }); - assert.doesNotThrow(() => CLIUtils.validateInputPath(inputPath), ReferenceError); + it('shouldn\'t throw an error if `inputPath` is a valid path', () => { + assert.doesNotThrow(() => CLIUtils.validateInputPath(inputPath), ReferenceError); + }); - fs.unlinkSync(inputPath); + after(() => { + fs.unlinkSync(inputPath); + }); }); - it('should throw an error if `inputPath` is not a valid path', () => { - tmpFileName = 'test.js'; - inputPath = `${tmpDir}/${tmpFileName}`; + describe('`inputPath` is not a valid path', () => { + const tmpFileName: string = 'test.js'; + const inputPath: string = `${tmpDir}/${tmpFileName}`; - assert.throws(() => CLIUtils.validateInputPath(inputPath), ReferenceError); + it('should throw an error if `inputPath` is not a valid path', () => { + assert.throws(() => CLIUtils.validateInputPath(inputPath), ReferenceError); + }); }); - it('should throw an error if `inputPath` is a file name has invalid extension', () => { - tmpFileName = 'test.ts'; - inputPath = `${tmpDir}/${tmpFileName}`; - fs.writeFileSync(inputPath, fileContent); + describe('`inputPath` is a file name has invalid extension', () => { + const tmpFileName: string = 'test.ts'; + const inputPath: string = `${tmpDir}/${tmpFileName}`; - assert.throws(() => CLIUtils.validateInputPath(inputPath), ReferenceError); + before(() => { + fs.writeFileSync(inputPath, fileContent); + }); - fs.unlinkSync(inputPath); + it('should throw an error if `inputPath` is a file name has invalid extension', () => { + assert.throws(() => CLIUtils.validateInputPath(inputPath), ReferenceError); + }); + + after(() => { + fs.unlinkSync(inputPath); + }); }); }); diff --git a/test/unit-tests/decorators/initializable/Initializable.spec.ts b/test/unit-tests/decorators/initializable/Initializable.spec.ts index 7f3a8c43..99b7011b 100644 --- a/test/unit-tests/decorators/initializable/Initializable.spec.ts +++ b/test/unit-tests/decorators/initializable/Initializable.spec.ts @@ -5,8 +5,8 @@ import { IInitializable } from '../../../../src/interfaces/IInitializable'; describe('@initializable', () => { describe('initializable (initializeMethodKey: string): any', () => { - it('shouldn\'t throws an errors if property was initialized', () => { - assert.doesNotThrow(() => { + describe('variant #1: property was initialized', () => { + const testFunc: () => void = () => { class Foo implements IInitializable { @initializable() public property: string; @@ -21,11 +21,15 @@ describe('@initializable', () => { foo.initialize('baz'); foo.property; - }, Error); + }; + + it('shouldn\'t throws an errors if property was initialized', () => { + assert.doesNotThrow(testFunc, Error); + }); }); - it('shouldn\'t throws an errors if custom initialization method name is passed', () => { - assert.doesNotThrow(() => { + describe('variant #2: custom initialization method name is passed', () => { + const testFunc: () => void = () => { class Foo implements IInitializable { @initializable() public property: string; @@ -43,11 +47,15 @@ describe('@initializable', () => { foo.bar('baz'); foo.property; - }, Error); + }; + + it('shouldn\'t throws an errors if custom initialization method name is passed', () => { + assert.doesNotThrow(testFunc, Error); + }); }); - it('should throws an error if property didn\'t initialized', () => { - assert.throws(() => { + describe('variant #3: property didn\'t initialized', () => { + const testFunc: () => void = () => { class Foo implements IInitializable { @initializable() public property: string; @@ -61,11 +69,15 @@ describe('@initializable', () => { foo.initialize('baz'); foo.property; - }, /Property `property` is not initialized/); + }; + + it('should throws an error if property didn\'t initialized', () => { + assert.throws(testFunc, /Property `property` is not initialized/); + }); }); - it('should throws an error if `initialize` method with custom name wasn\'t found', () => { - assert.throws(() => { + describe('variant #4: `initialize` method with custom name', () => { + const testFunc: () => void = () => { class Foo { @initializable('bar') public property: string; @@ -80,7 +92,11 @@ describe('@initializable', () => { foo.initialize('baz'); foo.property; - }, /method with initialization logic not found/); + }; + + it('should throws an error if `initialize` method with custom name wasn\'t found', () => { + assert.throws(testFunc, /method with initialization logic not found/); + }); }); }); }); diff --git a/test/unit-tests/node/node-appender/NodeAppender.spec.ts b/test/unit-tests/node/node-appender/NodeAppender.spec.ts index 817fe87b..b24f79b4 100644 --- a/test/unit-tests/node/node-appender/NodeAppender.spec.ts +++ b/test/unit-tests/node/node-appender/NodeAppender.spec.ts @@ -17,28 +17,34 @@ import { NodeAppender } from '../../../../src/node/NodeAppender'; import { Nodes } from '../../../../src/node/Nodes'; import { NodeUtils } from '../../../../src/node/NodeUtils'; +/** + * @param fixturePath + * @return {TStatement[]} + */ +const convertCodeToStructure: (fixturePath: string) => TStatement[] = (fixturePath) => { + return NodeUtils.convertCodeToStructure( + readFileAsString(`${__dirname}${fixturePath}`) + ); +}; + +/** + * @param fixturePath + * @return {ESTree.Program} + */ +const convertCodeToAst: (fixturePath: string) => ESTree.Program = (fixturePath) => { + return Nodes.getProgramNode(convertCodeToStructure(fixturePath)); +}; + describe('NodeAppender', () => { describe('appendNode (blockScopeNode: TNodeWithBlockStatement[], nodeBodyStatements: TStatement[]): void', () => { let astTree: ESTree.Program, expectedAstTree: ESTree.Program, node: TStatement[]; - beforeEach(() => { - node = NodeUtils.convertCodeToStructure( - readFileAsString(__dirname + '/fixtures/simple-input.js') - ); - - astTree = Nodes.getProgramNode( - NodeUtils.convertCodeToStructure( - readFileAsString(__dirname + '/fixtures/append-node.js') - ) - ); - - expectedAstTree = Nodes.getProgramNode( - NodeUtils.convertCodeToStructure( - readFileAsString(__dirname + '/fixtures/append-node-expected.js') - ) - ); + before(() => { + node = convertCodeToStructure('/fixtures/simple-input.js'); + astTree = convertCodeToAst('/fixtures/append-node.js'); + expectedAstTree = convertCodeToAst('/fixtures/append-node-expected.js'); astTree = NodeUtils.parentize(astTree); expectedAstTree = NodeUtils.parentize(expectedAstTree); @@ -62,116 +68,97 @@ describe('NodeAppender', () => { stackTraceData: IStackTraceData[]; beforeEach(() => { - node = NodeUtils.convertCodeToStructure( - readFileAsString(__dirname + '/fixtures/simple-input.js') - ); + node = convertCodeToStructure('/fixtures/simple-input.js'); }); - it('should append node into first and deepest function call in calls trace - variant #1', () => { - astTree = Nodes.getProgramNode( - NodeUtils.convertCodeToStructure( - readFileAsString(__dirname + '/fixtures/append-node-to-optimal-block-scope/variant-1.js') - ) - ); + describe('variant #1: nested function calls', () => { + beforeEach(() => { + astTree = convertCodeToAst('/fixtures/append-node-to-optimal-block-scope/variant-1.js'); + expectedAstTree = convertCodeToAst('/fixtures/append-node-to-optimal-block-scope/variant-1-expected.js'); - expectedAstTree = Nodes.getProgramNode( - NodeUtils.convertCodeToStructure( - readFileAsString(__dirname + '/fixtures/append-node-to-optimal-block-scope/variant-1-expected.js') - ) - ); + stackTraceData = stackTraceAnalyzer.analyze(astTree.body); + NodeAppender.appendNodeToOptimalBlockScope(stackTraceData, astTree, node); + }); - stackTraceData = stackTraceAnalyzer.analyze(astTree.body); - NodeAppender.appendNodeToOptimalBlockScope(stackTraceData, astTree, node); - - assert.deepEqual(astTree, expectedAstTree); + it('should append node into first and deepest function call in nested function calls', () => { + assert.deepEqual(astTree, expectedAstTree); + }); }); - it('should append node into first and deepest function call in calls trace - variant #2', () => { - astTree = Nodes.getProgramNode( - NodeUtils.convertCodeToStructure( - readFileAsString(__dirname + '/fixtures/append-node-to-optimal-block-scope/variant-2.js') - ) - ); + describe('variant #2: nested function calls', () => { + beforeEach(() => { + astTree = convertCodeToAst('/fixtures/append-node-to-optimal-block-scope/variant-2.js'); + expectedAstTree = convertCodeToAst('/fixtures/append-node-to-optimal-block-scope/variant-2-expected.js'); - expectedAstTree = Nodes.getProgramNode( - NodeUtils.convertCodeToStructure( - readFileAsString(__dirname + '/fixtures/append-node-to-optimal-block-scope/variant-2-expected.js') - ) - ); + stackTraceData = stackTraceAnalyzer.analyze(astTree.body); + NodeAppender.appendNodeToOptimalBlockScope(stackTraceData, astTree, node); - stackTraceData = stackTraceAnalyzer.analyze(astTree.body); - NodeAppender.appendNodeToOptimalBlockScope(stackTraceData, astTree, node); + }); - assert.deepEqual(astTree, expectedAstTree); + it('should append node into first and deepest function call in nested function calls', () => { + assert.deepEqual(astTree, expectedAstTree); + }); }); describe('append by specific index', () => { let astTree: ESTree.Program; beforeEach(() => { - astTree = Nodes.getProgramNode( - NodeUtils.convertCodeToStructure( - readFileAsString(__dirname + '/fixtures/append-node-to-optimal-block-scope/by-index.js') - - ) - ); + astTree = convertCodeToAst('/fixtures/append-node-to-optimal-block-scope/by-index.js'); }); - it('should append node into deepest function call by specified index in calls trace - variant #1', () => { - expectedAstTree = Nodes.getProgramNode( - NodeUtils.convertCodeToStructure( - readFileAsString(__dirname + '/fixtures/append-node-to-optimal-block-scope/by-index-variant-1-expected.js') + describe('variant #1: append by specific index in nested function calls', () => { + beforeEach(() => { + expectedAstTree = convertCodeToAst('/fixtures/append-node-to-optimal-block-scope/by-index-variant-1-expected.js'); - ) - ); + stackTraceData = stackTraceAnalyzer.analyze(astTree.body); + NodeAppender.appendNodeToOptimalBlockScope(stackTraceData, astTree, node, 2); - stackTraceData = stackTraceAnalyzer.analyze(astTree.body); - NodeAppender.appendNodeToOptimalBlockScope(stackTraceData, astTree, node, 2); + }); - assert.deepEqual(astTree, expectedAstTree); + it('should append node into deepest function call by specified index in nested function calls', () => { + assert.deepEqual(astTree, expectedAstTree); + }); }); - it('should append node into deepest function call by specified index in calls trace - variant #2', () => { - expectedAstTree = Nodes.getProgramNode( - NodeUtils.convertCodeToStructure( - readFileAsString(__dirname + '/fixtures/append-node-to-optimal-block-scope/by-index-variant-2-expected.js') + describe('variant #2: append by specific index in nested function calls', () => { + beforeEach(() => { + expectedAstTree = convertCodeToAst('/fixtures/append-node-to-optimal-block-scope/by-index-variant-2-expected.js'); - ) - ); + stackTraceData = stackTraceAnalyzer.analyze(astTree.body); + NodeAppender.appendNodeToOptimalBlockScope(stackTraceData, astTree, node, 1); - stackTraceData = stackTraceAnalyzer.analyze(astTree.body); - NodeAppender.appendNodeToOptimalBlockScope(stackTraceData, astTree, node, 1); + }); - assert.deepEqual(astTree, expectedAstTree); + it('should append node into deepest function call by specified index in nested function calls', () => { + assert.deepEqual(astTree, expectedAstTree); + }); }); - it('should append node into deepest function call by specified index in calls trace - variant #3', () => { - astTree = Nodes.getProgramNode( - NodeUtils.convertCodeToStructure( - readFileAsString(__dirname + '/fixtures/append-node-to-optimal-block-scope/by-index-variant-3.js') - ) - ); - expectedAstTree = Nodes.getProgramNode( - NodeUtils.convertCodeToStructure( - readFileAsString(__dirname + '/fixtures/append-node-to-optimal-block-scope/by-index-variant-3-expected.js') - ) - ); + describe('variant #3: append by specific index in nested function calls', () => { + beforeEach(() => { + astTree = convertCodeToAst('/fixtures/append-node-to-optimal-block-scope/by-index-variant-3.js'); + expectedAstTree = convertCodeToAst('/fixtures/append-node-to-optimal-block-scope/by-index-variant-3-expected.js'); - stackTraceData = stackTraceAnalyzer.analyze(astTree.body); - NodeAppender.appendNodeToOptimalBlockScope( - stackTraceData, - astTree, - node, - NodeAppender.getRandomStackTraceIndex(stackTraceData.length) - ); + stackTraceData = stackTraceAnalyzer.analyze(astTree.body); + NodeAppender.appendNodeToOptimalBlockScope( + stackTraceData, + astTree, + node, + NodeAppender.getRandomStackTraceIndex(stackTraceData.length) + ); - assert.deepEqual(astTree, expectedAstTree); + }); + + it('should append node into deepest function call by specified index in nested function calls', () => { + assert.deepEqual(astTree, expectedAstTree); + }); }); }); }); describe('getRandomStackTraceIndex (stackTraceRootLength: number): number', () => { - it('should returns random index between 0 and stack trace data root length', () => { + it('should return random index between 0 and stack trace data root length', () => { let index: number; for (let i: number = 0; i < 100; i++) { @@ -188,22 +175,10 @@ describe('NodeAppender', () => { expectedAstTree: ESTree.Program, node: TStatement[]; - beforeEach(() => { - node = NodeUtils.convertCodeToStructure( - readFileAsString(__dirname + '/fixtures/simple-input.js') - ); - - astTree = Nodes.getProgramNode( - NodeUtils.convertCodeToStructure( - readFileAsString(__dirname + '/fixtures/insert-node-at-index.js') - ) - ); - - expectedAstTree = Nodes.getProgramNode( - NodeUtils.convertCodeToStructure( - readFileAsString(__dirname + '/fixtures/insert-node-at-index-expected.js') - ) - ); + before(() => { + node = convertCodeToStructure('/fixtures/simple-input.js'); + astTree = convertCodeToAst('/fixtures/insert-node-at-index.js'); + expectedAstTree = convertCodeToAst('/fixtures/insert-node-at-index-expected.js'); astTree = NodeUtils.parentize(astTree); expectedAstTree = NodeUtils.parentize(expectedAstTree); @@ -221,22 +196,10 @@ describe('NodeAppender', () => { expectedAstTree: ESTree.Program, node: TStatement[]; - beforeEach(() => { - node = NodeUtils.convertCodeToStructure( - readFileAsString(__dirname + '/fixtures/simple-input.js') - ); - - astTree = Nodes.getProgramNode( - NodeUtils.convertCodeToStructure( - readFileAsString(__dirname + '/fixtures/prepend-node.js') - ) - ); - - expectedAstTree = Nodes.getProgramNode( - NodeUtils.convertCodeToStructure( - readFileAsString(__dirname + '/fixtures/prepend-node-expected.js') - ) - ); + before(() => { + node = convertCodeToStructure('/fixtures/simple-input.js'); + astTree = convertCodeToAst('/fixtures/prepend-node.js'); + expectedAstTree = convertCodeToAst('/fixtures/prepend-node-expected.js'); astTree = NodeUtils.parentize(astTree); expectedAstTree = NodeUtils.parentize(expectedAstTree); diff --git a/test/unit-tests/node/node-utils/NodeUtils.spec.ts b/test/unit-tests/node/node-utils/NodeUtils.spec.ts index 06698ba4..847abeee 100644 --- a/test/unit-tests/node/node-utils/NodeUtils.spec.ts +++ b/test/unit-tests/node/node-utils/NodeUtils.spec.ts @@ -2,6 +2,8 @@ import * as ESTree from 'estree'; import { assert } from 'chai'; +import { TStatement } from '../../../../src/types/node/TStatement'; + import { Nodes } from '../../../../src/node/Nodes'; import { NodeUtils } from '../../../../src/node/NodeUtils'; @@ -10,7 +12,7 @@ describe('NodeUtils', () => { let literalNode: any, expectedLiteralNode: any; - beforeEach(() => { + before(() => { literalNode = Nodes.getLiteralNode('value'); delete literalNode['x-verbatim-property']; @@ -25,86 +27,71 @@ describe('NodeUtils', () => { }); describe('clone (astTree: T): T', () => { - let ifStatementNode1: ESTree.IfStatement, - ifStatementNode2: ESTree.IfStatement, - ifStatementBlockStatementNode1: ESTree.BlockStatement, - ifStatementBlockStatementNode2: ESTree.BlockStatement, - expressionStatementNode1: ESTree.ExpressionStatement, - expressionStatementNode2: ESTree.ExpressionStatement, - expressionStatementNode3: ESTree.ExpressionStatement, - expressionStatementNode4: ESTree.ExpressionStatement, - programNode1: ESTree.Program, - programNode2: ESTree.Program; + let programNode: ESTree.Program, + expectedProgramNode: ESTree.Program; - beforeEach(() => { + before(() => { // actual AST tree - expressionStatementNode1 = Nodes.getExpressionStatementNode(Nodes.getIdentifierNode('identifier')); - expressionStatementNode2 = Nodes.getExpressionStatementNode(Nodes.getIdentifierNode('identifier')); + const expressionStatementNode1: ESTree.ExpressionStatement = Nodes.getExpressionStatementNode(Nodes.getIdentifierNode('identifier')); + const expressionStatementNode2: ESTree.ExpressionStatement = Nodes.getExpressionStatementNode(Nodes.getIdentifierNode('identifier')); - ifStatementBlockStatementNode1 = Nodes.getBlockStatementNode([ + const ifStatementBlockStatementNode1: ESTree.BlockStatement = Nodes.getBlockStatementNode([ expressionStatementNode1, expressionStatementNode2 ]); - ifStatementNode1 = Nodes.getIfStatementNode( + const ifStatementNode1: ESTree.IfStatement = Nodes.getIfStatementNode( Nodes.getLiteralNode(true), ifStatementBlockStatementNode1 ); - programNode1 = Nodes.getProgramNode([ - ifStatementNode1 - ]); - // expected AST tree - expressionStatementNode3 = Nodes.getExpressionStatementNode(Nodes.getIdentifierNode('identifier')); - expressionStatementNode4 = Nodes.getExpressionStatementNode(Nodes.getIdentifierNode('identifier')); + const expressionStatementNode3: ESTree.ExpressionStatement = Nodes.getExpressionStatementNode(Nodes.getIdentifierNode('identifier')); + const expressionStatementNode4: ESTree.ExpressionStatement = Nodes.getExpressionStatementNode(Nodes.getIdentifierNode('identifier')); - ifStatementBlockStatementNode2 = Nodes.getBlockStatementNode([ + const ifStatementBlockStatementNode2: ESTree.BlockStatement = Nodes.getBlockStatementNode([ expressionStatementNode3, expressionStatementNode4 ]); - ifStatementNode2 = Nodes.getIfStatementNode( + const ifStatementNode2: ESTree.IfStatement = Nodes.getIfStatementNode( Nodes.getLiteralNode(true), ifStatementBlockStatementNode2 ); - programNode2 = Nodes.getProgramNode([ - ifStatementNode2 - ]); - - programNode2 = NodeUtils.parentize(programNode2); + programNode = NodeUtils.clone( + Nodes.getProgramNode([ + ifStatementNode1 + ]) + ); + expectedProgramNode = NodeUtils.parentize( + Nodes.getProgramNode([ + ifStatementNode2 + ]) + ); }); it('should clone given AST-tree', () => { - assert.deepEqual(NodeUtils.clone(programNode1), programNode2); + assert.deepEqual(programNode, expectedProgramNode); }); }); describe('convertCodeToStructure (code: string): ESTree.Node[]', () => { - let code: string, - identifierNode: ESTree.Identifier, - literalNode: ESTree.Literal, - programNode: ESTree.Program, - variableDeclarationNode: ESTree.VariableDeclaration, - variableDeclaratorNode: ESTree.VariableDeclarator; + let structure: TStatement[], + expectedStructure: TStatement[]; - beforeEach(() => { - code = ` + before(() => { + const code: string = ` var abc = 'cde'; `; - identifierNode = Nodes.getIdentifierNode('abc'); - - literalNode = Nodes.getLiteralNode('cde'); - - variableDeclaratorNode = Nodes.getVariableDeclaratorNode(identifierNode, literalNode); - - variableDeclarationNode = Nodes.getVariableDeclarationNode([ + const identifierNode: ESTree.Identifier = Nodes.getIdentifierNode('abc'); + const literalNode: ESTree.Literal = Nodes.getLiteralNode('cde'); + const variableDeclaratorNode: ESTree.VariableDeclarator = Nodes.getVariableDeclaratorNode(identifierNode, literalNode); + const variableDeclarationNode: ESTree.VariableDeclaration = Nodes.getVariableDeclarationNode([ variableDeclaratorNode ]); - - programNode = Nodes.getProgramNode([ + const programNode: ESTree.Program = Nodes.getProgramNode([ variableDeclarationNode ]); @@ -113,10 +100,13 @@ describe('NodeUtils', () => { variableDeclaratorNode.parentNode = variableDeclarationNode; identifierNode.parentNode = variableDeclaratorNode; literalNode.parentNode = variableDeclaratorNode; + + structure = NodeUtils.convertCodeToStructure(code); + expectedStructure = [variableDeclarationNode]; }); it('should convert code to `ESTree.Node[]` structure array', () => { - assert.deepEqual(NodeUtils.convertCodeToStructure(code), [variableDeclarationNode]); + assert.deepEqual(structure, expectedStructure); }); }); @@ -124,7 +114,7 @@ describe('NodeUtils', () => { let structure: ESTree.Node[], expectedCode: string; - beforeEach(() => { + before(() => { structure = [ Nodes.getProgramNode([ Nodes.getVariableDeclarationNode([ @@ -160,6 +150,9 @@ describe('NodeUtils', () => { it('should return block-statement child node of given node if that node has block-statement', () => { assert.deepEqual(NodeUtils.getBlockStatementNodeByIndex(blockStatementNode), expressionStatementNode1); + }); + + it('should return block-statement child node of given node with index `1` if that node has block-statement', () => { assert.deepEqual(NodeUtils.getBlockStatementNodeByIndex(blockStatementNode, 1), expressionStatementNode2); }); @@ -184,7 +177,7 @@ describe('NodeUtils', () => { functionDeclarationNode: ESTree.FunctionDeclaration, programNode: ESTree.Program; - beforeEach(() => { + before(() => { expressionStatementNode1 = Nodes.getExpressionStatementNode(Nodes.getIdentifierNode('identifier')); expressionStatementNode2 = Nodes.getExpressionStatementNode(Nodes.getIdentifierNode('identifier')); expressionStatementNode3 = Nodes.getExpressionStatementNode(Nodes.getIdentifierNode('identifier')); @@ -230,19 +223,55 @@ describe('NodeUtils', () => { expressionStatementNode3.parentNode = ifStatementBlockStatementNode2; }); - it('should return block-scope node for given node', () => { + it('should return block-scope node for `program` node child', () => { assert.deepEqual(NodeUtils.getBlockScopesOfNode(programNode)[0], programNode); + }); + + it('should return block-scope node for `functionDeclaration` node child node #1', () => { assert.deepEqual(NodeUtils.getBlockScopesOfNode(functionDeclarationNode)[0], programNode); + }); + + it('should return block-scope node for `functionDeclaration blockStatement` node child node #1', () => { assert.deepEqual(NodeUtils.getBlockScopesOfNode(functionDeclarationBlockStatementNode)[0], programNode); + }); + + it('should return block-scope node for `expressionStatement` node #1 child node #1', () => { assert.deepEqual(NodeUtils.getBlockScopesOfNode(expressionStatementNode1)[0], functionDeclarationBlockStatementNode); + }); + + it('should return block-scope node for `expressionStatement` node #1 child node #2', () => { assert.deepEqual(NodeUtils.getBlockScopesOfNode(expressionStatementNode1)[1], programNode); + }); + + it('should return block-scope node for `ifStatement` node child node #1', () => { assert.deepEqual(NodeUtils.getBlockScopesOfNode(ifStatementNode1)[0], functionDeclarationBlockStatementNode); + }); + + it('should return block-scope node for `ifStatement` node child node #2', () => { assert.deepEqual(NodeUtils.getBlockScopesOfNode(ifStatementNode1)[1], programNode); + }); + + it('should return block-scope node for `ifStatement blockStatement` node #1 child node #1', () => { assert.deepEqual(NodeUtils.getBlockScopesOfNode(ifStatementBlockStatementNode1)[0], functionDeclarationBlockStatementNode); + }); + + it('should return block-scope node for `ifStatement blockStatement` node #1 child node #2', () => { assert.deepEqual(NodeUtils.getBlockScopesOfNode(ifStatementBlockStatementNode1)[1], programNode); + }); + + it('should return block-scope node for `ifStatement blockStatement` node #2 child node #1', () => { assert.deepEqual(NodeUtils.getBlockScopesOfNode(ifStatementBlockStatementNode2)[0], functionDeclarationBlockStatementNode); + }); + + it('should return block-scope node for `ifStatement blockStatement` node #1 child node #2', () => { assert.deepEqual(NodeUtils.getBlockScopesOfNode(ifStatementBlockStatementNode2)[1], programNode); + }); + + it('should return block-scope node for `expressionStatement` node #3 child node #1', () => { assert.deepEqual(NodeUtils.getBlockScopesOfNode(expressionStatementNode3)[0], functionDeclarationBlockStatementNode); + }); + + it('should return block-scope node for `expressionStatement` node #3 child node #2', () => { assert.deepEqual(NodeUtils.getBlockScopesOfNode(expressionStatementNode3)[1], programNode); }); @@ -265,7 +294,7 @@ describe('NodeUtils', () => { functionDeclarationNode2: ESTree.FunctionDeclaration, programNode: ESTree.Program; - beforeEach(() => { + before(() => { expressionStatementNode1 = Nodes.getExpressionStatementNode(Nodes.getIdentifierNode('identifier')); expressionStatementNode2 = Nodes.getExpressionStatementNode(Nodes.getIdentifierNode('identifier')); expressionStatementNode3 = Nodes.getExpressionStatementNode(Nodes.getIdentifierNode('identifier')); @@ -319,17 +348,47 @@ describe('NodeUtils', () => { ifStatementBlockStatementNode2.parentNode = ifStatementNode2; }); - it('should return block-scope depth for given node', () => { + it('should return block-scope depth for `program` node', () => { assert.deepEqual(NodeUtils.getNodeBlockScopeDepth(programNode), 0); + }); + + it('should return block-scope depth for `functionDeclaration` node #1', () => { assert.deepEqual(NodeUtils.getNodeBlockScopeDepth(functionDeclarationNode1), 0); + }); + + it('should return block-scope depth for `functionDeclaration blockStatement` node #1', () => { assert.deepEqual(NodeUtils.getNodeBlockScopeDepth(functionDeclarationBlockStatementNode1), 1); + }); + + it('should return block-scope depth for `expressionStatement` node #1', () => { assert.deepEqual(NodeUtils.getNodeBlockScopeDepth(expressionStatementNode1), 1); + }); + + it('should return block-scope depth for `ifStatement` node #1', () => { assert.deepEqual(NodeUtils.getNodeBlockScopeDepth(ifStatementNode1), 1); + }); + + it('should return block-scope depth for `ifStatement blockStatement` node #1', () => { assert.deepEqual(NodeUtils.getNodeBlockScopeDepth(ifStatementBlockStatementNode1), 1); + }); + + it('should return block-scope depth for `functionDeclaration` node #2', () => { assert.deepEqual(NodeUtils.getNodeBlockScopeDepth(functionDeclarationNode2), 1); + }); + + it('should return block-scope depth for `functionDeclaration blockStatement` node #2', () => { assert.deepEqual(NodeUtils.getNodeBlockScopeDepth(functionDeclarationBlockStatementNode2), 2); + }); + + it('should return block-scope depth for `expressionStatement` node #2', () => { assert.deepEqual(NodeUtils.getNodeBlockScopeDepth(expressionStatementNode2), 2); + }); + + it('should return block-scope depth for `ifStatement` node #2', () => { assert.deepEqual(NodeUtils.getNodeBlockScopeDepth(ifStatementNode2), 2); + }); + + it('should return block-scope depth for `ifStatement blockStatement` node #2', () => { assert.deepEqual(NodeUtils.getNodeBlockScopeDepth(ifStatementBlockStatementNode2), 2); }); @@ -339,18 +398,15 @@ describe('NodeUtils', () => { }); describe('getUnaryExpressionArgumentNode (unaryExpressionNode: ESTree.UnaryExpression): ESTree.Node', () => { - let expressionStatementNode: ESTree.ExpressionStatement, - literalNode: ESTree.Literal, - unaryExpressionNode1: ESTree.UnaryExpression, - unaryExpressionNode2: ESTree.UnaryExpression, - programNode: ESTree.Program; + let expectedNode: ESTree.Literal, + unaryExpressionArgumentNode: ESTree.Node; - beforeEach(() => { - literalNode = Nodes.getLiteralNode('test'); - unaryExpressionNode2 = Nodes.getUnaryExpressionNode('!', literalNode) - unaryExpressionNode1 = Nodes.getUnaryExpressionNode('!', unaryExpressionNode2) - expressionStatementNode = Nodes.getExpressionStatementNode(unaryExpressionNode1); - programNode = Nodes.getProgramNode([ + before(() => { + const literalNode: ESTree.Literal = Nodes.getLiteralNode('test'); + const unaryExpressionNode2: ESTree.UnaryExpression = Nodes.getUnaryExpressionNode('!', literalNode); + const unaryExpressionNode1: ESTree.UnaryExpression = Nodes.getUnaryExpressionNode('!', unaryExpressionNode2); + const expressionStatementNode: ESTree.ExpressionStatement = Nodes.getExpressionStatementNode(unaryExpressionNode1); + const programNode: ESTree.Program = Nodes.getProgramNode([ expressionStatementNode ]); @@ -359,10 +415,13 @@ describe('NodeUtils', () => { unaryExpressionNode1.parentNode = expressionStatementNode; unaryExpressionNode2.parentNode = unaryExpressionNode1; literalNode.parentNode = unaryExpressionNode2; + + unaryExpressionArgumentNode = NodeUtils.getUnaryExpressionArgumentNode(unaryExpressionNode1); + expectedNode = literalNode; }); it('should return unary expression argument node', () => { - assert.deepEqual(NodeUtils.getUnaryExpressionArgumentNode(unaryExpressionNode1), literalNode); + assert.deepEqual(unaryExpressionArgumentNode, expectedNode); }); }); @@ -388,32 +447,61 @@ describe('NodeUtils', () => { ); }); - it('should parentize given AST-tree with `ProgramNode` as root node', () => { - programNode = Nodes.getProgramNode([ - ifStatementNode - ]); + describe('parentize AST-tree with `ProgramNode` as root node', () => { + beforeEach(() => { + programNode = Nodes.getProgramNode([ + ifStatementNode + ]); - programNode = NodeUtils.parentize(programNode); + programNode = NodeUtils.parentize(programNode); + }); - assert.deepEqual(programNode.parentNode, programNode); - assert.deepEqual(ifStatementNode.parentNode, programNode); - assert.deepEqual(ifStatementBlockStatementNode.parentNode, ifStatementNode); - assert.deepEqual(expressionStatementNode1.parentNode, ifStatementBlockStatementNode); - assert.deepEqual(expressionStatementNode2.parentNode, ifStatementBlockStatementNode); + it('should parentize `program` node with `ProgramNode` as root node', () => { + assert.deepEqual(programNode.parentNode, programNode); + }); + + it('should parentize `ifStatement` node with `ProgramNode` as root node', () => { + assert.deepEqual(ifStatementNode.parentNode, programNode); + }); + + it('should parentize `ifStatement blockStatement` node with `ProgramNode` as root node', () => { + assert.deepEqual(ifStatementBlockStatementNode.parentNode, ifStatementNode); + }); + + it('should parentize `expressionStatement` node #1 with `ProgramNode` as root node', () => { + assert.deepEqual(expressionStatementNode1.parentNode, ifStatementBlockStatementNode); + }); + + it('should parentize `expressionStatement` node #2 with `ProgramNode` as root node', () => { + assert.deepEqual(expressionStatementNode2.parentNode, ifStatementBlockStatementNode); + }); }); - it('should parentize given AST-tree', () => { - programNode = Nodes.getProgramNode([ - ifStatementNode - ]); - programNode.parentNode = programNode; + describe('parentize AST-tree', () => { + beforeEach(() => { + programNode = Nodes.getProgramNode([ + ifStatementNode + ]); + programNode.parentNode = programNode; - ifStatementNode = NodeUtils.parentize(ifStatementNode); + ifStatementNode = NodeUtils.parentize(ifStatementNode); + }); - assert.deepEqual(ifStatementNode.parentNode, programNode); - assert.deepEqual(ifStatementBlockStatementNode.parentNode, ifStatementNode); - assert.deepEqual(expressionStatementNode1.parentNode, ifStatementBlockStatementNode); - assert.deepEqual(expressionStatementNode2.parentNode, ifStatementBlockStatementNode); + it('should parentize `ifStatement` node', () => { + assert.deepEqual(ifStatementNode.parentNode, programNode); + }); + + it('should parentize `ifStatement blockStatement` node', () => { + assert.deepEqual(ifStatementBlockStatementNode.parentNode, ifStatementNode); + }); + + it('should parentize `expressionStatement` node #1', () => { + assert.deepEqual(expressionStatementNode1.parentNode, ifStatementBlockStatementNode); + }); + + it('should parentize `expressionStatement` node #2', () => { + assert.deepEqual(expressionStatementNode2.parentNode, ifStatementBlockStatementNode); + }); }); }); }); diff --git a/test/unit-tests/obfuscation-result/ObfuscationResult.spec.ts b/test/unit-tests/obfuscation-result/ObfuscationResult.spec.ts index 2e5f08f5..5c41b4f0 100644 --- a/test/unit-tests/obfuscation-result/ObfuscationResult.spec.ts +++ b/test/unit-tests/obfuscation-result/ObfuscationResult.spec.ts @@ -10,12 +10,12 @@ describe('ObfuscationResult', () => { obfuscationResult: IObfuscationResult, sourceMap: string = 'sourceMap'; - beforeEach(() => { + before(() => { obfuscationResult = new ObfuscationResult(); obfuscationResult.initialize(obfuscatedCode, sourceMap); }); - it('should returns obfuscated code if `.toString()` was called on `ObfuscationResult` object', () => { + it('should return obfuscated code if `.toString()` was called on `ObfuscationResult` object', () => { assert.equal(obfuscationResult.toString(), obfuscatedCode); }); }); diff --git a/test/unit-tests/options/options-normalizer/OptionsNormalizer.spec.ts b/test/unit-tests/options/options-normalizer/OptionsNormalizer.spec.ts index 4d605c4f..0e3a2884 100644 --- a/test/unit-tests/options/options-normalizer/OptionsNormalizer.spec.ts +++ b/test/unit-tests/options/options-normalizer/OptionsNormalizer.spec.ts @@ -24,204 +24,286 @@ describe('OptionsNormalizer', () => { let optionsPreset: TInputOptions, expectedOptionsPreset: TInputOptions; - it('should normalize options preset: controlFlowFlatteningThresholdRule', () => { - optionsPreset = { - ...DEFAULT_PRESET, - controlFlowFlattening: true, - controlFlowFlatteningThreshold: 0 - }; + describe('controlFlowFlatteningThresholdRule', () => { + before(() => { + optionsPreset = getNormalizedOptions({ + ...DEFAULT_PRESET, + controlFlowFlattening: true, + controlFlowFlatteningThreshold: 0 + }); - expectedOptionsPreset = { - ...DEFAULT_PRESET, - controlFlowFlattening: false, - controlFlowFlatteningThreshold: 0 - }; + expectedOptionsPreset = { + ...DEFAULT_PRESET, + controlFlowFlattening: false, + controlFlowFlatteningThreshold: 0 + }; + }); - assert.deepEqual(getNormalizedOptions(optionsPreset), expectedOptionsPreset); + it('should normalize options preset', () => { + assert.deepEqual(optionsPreset, expectedOptionsPreset); + }); }); - it('should normalize options preset: deadCodeInjectionRule', () => { - optionsPreset = { - ...DEFAULT_PRESET, - deadCodeInjection: true, - deadCodeInjectionThreshold: 0.4, - stringArray: false, - stringArrayThreshold: 0 - }; + describe('deadCodeInjectionRule', () => { + before(() => { + optionsPreset = getNormalizedOptions({ + ...DEFAULT_PRESET, + deadCodeInjection: true, + deadCodeInjectionThreshold: 0.4, + stringArray: false, + stringArrayThreshold: 0 + }); - expectedOptionsPreset = { - ...DEFAULT_PRESET, - deadCodeInjection: true, - deadCodeInjectionThreshold: 0.4, - stringArray: true, - stringArrayThreshold: 0.75 - }; + expectedOptionsPreset = { + ...DEFAULT_PRESET, + deadCodeInjection: true, + deadCodeInjectionThreshold: 0.4, + stringArray: true, + stringArrayThreshold: 0.75 + }; + }); - assert.deepEqual(getNormalizedOptions(optionsPreset), expectedOptionsPreset); + it('should normalize options preset', () => { + assert.deepEqual(optionsPreset, expectedOptionsPreset); + }); }); - it('should normalize options preset: deadCodeInjectionRule. `stringArrayThreshold` option is not empty', () => { - optionsPreset = { - ...DEFAULT_PRESET, - deadCodeInjection: true, - deadCodeInjectionThreshold: 0.4, - stringArray: false, - stringArrayThreshold: 0.5 - }; + describe('deadCodeInjectionRule', () => { + describe('`stringArrayThreshold` option is empty', () => { + before(() => { + optionsPreset = getNormalizedOptions({ + ...DEFAULT_PRESET, + deadCodeInjection: true, + deadCodeInjectionThreshold: 0.4, + stringArray: false, + stringArrayThreshold: 0 + }); - expectedOptionsPreset = { - ...DEFAULT_PRESET, - deadCodeInjection: true, - deadCodeInjectionThreshold: 0.4, - stringArray: true, - stringArrayThreshold: 0.5 - }; + expectedOptionsPreset = { + ...DEFAULT_PRESET, + deadCodeInjection: true, + deadCodeInjectionThreshold: 0.4, + stringArray: true, + stringArrayThreshold: 0.75 + }; + }); - assert.deepEqual(getNormalizedOptions(optionsPreset), expectedOptionsPreset); + it('should normalize options preset', () => { + assert.deepEqual(optionsPreset, expectedOptionsPreset); + }); + }); + + describe('`stringArrayThreshold` option is not empty', () => { + before(() => { + optionsPreset = getNormalizedOptions({ + ...DEFAULT_PRESET, + deadCodeInjection: true, + deadCodeInjectionThreshold: 0.4, + stringArray: false, + stringArrayThreshold: 0.5 + }); + + expectedOptionsPreset = { + ...DEFAULT_PRESET, + deadCodeInjection: true, + deadCodeInjectionThreshold: 0.4, + stringArray: true, + stringArrayThreshold: 0.5 + }; + }); + + it('should normalize options preset', () => { + assert.deepEqual(optionsPreset, expectedOptionsPreset); + }); + }); }); - it('should normalize options preset: deadCodeInjectionThresholdRule', () => { - optionsPreset = { - ...DEFAULT_PRESET, - deadCodeInjection: true, - deadCodeInjectionThreshold: 0 - }; + describe('deadCodeInjectionThresholdRule', () => { + before(() => { + optionsPreset = getNormalizedOptions({ + ...DEFAULT_PRESET, + deadCodeInjection: true, + deadCodeInjectionThreshold: 0 + }); - expectedOptionsPreset = { - ...DEFAULT_PRESET, - deadCodeInjection: false, - deadCodeInjectionThreshold: 0 - }; + expectedOptionsPreset = { + ...DEFAULT_PRESET, + deadCodeInjection: false, + deadCodeInjectionThreshold: 0 + }; + }); - assert.deepEqual(getNormalizedOptions(optionsPreset), expectedOptionsPreset); + it('should normalize options preset', () => { + assert.deepEqual(optionsPreset, expectedOptionsPreset); + }); }); - it('should normalize options preset: domainLockRule', () => { - optionsPreset = { - ...DEFAULT_PRESET, - domainLock: ['//localhost:9000', 'https://google.ru/abc?cde=fgh'] - }; + describe('domainLockRule', () => { + before(() => { + optionsPreset = getNormalizedOptions({ + ...DEFAULT_PRESET, + domainLock: [ + '//localhost:9000', + 'https://google.ru/abc?cde=fgh' + ] + }); - expectedOptionsPreset = { - ...DEFAULT_PRESET, - domainLock: ['localhost', 'google.ru'] - }; + expectedOptionsPreset = { + ...DEFAULT_PRESET, + domainLock: [ + 'localhost', + 'google.ru' + ] + }; + }); - assert.deepEqual(getNormalizedOptions(optionsPreset), expectedOptionsPreset); + it('should normalize options preset', () => { + assert.deepEqual(optionsPreset, expectedOptionsPreset); + }); }); - it('should normalize options preset: selfDefendingRule', () => { - optionsPreset = { - ...DEFAULT_PRESET, - selfDefending: true, - compact: false - }; + describe('selfDefendingRule', () => { + before(() => { + optionsPreset = getNormalizedOptions({ + ...DEFAULT_PRESET, + selfDefending: true, + compact: false + }); - expectedOptionsPreset = { - ...DEFAULT_PRESET, - selfDefending: true, - compact: true - }; + expectedOptionsPreset = { + ...DEFAULT_PRESET, + selfDefending: true, + compact: true + }; + }); - assert.deepEqual(getNormalizedOptions(optionsPreset), expectedOptionsPreset); + it('should normalize options preset', () => { + assert.deepEqual(optionsPreset, expectedOptionsPreset); + }); }); - it('should normalize options preset: sourceMapBaseUrlRule #1', () => { - optionsPreset = { - ...DEFAULT_PRESET, - sourceMapBaseUrl: 'http://localhost:9000', - }; + describe('sourceMapBaseUrlRule', () => { + describe('variant #1: only source map base url', () => { + before(() => { + optionsPreset = getNormalizedOptions({ + ...DEFAULT_PRESET, + sourceMapBaseUrl: 'http://localhost:9000', + }); - expectedOptionsPreset = { - ...DEFAULT_PRESET, - sourceMapBaseUrl: '' - }; + expectedOptionsPreset = { + ...DEFAULT_PRESET, + sourceMapBaseUrl: '' + }; + }); - assert.deepEqual(getNormalizedOptions(optionsPreset), expectedOptionsPreset); + it('should normalize options preset', () => { + assert.deepEqual(optionsPreset, expectedOptionsPreset); + }); + }); + + describe('variant #2: source map base url with source map file name', () => { + before(() => { + optionsPreset = getNormalizedOptions({ + ...DEFAULT_PRESET, + sourceMapBaseUrl: 'http://localhost:9000', + sourceMapFileName: '/outputSourceMapName.map' + }); + + expectedOptionsPreset = { + ...DEFAULT_PRESET, + sourceMapBaseUrl: 'http://localhost:9000/', + sourceMapFileName: 'outputSourceMapName.js.map' + }; + }); + + it('should normalize options preset', () => { + assert.deepEqual(optionsPreset, expectedOptionsPreset); + }); + }); }); - it('should normalize options preset: sourceMapBaseUrlRule #2', () => { - optionsPreset = { - ...DEFAULT_PRESET, - sourceMapBaseUrl: 'http://localhost:9000', - sourceMapFileName: '/outputSourceMapName.map' - }; + describe('sourceMapFileNameRule', () => { + before(() => { + optionsPreset = getNormalizedOptions({ + ...DEFAULT_PRESET, + sourceMapBaseUrl: 'http://localhost:9000', + sourceMapFileName: '//outputSourceMapName' + }); - expectedOptionsPreset = { - ...DEFAULT_PRESET, - sourceMapBaseUrl: 'http://localhost:9000/', - sourceMapFileName: 'outputSourceMapName.js.map' - }; + expectedOptionsPreset = { + ...DEFAULT_PRESET, + sourceMapBaseUrl: 'http://localhost:9000/', + sourceMapFileName: 'outputSourceMapName.js.map' + }; + }); - assert.deepEqual(getNormalizedOptions(optionsPreset), expectedOptionsPreset); + it('should normalize options preset', () => { + assert.deepEqual(optionsPreset, expectedOptionsPreset); + }); }); - it('should normalize options preset: sourceMapFileNameRule', () => { - optionsPreset = { - ...DEFAULT_PRESET, - sourceMapBaseUrl: 'http://localhost:9000', - sourceMapFileName: '//outputSourceMapName' - }; + describe('stringArrayRule', () => { + before(() => { + optionsPreset = getNormalizedOptions({ + ...DEFAULT_PRESET, + stringArray: false, + stringArrayEncoding: 'rc4', + stringArrayThreshold: 0.5, + rotateStringArray: true + }); - expectedOptionsPreset = { - ...DEFAULT_PRESET, - sourceMapBaseUrl: 'http://localhost:9000/', - sourceMapFileName: 'outputSourceMapName.js.map' - }; + expectedOptionsPreset = { + ...DEFAULT_PRESET, + stringArray: false, + stringArrayEncoding: false, + stringArrayThreshold: 0, + rotateStringArray: false + }; + }); - assert.deepEqual(getNormalizedOptions(optionsPreset), expectedOptionsPreset); + it('should normalize options preset', () => { + assert.deepEqual(optionsPreset, expectedOptionsPreset); + }); }); - it('should normalize options preset: stringArrayRule', () => { - optionsPreset = { - ...DEFAULT_PRESET, - stringArray: false, - stringArrayEncoding: 'rc4', - stringArrayThreshold: 0.5, - rotateStringArray: true - }; + describe('stringArrayEncodingRule', () => { + before(() => { + optionsPreset = getNormalizedOptions({ + ...DEFAULT_PRESET, + stringArrayEncoding: true + }); - expectedOptionsPreset = { - ...DEFAULT_PRESET, - stringArray: false, - stringArrayEncoding: false, - stringArrayThreshold: 0, - rotateStringArray: false - }; + expectedOptionsPreset = { + ...DEFAULT_PRESET, + stringArrayEncoding: 'base64' + }; + }); - assert.deepEqual(getNormalizedOptions(optionsPreset), expectedOptionsPreset); + it('should normalize options preset', () => { + assert.deepEqual(optionsPreset, expectedOptionsPreset); + }); }); - it('should normalize options preset: stringArrayEncodingRule', () => { - optionsPreset = { - ...DEFAULT_PRESET, - stringArrayEncoding: true - }; + describe('stringArrayThresholdRule', () => { + before(() => { + optionsPreset = getNormalizedOptions({ + ...DEFAULT_PRESET, + rotateStringArray: true, + stringArray: true, + stringArrayThreshold: 0 + }); - expectedOptionsPreset = { - ...DEFAULT_PRESET, - stringArrayEncoding: 'base64' - }; + expectedOptionsPreset = { + ...DEFAULT_PRESET, + rotateStringArray: false, + stringArray: false, + stringArrayThreshold: 0 + }; + }); - assert.deepEqual(getNormalizedOptions(optionsPreset), expectedOptionsPreset); - }); - - it('should normalize options preset: stringArrayThresholdRule', () => { - optionsPreset = { - ...DEFAULT_PRESET, - rotateStringArray: true, - stringArray: true, - stringArrayThreshold: 0 - }; - - expectedOptionsPreset = { - ...DEFAULT_PRESET, - rotateStringArray: false, - stringArray: false, - stringArrayThreshold: 0 - }; - - assert.deepEqual(getNormalizedOptions(optionsPreset), expectedOptionsPreset); + it('should normalize options preset', () => { + assert.deepEqual(optionsPreset, expectedOptionsPreset); + }); }); }); }); diff --git a/test/unit-tests/source-map-corrector/SourceMapCorrector.spec.ts b/test/unit-tests/source-map-corrector/SourceMapCorrector.spec.ts index 1a90c402..334dd3aa 100644 --- a/test/unit-tests/source-map-corrector/SourceMapCorrector.spec.ts +++ b/test/unit-tests/source-map-corrector/SourceMapCorrector.spec.ts @@ -40,60 +40,82 @@ function getCorrectedObfuscationResult ( describe('SourceMapCorrector', () => { describe('correct (): IObfuscationResult', () => { - let expectedObfuscationResult: IObfuscationResult, - obfuscatedCode: string = 'var test = 1;', - sourceMap: string = 'test'; + const expectedObfuscatedCode: string = 'var test = 1;'; + const sourceMap: string = 'test'; - it('should return untouched obfuscated code if source map does not exist', () => { - expectedObfuscationResult = getCorrectedObfuscationResult( - obfuscatedCode, - '', - '', - '', - SourceMapMode.Separate) - ; + let obfuscationResult: IObfuscationResult, + obfuscatedCode: string; - assert.equal(expectedObfuscationResult.getObfuscatedCode(), obfuscatedCode); + describe('source map doest\'t exist', () => { + before(() => { + obfuscationResult = getCorrectedObfuscationResult( + expectedObfuscatedCode, + '', + '', + '', + SourceMapMode.Separate + ); + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('should return untouched obfuscated code', () => { + assert.equal(obfuscatedCode, expectedObfuscatedCode); + }); }); - describe('if source map is set and source map mode is `inline`', () => { - before (() => { - expectedObfuscationResult = getCorrectedObfuscationResult( - obfuscatedCode, + describe('source map is set, source map mode is `inline`', () => { + const regExp: RegExp = /data:application\/json;base64/; + + before(() => { + obfuscationResult = getCorrectedObfuscationResult( + expectedObfuscatedCode, sourceMap, '', '', SourceMapMode.Inline ); + obfuscatedCode = obfuscationResult.getObfuscatedCode(); }); it('should add source map to obfuscated code as base64 encoded string', () => { - assert.match(expectedObfuscationResult.getObfuscatedCode(), /data:application\/json;base64/); + assert.match(obfuscatedCode, regExp); }); }); - it('should add source map import to obfuscated code if source map mode is `separate`', () => { - expectedObfuscationResult = getCorrectedObfuscationResult( - obfuscatedCode, - sourceMap, - 'http://example.com', - 'output.js.map', - SourceMapMode.Separate - ); + describe('source map mode is `separate`', () => { + const regExp: RegExp = /sourceMappingURL=http:\/\/example\.com\/output\.js\.map/; - assert.match(expectedObfuscationResult.getObfuscatedCode(), /sourceMappingURL=http:\/\/example\.com\/output\.js\.map/); + before(() => { + obfuscationResult = getCorrectedObfuscationResult( + expectedObfuscatedCode, + sourceMap, + 'http://example.com', + 'output.js.map', + SourceMapMode.Separate + ); + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); + + it('should add source map import to obfuscated code', () => { + assert.match(obfuscatedCode, regExp); + }); }); - it('should not touch obfuscated code if source map mode is `separate` and `sourceMapUrl` is not set', () => { - expectedObfuscationResult = getCorrectedObfuscationResult( - obfuscatedCode, - sourceMap, - '', - '', - SourceMapMode.Separate - ); + describe('source map mode is `separate`, `sourceMapUrl` is not set', () => { + before(() => { + obfuscationResult = getCorrectedObfuscationResult( + expectedObfuscatedCode, + sourceMap, + '', + '', + SourceMapMode.Separate + ); + obfuscatedCode = obfuscationResult.getObfuscatedCode(); + }); - assert.equal(expectedObfuscationResult.getObfuscatedCode(), obfuscatedCode); + it('should not touch obfuscated code', () => { + assert.equal(obfuscatedCode, expectedObfuscatedCode); + }); }); }); }); diff --git a/test/unit-tests/stack-trace-analyzer/stack-trace-analyzer/StackTraceAnalyzer.spec.ts b/test/unit-tests/stack-trace-analyzer/stack-trace-analyzer/StackTraceAnalyzer.spec.ts index 30a48144..bdcc1410 100644 --- a/test/unit-tests/stack-trace-analyzer/stack-trace-analyzer/StackTraceAnalyzer.spec.ts +++ b/test/unit-tests/stack-trace-analyzer/stack-trace-analyzer/StackTraceAnalyzer.spec.ts @@ -4,16 +4,58 @@ import { StackTraceAnalyzer } from '../../../../src/stack-trace-analyzer/StackTr describe('StackTraceAnalyzer', () => { describe('getLimitIndex (blockScopeBodyLength: number): number', () => { - it('should returns correct limit index based on block scope body length', () => { - const blockScopeBodyLength1: number = 10000; - const blockScopeBodyLength2: number = 1000; - const blockScopeBodyLength3: number = 25; - const blockScopeBodyLength4: number = 5; + let limitIndex: number; - assert.equal(StackTraceAnalyzer.getLimitIndex(blockScopeBodyLength1), 44); - assert.equal(StackTraceAnalyzer.getLimitIndex(blockScopeBodyLength2), 26); - assert.equal(StackTraceAnalyzer.getLimitIndex(blockScopeBodyLength3), 24); - assert.equal(StackTraceAnalyzer.getLimitIndex(blockScopeBodyLength4), 4); + describe('variant #1: length - 10000', () => { + const blockScopeBodyLength: number = 10000; + const expectedLimitIndex: number = 44; + + before(() => { + limitIndex = StackTraceAnalyzer.getLimitIndex(blockScopeBodyLength); + }); + + it('should return correct limit index based on block scope body length', () => { + assert.equal(limitIndex, expectedLimitIndex); + }); + }); + + describe('variant #2: length - 1000', () => { + const blockScopeBodyLength: number = 1000; + const expectedLimitIndex: number = 26; + + before(() => { + limitIndex = StackTraceAnalyzer.getLimitIndex(blockScopeBodyLength); + }); + + it('should return correct limit index based on block scope body length', () => { + assert.equal(limitIndex, expectedLimitIndex); + }); + }); + + describe('variant #3: length - 25', () => { + const blockScopeBodyLength: number = 25; + const expectedLimitIndex: number = 24; + + before(() => { + limitIndex = StackTraceAnalyzer.getLimitIndex(blockScopeBodyLength); + }); + + it('should return correct limit index based on block scope body length', () => { + assert.equal(limitIndex, expectedLimitIndex); + }); + }); + + describe('variant #4: length - 5', () => { + const blockScopeBodyLength: number = 5; + const expectedLimitIndex: number = 4; + + before(() => { + limitIndex = StackTraceAnalyzer.getLimitIndex(blockScopeBodyLength); + }); + + it('should return correct limit index based on block scope body length', () => { + assert.equal(limitIndex, expectedLimitIndex); + }); }); }); }); diff --git a/test/unit-tests/storages/ArrayStorage.spec.ts b/test/unit-tests/storages/ArrayStorage.spec.ts index 46acdc75..1349079d 100644 --- a/test/unit-tests/storages/ArrayStorage.spec.ts +++ b/test/unit-tests/storages/ArrayStorage.spec.ts @@ -10,117 +10,195 @@ class ConcreteStorage extends ArrayStorage { } } -describe('ArrayStorage', () => { - describe('initialize (...args: any[]): void', () => { - it('should throws an error when storage isn\'t initialized', () => { - const storage: IStorage = new ConcreteStorage(); +/** + * @type {IStorage} + */ +const getStorageInstance = (): IStorage => { + const storage: IStorage = new ConcreteStorage(); - assert.throws(() => storage.set(0, 'foo'), Error); + storage.initialize(); + + return storage; +}; + +describe('ArrayStorage', () => { + const storageKey: number = 0; + const storageValue: string = 'foo'; + + let storage: IStorage ; + + describe('initialize (...args: any[]): void', () => { + const expectedError: ErrorConstructor = Error; + + let testFunc: () => void; + + before(() => { + storage = new ConcreteStorage(); + testFunc = () => storage.set(storageKey, storageValue); + }); + + it('should throws an error when storage isn\'t initialized', () => { + assert.throws(testFunc, expectedError); }); }); describe('getStorage (): T[]', () => { - it('should returns storage', () => { - const storage: IStorage = new ConcreteStorage(); + const expectedInstanceOf: ArrayConstructor = Array; - storage.initialize(); + let arrayStorage: string[]; - assert.instanceOf(storage.getStorage(), Array); + before(() => { + storage = getStorageInstance(); + + arrayStorage = storage.getStorage(); + }); + + it('should return storage', () => { + assert.instanceOf(arrayStorage, expectedInstanceOf); }); }); describe('get (key: number): T', () => { - it('should returns value from storage by key', () => { - const storage: IStorage = new ConcreteStorage(); + describe('variant #1: value exist', () => { + const expectedValue: string = storageValue; - storage.initialize(); - storage.set(0, 'foo'); + let value: string; - assert.equal(storage.get(0), 'foo'); + before(() => { + storage = getStorageInstance(); + storage.set(storageKey, storageValue); + + value = storage.get(storageKey); + }); + + it('should return value from storage by key', () => { + assert.equal(value, expectedValue); + }); }); - it('should throw an error if value isn\'t exist', () => { - const storage: IStorage = new ConcreteStorage(); + describe('variant #2: value isn\'t exist', () => { + const expectedError: ErrorConstructor = Error; - storage.initialize(); + let testFunc: () => void; - assert.throws(() => storage.get(0), Error); + before(() => { + storage = getStorageInstance(); + + testFunc = () => storage.get(storageKey); + }); + + it('should throw an error', () => { + assert.throws(testFunc, expectedError); + }); }); }); describe('getLength (): number', () => { - it('should returns length of storage', () => { - const storage: IStorage = new ConcreteStorage(); + const expectedStorageLength: number = 1; - storage.initialize(); - storage.set(0, 'foo'); + let storageLength: number; - assert.equal(storage.getLength(), 1); + before(() => { + storage = getStorageInstance(); + storage.set(storageKey, storageValue); + + storageLength = storage.getLength(); + }); + + it('should return length of storage', () => { + assert.equal(storageLength, expectedStorageLength); }); }); describe('getKeyOf (value: T): number | null', () => { - it('should returns key of string value', () => { - const storage: IStorage = new ConcreteStorage(); + let key: string | number | null; - storage.initialize(); - storage.set(0, 'foo'); + describe('variant #1', () => { + before(() => { + storage = getStorageInstance(); + storage.set(storageKey, storageValue); - assert.equal(storage.getKeyOf('foo'), 0); + key = storage.getKeyOf(storageValue); + }); + + it('should return key of string value', () => { + assert.equal(key, storageKey); + }); }); - it('should returns key of object if objects in `set` and `get` are two linked objects', () => { - const storage: IStorage = new ConcreteStorage(); + describe('variant #2', () => { const object: Object = { foo: 'bar' }; - storage.initialize(); - storage.set(0, object); + before(() => { + storage = getStorageInstance(); + storage.set(storageKey, object); - assert.equal(storage.getKeyOf(object), 0); - }); - - it('should return `null` if objects in `set` and `get` are two equal objects', () => { - const storage: IStorage = new ConcreteStorage(); - - storage.initialize(); - storage.set(0, { - foo: 'bar' + key = storage.getKeyOf(object); }); - assert.equal(storage.getKeyOf({ + it('should return key of object if objects in `set` and `get` are two same objects', () => { + assert.equal(key, storageKey); + }); + }); + + describe('variant #3', () => { + const expectedKey: null = null; + const object: Object = { foo: 'bar' - }), null); + }; + + before(() => { + storage = getStorageInstance(); + storage.set(storageKey, object); + + key = storage.getKeyOf({...object}); + }); + + it('should return `null` if objects in `set` and `get` are two different objects', () => { + assert.equal(key, expectedKey); + }); }); }); describe('set (key: number, value: T): void', () => { + let value: string; + + before(() => { + storage = getStorageInstance(); + storage.set(storageKey, storageValue); + + value = storage.get(storageKey); + }); + it('should set value to the storage', () => { - const storage: IStorage = new ConcreteStorage(); - - storage.initialize(); - storage.set(0, 'foo'); - - assert.equal(storage.get(0), 'foo'); - assert.equal(storage.getLength(), 1); + assert.equal(value, storageValue); }); }); describe('mergeWith (storage: this, mergeId: boolean = false): void', () => { + const secondStorageKey: number = 1; + const secondStorageValue: string = 'bar'; + + const expectedArray: string[] = [storageValue, secondStorageValue]; + + let array: string[]; + + before(() => { + storage = getStorageInstance(); + storage.set(storageKey, storageValue); + + const secondStorage: IStorage = getStorageInstance(); + secondStorage.set(secondStorageKey, secondStorageValue); + + storage.mergeWith(secondStorage, false); + + array = storage.getStorage(); + }); + it('should merge two storages', () => { - const storage1: IStorage = new ConcreteStorage(); - const storage2: IStorage = new ConcreteStorage(); - - storage1.initialize(); - storage1.set(0, 'foo'); - - storage2.initialize(); - storage2.set(1, 'bar'); - - storage1.mergeWith(storage2, false); - - assert.deepEqual(storage1.getStorage(), ['foo', 'bar']); + assert.deepEqual(array, expectedArray); }); }); }); diff --git a/test/unit-tests/storages/MapStorage.spec.ts b/test/unit-tests/storages/MapStorage.spec.ts index fc2a5b88..4fd4953f 100644 --- a/test/unit-tests/storages/MapStorage.spec.ts +++ b/test/unit-tests/storages/MapStorage.spec.ts @@ -10,117 +10,198 @@ class ConcreteStorage extends MapStorage { } } -describe('MapStorage', () => { - describe('initialize (...args: any[]): void', () => { - it('should throws an error when storage isn\'t initialized', () => { - const storage: IStorage = new ConcreteStorage(); +/** + * @type {IStorage} + */ +const getStorageInstance = (): IStorage => { + const storage: IStorage = new ConcreteStorage(); - assert.throws(() => storage.set('foo', 'bar'), Error); + storage.initialize(); + + return storage; +}; + +describe('MapStorage', () => { + const storageKey: string = 'foo'; + const storageValue: string = 'bar'; + + let storage: IStorage ; + + describe('initialize (...args: any[]): void', () => { + const expectedError: ErrorConstructor = Error; + + let testFunc: () => void; + + before(() => { + storage = new ConcreteStorage(); + testFunc = () => storage.set(storageKey, storageValue); + }); + + it('should throws an error when storage isn\'t initialized', () => { + assert.throws(testFunc, expectedError); }); }); describe('getStorage (): Map ', () => { - it('should returns storage', () => { - const storage: IStorage = new ConcreteStorage(); + const expectedInstanceOf: MapConstructor = Map; - storage.initialize(); + let mapStorage: string[]; - assert.instanceOf(storage.getStorage(), Map); + before(() => { + storage = getStorageInstance(); + + mapStorage = storage.getStorage(); + }); + + it('should return storage', () => { + assert.instanceOf(mapStorage, expectedInstanceOf); }); }); describe('get (key: string | number): T', () => { - it('should returns value from storage by key', () => { - const storage: IStorage = new ConcreteStorage(); + describe('variant #1: value exist', () => { + const expectedValue: string = storageValue; - storage.initialize(); - storage.set('foo', 'bar'); + let value: string; - assert.equal(storage.get('foo'), 'bar'); + before(() => { + storage = getStorageInstance(); + storage.set(storageKey, storageValue); + + value = storage.get(storageKey); + }); + + it('should return value from storage by key', () => { + assert.equal(value, expectedValue); + }); }); - it('should throw an error if value isn\'t exist', () => { - const storage: IStorage = new ConcreteStorage(); + describe('variant #2: value isn\'t exist', () => { + const expectedError: ErrorConstructor = Error; - storage.initialize(); + let testFunc: () => void; - assert.throws(() => storage.get('foo'), Error); + before(() => { + storage = getStorageInstance(); + + testFunc = () => storage.get(storageKey); + }); + + it('should throw an error', () => { + assert.throws(testFunc, expectedError); + }); }); }); describe('getLength (): number', () => { - it('should returns length of storage', () => { - const storage: IStorage = new ConcreteStorage(); + const expectedStorageLength: number = 1; - storage.initialize(); - storage.set('foo', 'bar'); + let storageLength: number; - assert.equal(storage.getLength(), 1); + before(() => { + storage = getStorageInstance(); + storage.set(storageKey, storageValue); + + storageLength = storage.getLength(); + }); + + it('should return length of storage', () => { + assert.equal(storageLength, expectedStorageLength); }); }); describe('getKeyOf (value: T): string | number | null', () => { - it('should returns key of string value', () => { - const storage: IStorage = new ConcreteStorage(); + let key: string | number | null; - storage.initialize(); - storage.set('foo', 'bar'); + describe('variant #1', () => { + before(() => { + storage = getStorageInstance(); + storage.set(storageKey, storageValue); - assert.equal(storage.getKeyOf('bar'), 'foo'); + key = storage.getKeyOf(storageValue); + }); + + it('should return key of string value', () => { + assert.equal(key, storageKey); + }); }); - it('should returns key of object if objects in `set` and `get` are two linked objects', () => { - const storage: IStorage = new ConcreteStorage(); + describe('variant #2', () => { const object: Object = { bar: 'baz' }; - storage.initialize(); - storage.set('foo', object); + before(() => { + storage = getStorageInstance(); + storage.set(storageKey, object); - assert.equal(storage.getKeyOf(object), 'foo'); - }); - - it('should return `null` if objects in `set` and `get` are two equal objects', () => { - const storage: IStorage = new ConcreteStorage(); - - storage.initialize(); - storage.set('foo', { - bar: 'baz' + key = storage.getKeyOf(object); }); - assert.equal(storage.getKeyOf({ + it('should return key of object if objects in `set` and `get` are two same objects', () => { + assert.equal(key, storageKey); + }); + }); + + describe('variant #3', () => { + const expectedKey: null = null; + const object: Object = { bar: 'baz' - }), null); + }; + + before(() => { + storage = getStorageInstance(); + storage.set(storageKey, object); + + key = storage.getKeyOf({...object}); + }); + + it('should return `null` if objects in `set` and `get` are two different objects', () => { + assert.equal(key, expectedKey); + }); }); }); describe('set (key: string | number, value: T): void', () => { + let value: string; + + before(() => { + storage = getStorageInstance(); + storage.set(storageKey, storageValue); + + value = storage.get(storageKey); + }); + it('should set value to the storage', () => { - const storage: IStorage = new ConcreteStorage(); - - storage.initialize(); - storage.set('foo', 'bar'); - - assert.equal(storage.get('foo'), 'bar'); - assert.equal(storage.getLength(), 1); + assert.equal(value, storageValue); }); }); describe('mergeWith (storage: this, mergeId: boolean = false): void', () => { + const secondStorageKey: string = 'baz'; + const secondStorageValue: string = 'quux'; + + const expectedArray: string[][] = [ + [storageKey, storageValue], + [secondStorageKey, secondStorageValue] + ]; + + let array: string[][]; + + before(() => { + storage = getStorageInstance(); + storage.set(storageKey, storageValue); + + const secondStorage: IStorage = getStorageInstance(); + secondStorage.set(secondStorageKey, secondStorageValue); + + storage.mergeWith(secondStorage, false); + + array = Array.from(storage.getStorage()); + }); + it('should merge two storages', () => { - const storage1: IStorage = new ConcreteStorage(); - const storage2: IStorage = new ConcreteStorage(); - - storage1.initialize(); - storage1.set('foo', 'bar'); - - storage2.initialize(); - storage2.set('baz', 'quux'); - - storage1.mergeWith(storage2, false); - - assert.deepEqual(Array.from(storage1.getStorage()), [['foo', 'bar'], ['baz', 'quux']]); + assert.deepEqual(array, expectedArray); }); }); }); diff --git a/test/unit-tests/utils/crypt-utils/CryptUtils.spec.ts b/test/unit-tests/utils/crypt-utils/CryptUtils.spec.ts index 4532cca4..cbd9761f 100644 --- a/test/unit-tests/utils/crypt-utils/CryptUtils.spec.ts +++ b/test/unit-tests/utils/crypt-utils/CryptUtils.spec.ts @@ -4,35 +4,77 @@ import { CryptUtils } from '../../../../src/utils/CryptUtils'; describe('CryptUtils', () => { describe('btoa (string: string): string', () => { + const expectedString: string = 'c3RyaW5n'; + + let string: string; + + before(() => { + string = CryptUtils.btoa('string'); + }); + it('should create a base-64 encoded string from a given string', () => { - assert.equal(CryptUtils.btoa('string'), 'c3RyaW5n'); + assert.equal(string, expectedString); }); }); describe('hideString (str: string, length: number): [string, string]', () => { - let original1: string = 'example.com', - [str1, diff] = CryptUtils.hideString(original1, 30); + const originalString: string = 'example.com'; + const hiddenStringLength: number = 30; - it('should return a string with the original string within', () => { - assert.isTrue(str1.length > original1.length); - assert.equal(str1.replace(new RegExp('[' + diff + ']', 'g'), ''), original1); + let hiddenString: string, + diffString: string; + + before(() => { + [hiddenString, diffString] = CryptUtils.hideString(originalString, hiddenStringLength); }); + describe('hidden string length check', () => { + let originalStringActualLength: number, + hiddenStringActualLength: number; + + before(() => { + originalStringActualLength = originalString.length; + hiddenStringActualLength = hiddenString.length; + }); + + it('should create hidden string with length equal or bigger than given length', () => { + assert.isTrue(hiddenStringActualLength > originalStringActualLength); + }); + }); + + describe('hidden string content', () => { + let hiddenStringWithoutDiff: string; + + before(() => { + const regExp: RegExp = new RegExp(`[${diffString}]`, 'g'); + + hiddenStringWithoutDiff = hiddenString.replace(regExp, ''); + }); + + it('should return a hidden string with the original string within', () => { + assert.equal(hiddenStringWithoutDiff, originalString); + }); + }); }); describe('rc4 (string: string, key: string): string', () => { - it('should encode string using the rc4 algorithm', () => { - const string: string = 'test'; - const key: string = 'key'; + const string: string = 'test'; + const key: string = 'key'; - assert.notEqual(CryptUtils.rc4(string, key), string); + let encodedString: string, + decodedString: string; + + before(() => { + encodedString = CryptUtils.rc4(string, key); + decodedString = CryptUtils.rc4(encodedString, key); + }); + + it('should encode string using the rc4 algorithm', () => { + assert.notEqual(encodedString, string); }); it('should encode and successfully decode string using the rc4 algorithm', () => { - const string: string = 'test'; - const key: string = 'key'; - - assert.equal(CryptUtils.rc4(CryptUtils.rc4(string, key), key), string); + assert.equal(decodedString, string); }); }); }); diff --git a/test/unit-tests/utils/random-generator-utils/RandomGeneratorUtils.spec.ts b/test/unit-tests/utils/random-generator-utils/RandomGeneratorUtils.spec.ts index 89f0ce41..ae614465 100644 --- a/test/unit-tests/utils/random-generator-utils/RandomGeneratorUtils.spec.ts +++ b/test/unit-tests/utils/random-generator-utils/RandomGeneratorUtils.spec.ts @@ -4,9 +4,29 @@ import { RandomGeneratorUtils } from '../../../../src/utils/RandomGeneratorUtils describe('RandomGeneratorUtils', () => { describe('getRandomVariableName (length: number = 6): string', () => { - it('should return a string of given length with random variable name', () => { - assert.match(RandomGeneratorUtils.getRandomVariableName(4), /^_0x(\w){4}$/); - assert.match(RandomGeneratorUtils.getRandomVariableName(6), /^_0x(\w){4,6}$/); + let randomVariableName: string, + regExp: RegExp; + + describe('variant #1: string with random variable of length `4`', () => { + before(() => { + randomVariableName = RandomGeneratorUtils.getRandomVariableName(4); + regExp = /^_0x(\w){4}$/; + }); + + it('should return random variable name', () => { + assert.match(randomVariableName, regExp); + }) + }); + + describe('variant #2: string with random variable of length `6`', () => { + before(() => { + randomVariableName = RandomGeneratorUtils.getRandomVariableName(6); + regExp = /^_0x(\w){4,6}$/; + }); + + it('should return random variable name', () => { + assert.match(randomVariableName, regExp); + }) }); }); }); diff --git a/test/unit-tests/utils/utils/Utils.spec.ts b/test/unit-tests/utils/utils/Utils.spec.ts index d312bbeb..dd120d77 100644 --- a/test/unit-tests/utils/utils/Utils.spec.ts +++ b/test/unit-tests/utils/utils/Utils.spec.ts @@ -6,108 +6,366 @@ import { JSFuck } from '../../../../src/enums/JSFuck'; describe('Utils', () => { describe('arrayRange (length: number): number[]', () => { - it('should return array with range of numbers', () => { - assert.deepEqual(Utils.arrayRange(5), [0, 1, 2, 3, 4]); + describe('range length more than 0', () => { + const rangeLength: number = 5; + const expectedArray: number[] = [0, 1, 2, 3, 4]; + + let array: number[]; + + before(() => { + array = Utils.arrayRange(rangeLength); + }); + + it('should return array with range of numbers', () => { + assert.deepEqual(array, expectedArray); + }); }); + describe('range length is 0', () => { + const rangeLength: number = 0; + const expectedArray: number[] = []; - it('should return empty array if length is 0', () => { - assert.deepEqual(Utils.arrayRange(0), []); + let array: number[]; + + before(() => { + array = Utils.arrayRange(rangeLength); + }); + + it('should return empty array', () => { + assert.deepEqual(array, expectedArray); + }); }); - it('should return empty array if length less then 0', () => { - assert.deepEqual(Utils.arrayRange(-5), []); + describe('range length less than 0', () => { + const rangeLength: number = -5; + const expectedArray: number[] = []; + + let array: number[]; + + before(() => { + array = Utils.arrayRange(rangeLength); + }); + + it('should return empty array', () => { + assert.deepEqual(array, expectedArray); + }); }); }); describe('arrayRotate (array: T[], times: number): T[]', () => { - let array: number[]; + let array: number[], + rotatedArray: number[]; beforeEach(() => { array = [1, 2, 3, 4, 5, 6]; }); - it('should rotate (shift) array by a given value', () => { - assert.deepEqual(Utils.arrayRotate(array, 2), [5, 6, 1, 2, 3, 4]); + describe('value is not 0', () => { + const rotateValue: number = 2; + const expectedArray: number[] = [5, 6, 1, 2, 3, 4]; + + beforeEach(() => { + rotatedArray = Utils.arrayRotate(array, rotateValue); + }); + + it('should rotate (shift) array by a given value', () => { + assert.deepEqual(rotatedArray, expectedArray); + }); }); + describe('value equals or less 0', () => { + const rotateValue: number = 0; + const expectedArray: number[] = [1, 2, 3, 4, 5, 6]; - it('should do nothing if value <= 0', () => { - assert.deepEqual(Utils.arrayRotate(array, 0), [1, 2, 3, 4, 5, 6]); - assert.deepEqual(Utils.arrayRotate(array, -1), [1, 2, 3, 4, 5, 6]); + beforeEach(() => { + rotatedArray = Utils.arrayRotate(array, rotateValue); + }); + + it('shouldn\'t rotate array', () => { + assert.deepEqual(rotatedArray, expectedArray); + }); }); - it('should throw exception if array is empty', () => { - assert.throws(() => Utils.arrayRotate([], 5), ReferenceError); + describe('empty array', () => { + const emptyArray: number[] = []; + const rotateValue: number = 5; + const expectedError: ReferenceErrorConstructor = ReferenceError; + + let testFunc: () => void; + + beforeEach(() => { + testFunc = () => Utils.arrayRotate(emptyArray, rotateValue); + }); + + it('should throw exception if array is empty', () => { + assert.throws(testFunc, expectedError); + }); }); }); describe('decToHex (dec: number): string', () => { - it('should creates a string with hexadecimal value from a given decimal number', () => { - assert.equal(Utils.decToHex(0), '0'); - assert.equal(Utils.decToHex(10), 'a'); - assert.equal(Utils.decToHex(17), '11'); - assert.equal(Utils.decToHex(536870912), '20000000'); + describe('variant #1: number `0`', () => { + const number: number = 0; + const expectedHexString = '0'; + + let hexString: string; + + before(() => { + hexString = Utils.decToHex(number); + }); + + it('should create a string with hexadecimal value from a given decimal number', () => { + assert.equal(hexString, expectedHexString); + }); + }); + + describe('variant #2: number `10`', () => { + const number: number = 10; + const expectedHexString = 'a'; + + let hexString: string; + + before(() => { + hexString = Utils.decToHex(number); + }); + + it('should create a string with hexadecimal value from a given decimal number', () => { + assert.equal(hexString, expectedHexString); + }); + }); + + describe('variant #3: number `17`', () => { + const number: number = 17; + const expectedHexString = '11'; + + let hexString: string; + + before(() => { + hexString = Utils.decToHex(number); + }); + + it('should create a string with hexadecimal value from a given decimal number', () => { + assert.equal(hexString, expectedHexString); + }); + }); + + describe('variant #4: number `536870912`', () => { + const number: number = 536870912; + const expectedHexString = '20000000'; + + let hexString: string; + + before(() => { + hexString = Utils.decToHex(number); + }); + + it('should create a string with hexadecimal value from a given decimal number', () => { + assert.equal(hexString, expectedHexString); + }); }); }); describe('extractDomainFromUrl (url: string): string', () => { - it('should extract domain from the given URL', () => { - assert.equal(Utils.extractDomainFromUrl('http://google.ru'), 'google.ru'); - assert.equal(Utils.extractDomainFromUrl('http://www.google.ru'), 'www.google.ru'); - assert.equal(Utils.extractDomainFromUrl('https://www.google.ru:9000'), 'www.google.ru'); - assert.equal(Utils.extractDomainFromUrl('//google.ru/abc'), 'google.ru'); - assert.equal(Utils.extractDomainFromUrl('//localhost:9000'), 'localhost'); + describe('variant #1: simple url', () => { + const url: string = 'http://google.ru'; + const expectedDomain: string = 'google.ru'; + + let domain: string; + + before(() => { + domain = Utils.extractDomainFromUrl(url); + }); + + it('should extract domain from the given URL', () => { + assert.equal(domain, expectedDomain); + }); + }); + + describe('variant #2: url with `www` part', () => { + const url: string = 'http://www.google.ru'; + const expectedDomain: string = 'www.google.ru'; + + let domain: string; + + before(() => { + domain = Utils.extractDomainFromUrl(url); + }); + + it('should extract domain from the given URL', () => { + assert.equal(domain, expectedDomain); + }); + }); + + describe('variant #3: url with `https` protocol and port', () => { + const url: string = 'https://www.google.ru:9000'; + const expectedDomain: string = 'www.google.ru'; + + let domain: string; + + before(() => { + domain = Utils.extractDomainFromUrl(url); + }); + + it('should extract domain from the given URL', () => { + assert.equal(domain, expectedDomain); + }); + }); + + describe('variant #4: protocol-wide url and route', () => { + const url: string = '//google.ru/abc'; + const expectedDomain: string = 'google.ru'; + + let domain: string; + + before(() => { + domain = Utils.extractDomainFromUrl(url); + }); + + it('should extract domain from the given URL', () => { + assert.equal(domain, expectedDomain); + }); + }); + + describe('variant #5: protocol-wide url, `localhost` and port', () => { + const url: string = '//localhost:9000'; + const expectedDomain: string = 'localhost'; + + let domain: string; + + before(() => { + domain = Utils.extractDomainFromUrl(url); + }); + + it('should extract domain from the given URL', () => { + assert.equal(domain, expectedDomain); + }); }); }); describe('isCeilNumber (number: number): boolean', () => { - it('should return true if given number is a ceil', () => { - assert.equal(Utils.isCeilNumber(4), true); - assert.equal(Utils.isCeilNumber(4.5), false); + describe('given number is a ceil', () => { + const number: number = 4; + const expectedResult: boolean = true; + + let result: boolean; + + before(() => { + result = Utils.isCeilNumber(number); + }); + + it('should return true', () => { + assert.equal(result, expectedResult); + }); + }); + + describe('given number is a float', () => { + const number: number = 4.5; + const expectedResult: boolean = false; + + let result: boolean; + + before(() => { + result = Utils.isCeilNumber(number); + }); + + it('should return false', () => { + assert.equal(result, expectedResult); + }); }); }); describe('stringRotate (string: string, times: number): string', () => { - let string: string; + const string: string = 'abcdefg'; - beforeEach(() => { - string = 'abcdefg'; + let rotatedString: string; + + describe('value is not 0', () => { + const rotateValue: number = 2; + const expectedString: string = 'fgabcde'; + + before(() => { + rotatedString = Utils.stringRotate(string, rotateValue); + }); + + it('should rotate string by a given value', () => { + assert.deepEqual(rotatedString, expectedString); + }); }); - it('should rotate string by a given value', () => { - assert.deepEqual(Utils.stringRotate(string, 2), 'fgabcde'); + describe('value equals or less 0', () => { + const rotateValue: number = 0; + const expectedString: string = 'abcdefg'; + + before(() => { + rotatedString = Utils.stringRotate(string, rotateValue); + }); + + it('shouldn\'t rotate string', () => { + assert.deepEqual(rotatedString, expectedString); + }); }); + describe('empty array', () => { + const emptyString: string = ''; + const rotateValue: number = 5; + const expectedError: ReferenceErrorConstructor = ReferenceError; - it('should do nothing if value <= 0', () => { - assert.deepEqual(Utils.stringRotate(string, 0), 'abcdefg'); - assert.deepEqual(Utils.stringRotate(string, -1), 'abcdefg'); - }); + let testFunc: () => void ; - it('should throw exception if string is empty', () => { - assert.throws(() => Utils.stringRotate('', 5), ReferenceError); + before(() => { + testFunc = () => Utils.stringRotate(emptyString, rotateValue); + }); + + it('should throw exception if string is empty', () => { + assert.throws(testFunc, expectedError); + }); }); }); describe('stringToJSFuck (string: string): string', () => { - let expected: string = `${JSFuck.s} + ${JSFuck.t} + ${JSFuck.r} + ${JSFuck.i} + ${JSFuck.n} + ${JSFuck.g}`; + const string: string = 'string'; + const expectedString: string = `${JSFuck.s} + ${JSFuck.t} + ${JSFuck.r} + ${JSFuck.i} + ${JSFuck.n} + ${JSFuck.g}`; - it('should creates a JSFuck encoded string from a given string', () => { - assert.equal(Utils.stringToJSFuck('string'), expected); + let actualString: string; + + before(() => { + actualString = Utils.stringToJSFuck(string); + }); + + it('should create a JSFuck encoded string from a given string', () => { + assert.equal(actualString, expectedString); }); }); describe('stringToUnicodeEscapeSequence (string: string, nonLatinAndNonDigitsOnly: boolean = false): string', () => { - const expected1: string = '\\x73\\x74\\x72\\x69\\x6e\\x67'; - const expected2: string = 'abc\\x21\\u0434\\u0435'; + describe('variant #1: default', () => { + const string: string = 'string'; + const expectedString: string = '\\x73\\x74\\x72\\x69\\x6e\\x67'; - it('should return a unicode escape sequence based on a given string', () => { - assert.equal(Utils.stringToUnicodeEscapeSequence('string'), expected1); + let actualString: string; + + before(() => { + actualString = Utils.stringToUnicodeEscapeSequence(string); + }); + + it('should return a unicode escape sequence based on a given string', () => { + assert.equal(actualString, expectedString); + }); }); - it('should return a string where only non-digits and non-latin letters are escaped', () => { - assert.equal(Utils.stringToUnicodeEscapeSequence('abc!де', true), expected2); + describe('variant #2: escape non-digits and non-latin letters', () => { + const string: string = 'abc!де'; + const expectedString: string = 'abc\\x21\\u0434\\u0435'; + + let actualString: string; + + before(() => { + actualString = Utils.stringToUnicodeEscapeSequence(string, true); + }); + + it('should return a string where only non-digits and non-latin letters are escaped', () => { + assert.equal(actualString, expectedString); + }); }); }); }); diff --git a/yarn.lock b/yarn.lock index abd71062..b377f3e8 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,17 +2,17 @@ # yarn lockfile v1 -"@types/chai@3.5.2": - version "3.5.2" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-3.5.2.tgz#c11cd2817d3a401b7ba0f5a420f35c56139b1c1e" +"@types/chai@4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.0.0.tgz#4c9adabd2d04265769e6d9e847e86cc404dc7dcd" "@types/chance@0.7.33": version "0.7.33" resolved "https://registry.yarnpkg.com/@types/chance/-/chance-0.7.33.tgz#9666ae5c8f602a14a67e5b608dabf1a7853a1e28" -"@types/commander@2.3.31": - version "2.3.31" - resolved "https://registry.yarnpkg.com/@types/commander/-/commander-2.3.31.tgz#c60e5517091f9e2200a5e2063a830eddac4a7036" +"@types/commander@2.9.1": + version "2.9.1" + resolved "https://registry.yarnpkg.com/@types/commander/-/commander-2.9.1.tgz#d4e464425baf4685bd49dd233be11de9c00c0784" dependencies: "@types/node" "*" @@ -44,13 +44,13 @@ version "2.2.41" resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-2.2.41.tgz#e27cf0817153eb9f2713b2d3f6c68f1e1c3ca608" -"@types/node@*", "@types/node@7.0.22": - version "7.0.22" - resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.22.tgz#4593f4d828bdd612929478ea40c67b4f403ca255" +"@types/node@*", "@types/node@7.0.29": + version "7.0.29" + resolved "https://registry.yarnpkg.com/@types/node/-/node-7.0.29.tgz#ccfcec5b7135c7caf6c4ffb8c7f33102340d99df" -"@types/sinon@2.2.2": - version "2.2.2" - resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-2.2.2.tgz#a80da4868ba08accacbce4d37276f35e1ba0a52f" +"@types/sinon@2.3.1": + version "2.3.1" + resolved "https://registry.yarnpkg.com/@types/sinon/-/sinon-2.3.1.tgz#5e214093e9e2345219ab0f31bf310c9790ad0712" "@types/string-template@1.0.2": version "1.0.2" @@ -823,9 +823,9 @@ center-align@^0.1.1: align-text "^0.1.3" lazy-cache "^1.0.3" -chai@4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/chai/-/chai-4.0.0.tgz#f6c989e45a5707d40c54d97ddd7ca89b30a6a06a" +chai@4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.0.2.tgz#2f7327c4de6f385dd7787999e2ab02697a32b83b" dependencies: assertion-error "^1.0.1" check-error "^1.0.1" @@ -1200,7 +1200,7 @@ escope@~1.0.1: dependencies: estraverse "^2.0.0" -esmangle@^1.0.1: +esmangle@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/esmangle/-/esmangle-1.0.1.tgz#d9bb37b8f8eafbf4e6d4ed6b7aa2956abbd3c4c2" dependencies: @@ -2326,7 +2326,7 @@ onetime@^2.0.0: dependencies: mimic-fn "^1.0.0" -opencollective@^1.0.3: +opencollective@1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/opencollective/-/opencollective-1.0.3.tgz#aee6372bc28144583690c3ca8daecfc120dd0ef1" dependencies: @@ -2344,7 +2344,7 @@ opn@4.0.2: object-assign "^4.0.1" pinkie-promise "^2.0.0" -optimist@^0.6.1, optimist@~0.6.0: +optimist@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" dependencies: @@ -2509,7 +2509,7 @@ pkg-dir@^1.0.0: dependencies: find-up "^1.0.0" -pre-commit@^1.2.2: +pre-commit@1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/pre-commit/-/pre-commit-1.2.2.tgz#dbcee0ee9de7235e57f79c56d7ce94641a69eec6" dependencies: @@ -2844,9 +2844,9 @@ signal-exit@^3.0.0, signal-exit@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" -sinon@2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/sinon/-/sinon-2.3.2.tgz#c43a9c570f32baac1159505cfeed19108855df89" +sinon@2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/sinon/-/sinon-2.3.3.tgz#fc09e93451e32cb2d08cab16a03bea69778853fc" dependencies: diff "^3.1.0" formatio "1.2.0" @@ -3082,9 +3082,9 @@ trim-right@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" -ts-node@3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-3.0.4.tgz#a1475ebf24fd4e2ee2fba8b1aa1605b977bde506" +ts-node@3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-3.0.6.tgz#55127ff790c7eebf6ba68c1e6dde94b09aaa21e0" dependencies: arrify "^1.0.0" chalk "^1.1.1" @@ -3095,7 +3095,7 @@ ts-node@3.0.4: source-map-support "^0.4.0" tsconfig "^6.0.0" v8flags "^2.0.11" - yn "^1.2.0" + yn "^2.0.0" tsconfig@^6.0.0: version "6.0.0" @@ -3104,7 +3104,7 @@ tsconfig@^6.0.0: strip-bom "^3.0.0" strip-json-comments "^2.0.0" -tslib@1.7.1, tslib@^1.6.0: +tslib@1.7.1, tslib@^1.7.1: version "1.7.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.7.1.tgz#bc8004164691923a79fe8378bbeb3da2017538ec" @@ -3118,23 +3118,24 @@ tslint-loader@3.5.3: rimraf "^2.4.4" semver "^5.3.0" -tslint@5.3.2: - version "5.3.2" - resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.3.2.tgz#e56459fb095a7307f103b84052174f5e3bbef6ed" +tslint@5.4.3: + version "5.4.3" + resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.4.3.tgz#761c8402b80e347b7733a04390a757b253580467" dependencies: babel-code-frame "^6.22.0" colors "^1.1.2" + commander "^2.9.0" diff "^3.2.0" glob "^7.1.1" - optimist "~0.6.0" + minimatch "^3.0.4" resolve "^1.3.2" semver "^5.3.0" - tslib "^1.6.0" - tsutils "^2.0.0" + tslib "^1.7.1" + tsutils "^2.3.0" -tsutils@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.1.0.tgz#5be8376c929528f65b302de9e17b0004e4c1eb20" +tsutils@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.3.0.tgz#96e661d7c2363f31adc8992ac67bbe7b7fc175e5" tty-browserify@0.0.0: version "0.0.0" @@ -3172,9 +3173,9 @@ typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" -typescript@2.3.3: - version "2.3.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.3.3.tgz#9639f3c3b40148e8ca97fe08a51dd1891bb6be22" +typescript@2.3.4: + version "2.3.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-2.3.4.tgz#3d38321828231e434f287514959c37a82b629f42" uglify-js@^2.6, uglify-js@^2.8.27: version "2.8.27" @@ -3312,7 +3313,7 @@ window-size@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" -wordwrap@0.0.2: +wordwrap@0.0.2, wordwrap@~0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" @@ -3320,10 +3321,6 @@ wordwrap@^1.0.0, wordwrap@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" -wordwrap@~0.0.2: - version "0.0.3" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" - wrap-ansi@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" @@ -3380,8 +3377,6 @@ yargs@~3.10.0: decamelize "^1.0.0" window-size "0.1.0" -yn@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/yn/-/yn-1.3.0.tgz#1b0812abb8d805d48966f8df385dc9dacc9a19d8" - dependencies: - object-assign "^4.1.1" +yn@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yn/-/yn-2.0.0.tgz#e5adabc8acf408f6385fc76495684c88e6af689a"