diff --git a/.eslintrc.json b/.eslintrc.json index d1d31b73..58dcc8b3 100755 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -97,6 +97,9 @@ "COMPILE_TIME": false, "COMPILE_MSG": false, - "PKG_VERSION": false + "PKG_VERSION": false, + "ENVIRONMENT_IS_WORKER": false, + "ENVIRONMENT_IS_NODE": false, + "ENVIRONMENT_IS_WEB": false } } diff --git a/Gruntfile.js b/Gruntfile.js index 9ff98c04..93e58857 100755 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -72,7 +72,16 @@ module.exports = function (grunt) { BUILD_CONSTANTS = { COMPILE_TIME: JSON.stringify(compileTime), COMPILE_MSG: JSON.stringify(grunt.option("compile-msg") || grunt.option("msg") || ""), - PKG_VERSION: JSON.stringify(pkg.version) + PKG_VERSION: JSON.stringify(pkg.version), + ENVIRONMENT_IS_WORKER: function() { + return typeof importScripts === "function"; + }, + ENVIRONMENT_IS_NODE: function() { + return typeof process === "object" && typeof require === "function"; + }, + ENVIRONMENT_IS_WEB: function() { + return typeof window === "object"; + } }, moduleEntryPoints = listEntryModules(); @@ -277,7 +286,10 @@ module.exports = function (grunt) { output: { filename: "index.js", path: __dirname + "/build/test" - } + }, + plugins: [ + new webpack.DefinePlugin(BUILD_CONSTANTS) + ] }, node: { target: "node", @@ -288,7 +300,10 @@ module.exports = function (grunt) { path: __dirname + "/build/node", library: "CyberChef", libraryTarget: "commonjs2" - } + }, + plugins: [ + new webpack.DefinePlugin(BUILD_CONSTANTS) + ] } }, "webpack-dev-server": { diff --git a/src/core/Chef.js b/src/core/Chef.js index 7da8ab59..7c9817df 100755 --- a/src/core/Chef.js +++ b/src/core/Chef.js @@ -30,7 +30,6 @@ const Chef = function() { * @returns {string} response.result - The output of the recipe * @returns {string} response.type - The data type of the result * @returns {number} response.progress - The position that we have got to in the recipe - * @returns {number} response.options - The app options object (which may have been changed) * @returns {number} response.duration - The number of ms it took to execute the recipe * @returns {number} response.error - The error object thrown by a failed operation (false if no error) */ @@ -40,12 +39,7 @@ Chef.prototype.bake = async function(inputText, recipeConfig, options, progress, containsFc = recipe.containsFlowControl(), error = false; - // Reset attemptHighlight flag - if (options.hasOwnProperty("attemptHighlight")) { - options.attemptHighlight = true; - } - - if (containsFc) options.attemptHighlight = false; + if (containsFc && ENVIRONMENT_IS_WORKER()) self.setOption("attemptHighlight", false); // Clean up progress if (progress >= recipeConfig.length) { @@ -86,7 +80,6 @@ Chef.prototype.bake = async function(inputText, recipeConfig, options, progress, this.dish.get(Dish.STRING), type: Dish.enumLookup(this.dish.type), progress: progress, - options: options, duration: new Date().getTime() - startTime, error: error }; diff --git a/src/core/ChefWorker.js b/src/core/ChefWorker.js index 22b5b81c..d3f0c032 100644 --- a/src/core/ChefWorker.js +++ b/src/core/ChefWorker.js @@ -41,23 +41,24 @@ self.postMessage({ */ self.addEventListener("message", function(e) { // Handle message - switch (e.data.action) { + const r = e.data; + switch (r.action) { case "bake": - bake(e.data.data); + bake(r.data); break; case "silentBake": - silentBake(e.data.data); + silentBake(r.data); break; case "docURL": // Used to set the URL of the current document so that scripts can be // imported into an inline worker. - self.docURL = e.data.data; + self.docURL = r.data; break; case "highlight": calculateHighlights( - e.data.data.recipeConfig, - e.data.data.direction, - e.data.data.pos + r.data.recipeConfig, + r.data.direction, + r.data.pos ); break; default: @@ -158,3 +159,20 @@ self.sendStatusMessage = function(msg) { data: msg }); }; + + +/** + * Send an option value update to the app. + * + * @param {string} option + * @param {*} value + */ +self.setOption = function(option, value) { + self.postMessage({ + action: "optionUpdate", + data: { + option: option, + value: value + } + }); +}; diff --git a/src/core/Utils.js b/src/core/Utils.js index 508c8e07..375c451d 100755 --- a/src/core/Utils.js +++ b/src/core/Utils.js @@ -234,7 +234,7 @@ const Utils = { * @returns {string} */ printable: function(str, preserveWs) { - if (typeof window !== "undefined" && window.app && !window.app.options.treatAsUtf8) { + if (ENVIRONMENT_IS_WEB() && window.app && !window.app.options.treatAsUtf8) { str = Utils.byteArrayToChars(Utils.strToByteArray(str)); } @@ -384,8 +384,12 @@ const Utils = { let wordArray = CryptoJS.enc.Utf8.parse(str), byteArray = Utils.wordArrayToByteArray(wordArray); - if (typeof window !== "undefined" && str.length !== wordArray.sigBytes) { - window.app.options.attemptHighlight = false; + if (str.length !== wordArray.sigBytes) { + if (ENVIRONMENT_IS_WORKER()) { + self.setOption("attemptHighlight", false); + } else if (ENVIRONMENT_IS_WEB()) { + window.app.options.attemptHighlight = false; + } } return byteArray; }, @@ -448,8 +452,13 @@ const Utils = { let wordArray = new CryptoJS.lib.WordArray.init(words, byteArray.length), str = CryptoJS.enc.Utf8.stringify(wordArray); - if (typeof window !== "undefined" && str.length !== wordArray.sigBytes) - window.app.options.attemptHighlight = false; + if (str.length !== wordArray.sigBytes) { + if (ENVIRONMENT_IS_WORKER()) { + self.setOption("attemptHighlight", false); + } else if (ENVIRONMENT_IS_WEB()) { + window.app.options.attemptHighlight = false; + } + } return str; } catch (err) { // If it fails, treat it as ANSI diff --git a/src/core/operations/BitwiseOp.js b/src/core/operations/BitwiseOp.js index f658cdb9..7512aa32 100755 --- a/src/core/operations/BitwiseOp.js +++ b/src/core/operations/BitwiseOp.js @@ -137,7 +137,8 @@ const BitwiseOp = { input = input.slice(sampleOffset, sampleOffset + sampleLength); - if (self) self.sendStatusMessage("Calculating " + Math.pow(256, keyLength) + " values..."); + if (ENVIRONMENT_IS_WORKER()) + self.sendStatusMessage("Calculating " + Math.pow(256, keyLength) + " values..."); /** * Converts an integer to an array of bytes expressing that number. @@ -156,7 +157,7 @@ const BitwiseOp = { }; for (let key = 1, l = Math.pow(256, keyLength); key < l; key++) { - if (key % 10000 === 0 && self) { + if (key % 10000 === 0 && ENVIRONMENT_IS_WORKER()) { self.sendStatusMessage("Calculating " + l + " values... " + Math.floor(key / l * 100) + "%"); } diff --git a/src/core/operations/ByteRepr.js b/src/core/operations/ByteRepr.js index 5a845c70..3564e5d6 100755 --- a/src/core/operations/ByteRepr.js +++ b/src/core/operations/ByteRepr.js @@ -119,11 +119,11 @@ const ByteRepr = { else if (ordinal < 4294967296) padding = 8; else padding = 2; - if (padding > 2 && app) app.options.attemptHighlight = false; + if (padding > 2 && ENVIRONMENT_IS_WORKER()) self.setOption("attemptHighlight", false); output += Utils.hex(ordinal, padding) + delim; } else { - if (app) app.options.attemptHighlight = false; + if (ENVIRONMENT_IS_WORKER()) self.setOption("attemptHighlight", false); output += ordinal.toString(base) + delim; } } @@ -149,9 +149,7 @@ const ByteRepr = { throw "Error: Base argument must be between 2 and 36"; } - if (base !== 16 && app) { - app.options.attemptHighlight = false; - } + if (base !== 16 && ENVIRONMENT_IS_WORKER()) self.setOption("attemptHighlight", false); // Split into groups of 2 if the whole string is concatenated and // too long to be a single character diff --git a/src/core/operations/Hexdump.js b/src/core/operations/Hexdump.js index f6d995f5..7bb08728 100755 --- a/src/core/operations/Hexdump.js +++ b/src/core/operations/Hexdump.js @@ -92,7 +92,7 @@ const Hexdump = { const w = (width - 13) / 4; // w should be the specified width of the hexdump and therefore a round number if (Math.floor(w) !== w || input.indexOf("\r") !== -1 || output.indexOf(13) !== -1) { - //TODO if (self) self.setOption("attemptHighlight", false); + if (ENVIRONMENT_IS_WORKER()) self.setOption("attemptHighlight", false); } return output; }, diff --git a/src/web/App.js b/src/web/App.js index e96dafcf..7dade878 100755 --- a/src/web/App.js +++ b/src/web/App.js @@ -105,6 +105,9 @@ App.prototype.handleError = function(err) { App.prototype.bake = function(step) { if (this.baking) return; + // Reset attemptHighlight flag + this.options.attemptHighlight = true; + this.manager.worker.bake( this.getInput(), // The user's input this.getRecipeConfig(), // The configuration of the recipe diff --git a/src/web/WorkerWaiter.js b/src/web/WorkerWaiter.js index 0d38c4f8..362ab128 100644 --- a/src/web/WorkerWaiter.js +++ b/src/web/WorkerWaiter.js @@ -40,12 +40,13 @@ WorkerWaiter.prototype.registerChefWorker = function() { * @param {MessageEvent} e */ WorkerWaiter.prototype.handleChefMessage = function(e) { - switch (e.data.action) { + const r = e.data; + switch (r.action) { case "bakeSuccess": - this.bakingComplete(e.data.data); + this.bakingComplete(r.data); break; case "bakeError": - this.app.handleError(e.data.data); + this.app.handleError(r.data); this.setBakingStatus(false); break; case "silentBakeComplete": @@ -55,10 +56,13 @@ WorkerWaiter.prototype.handleChefMessage = function(e) { this.app.loaded(); break; case "statusMessage": - this.manager.output.setStatusMsg(e.data.data); + this.manager.output.setStatusMsg(r.data); + break; + case "optionUpdate": + this.app.options[r.data.option] = r.data.value; break; case "highlightsCalculated": - this.manager.highlighter.displayHighlights(e.data.data.pos, e.data.data.direction); + this.manager.highlighter.displayHighlights(r.data.pos, r.data.direction); break; default: console.error("Unrecognised message from ChefWorker", e); @@ -104,7 +108,6 @@ WorkerWaiter.prototype.bakingComplete = function(response) { this.app.handleError(response.error); } - this.app.options = response.options; this.app.dishStr = response.type === "html" ? Utils.stripHtmlTags(response.result, true) : response.result; this.app.progress = response.progress; this.manager.recipe.updateBreakpointIndicator(response.progress);