diff --git a/src/web/App.mjs b/src/web/App.mjs index 534e7983..86a97314 100755 --- a/src/web/App.mjs +++ b/src/web/App.mjs @@ -79,9 +79,6 @@ class App { if (!this.workerLoaded || !this.appLoaded || !document.getElementById("loader-wrapper")) return; - // Bake initial input - this.getAllInput(); - // Trigger CSS animations to remove preloader document.body.classList.add("loaded"); @@ -90,7 +87,10 @@ class App { setTimeout(function() { document.getElementById("loader-wrapper").remove(); document.body.classList.remove("loaded"); - }, 1000); + + // Bake initial input + this.getAllInput(); + }.bind(this), 1000); // Clear the loading message interval clearInterval(window.loadingMsgsInt); @@ -125,7 +125,7 @@ class App { * whole recipe. */ bake(step=false, input) { - // if (this.baking) return; + if (this.baking) return; // Reset attemptHighlight flag this.options.attemptHighlight = true; @@ -151,7 +151,7 @@ class App { // has completed. if (this.autoBakePause) return false; - if (this.autoBake_ && !this.baking) { + if (this.autoBake_) { log.debug("Auto-baking"); this.manager.input.inputWorker.postMessage({ action: "autobake", @@ -662,6 +662,16 @@ class App { this.progress = 0; this.autoBake(); + this.updateUrl(false, ""); + } + + /** + * Update the page URL to contain the new recipe and input + * + * @param {boolean} includeInput + * @param {string} input + */ + updateUrl(includeInput, input) { // Set title const recipeConfig = this.getRecipeConfig(); let title = "CyberChef"; @@ -681,8 +691,8 @@ class App { // Update the current history state (not creating a new one) if (this.options.updateUrl) { - // this.lastStateUrl = this.manager.controls.generateStateUrl(true, true, recipeConfig); - // window.history.replaceState({}, title, this.lastStateUrl); + this.lastStateUrl = this.manager.controls.generateStateUrl(true, includeInput, input, recipeConfig); + window.history.replaceState({}, title, this.lastStateUrl); } } diff --git a/src/web/ControlsWaiter.mjs b/src/web/ControlsWaiter.mjs index 70214bd6..21655f8d 100755 --- a/src/web/ControlsWaiter.mjs +++ b/src/web/ControlsWaiter.mjs @@ -117,22 +117,19 @@ class ControlsWaiter { * @param {string} [baseURL] - The CyberChef URL, set to the current URL if not included * @returns {string} */ - generateStateUrl(includeRecipe, includeInput, recipeConfig, baseURL) { + generateStateUrl(includeRecipe, includeInput, input, recipeConfig, baseURL) { recipeConfig = recipeConfig || this.app.getRecipeConfig(); const link = baseURL || window.location.protocol + "//" + window.location.host + window.location.pathname; const recipeStr = Utils.generatePrettyRecipe(recipeConfig); - const inputStr = toBase64(this.app.getInput().input, "A-Za-z0-9+/"); // B64 alphabet with no padding includeRecipe = includeRecipe && (recipeConfig.length > 0); - // Only inlcude input if it is less than 50KB (51200 * 4/3 as it is Base64 encoded) - includeInput = includeInput && (inputStr.length > 0) && (inputStr.length <= 68267); const params = [ includeRecipe ? ["recipe", recipeStr] : undefined, - includeInput ? ["input", inputStr] : undefined, + includeInput ? ["input", input] : undefined, ]; const hash = params diff --git a/src/web/InputWaiter.mjs b/src/web/InputWaiter.mjs index 08cfb986..1f403570 100644 --- a/src/web/InputWaiter.mjs +++ b/src/web/InputWaiter.mjs @@ -89,6 +89,10 @@ class InputWaiter { action: "updateMaxTabs", data: this.maxTabs }); + this.inputWorker.postMessage({ + action: "setLogLevel", + data: log.getLevel() + }); this.inputWorker.addEventListener("message", this.handleInputWorkerMessage.bind(this)); @@ -269,6 +273,9 @@ class InputWaiter { case "displayTabSearchResults": this.displayTabSearchResults(r.data); break; + case "setUrl": + this.setUrl(r.data); + break; default: log.error(`Unknown action ${r.action}.`); } @@ -1199,6 +1206,17 @@ class InputWaiter { this.changeTab(inputNum, this.app.options.syncTabs); } + /** + * Update the input URL to the new value + * + * @param {object} urlData + * @param {boolean} urlData.includeInput + * @param {string} urlData.input + */ + setUrl(urlData) { + this.app.updateUrl(urlData.includeInput, urlData.input); + } + } diff --git a/src/web/InputWorker.mjs b/src/web/InputWorker.mjs index d02d3cf7..0d80dd8c 100644 --- a/src/web/InputWorker.mjs +++ b/src/web/InputWorker.mjs @@ -7,6 +7,7 @@ */ import Utils from "../core/Utils"; +import {toBase64} from "../core/lib/Base64"; self.maxWorkers = 4; self.maxTabs = 1; @@ -28,6 +29,8 @@ self.addEventListener("message", function(e) { return; } + log.debug(`Receiving ${r.action} from InputWaiter.`); + switch (r.action) { case "loadUIFiles": self.loadFiles(r.data); @@ -306,13 +309,14 @@ self.setInput = function(inputData) { const input = self.getInputObj(inputNum); if (input === undefined || input === null) return; - const inputVal = input.data; + let inputVal = input.data; const inputObj = { inputNum: inputNum, input: inputVal }; if (typeof inputVal !== "string") { - const fileSlice = inputVal.fileBuffer.slice(0, 512001); + inputVal = inputVal.fileBuffer; + const fileSlice = inputVal.slice(0, 512001); inputObj.input = fileSlice; inputObj.name = inputVal.name; inputObj.size = inputVal.size; @@ -385,6 +389,20 @@ self.updateInputValue = function(inputData) { } self.inputs[inputNum].status = "loaded"; self.inputs[inputNum].progress = 100; + + let includeInput = false; + const recipeStr = toBase64(value, "A-Za-z0-9+/"); // B64 alphabet with no padding + if (recipeStr.length > 0 && recipeStr.length <= 68267) { + includeInput = true; + } + + self.postMessage({ + action: "setUrl", + data: { + includeInput: includeInput, + input: recipeStr + } + }); return; } diff --git a/src/web/Manager.mjs b/src/web/Manager.mjs index b4191519..37bb5386 100755 --- a/src/web/Manager.mjs +++ b/src/web/Manager.mjs @@ -335,7 +335,6 @@ class Manager { } } } - } export default Manager; diff --git a/src/web/WorkerWaiter.mjs b/src/web/WorkerWaiter.mjs index 2a8bea9e..e92d665c 100644 --- a/src/web/WorkerWaiter.mjs +++ b/src/web/WorkerWaiter.mjs @@ -69,7 +69,12 @@ class WorkerWaiter { if (index > 0) { docURL = docURL.substring(0, index); } + newWorker.postMessage({"action": "docURL", "data": docURL}); + newWorker.postMessage({ + action: "setLogLevel", + data: log.getLevel() + }); // Store the worker, whether or not it's active, and the inputNum as an object const newWorkerObj = { @@ -138,7 +143,6 @@ class WorkerWaiter { log.debug(`Bake ${inputNum} complete.`); this.updateOutput(r.data, r.data.inputNum); this.workerFinished(currentWorker); - break; case "bakeError": if (!r.data.hasOwnProperty("progress")) this.app.handleError(r.data.error); @@ -315,12 +319,12 @@ class WorkerWaiter { if (!this.chefWorkers[workerIdx]) return; const nextInput = this.inputs.splice(0, 1)[0]; + if (typeof nextInput.inputNum === "string") nextInput.inputNum = parseInt(nextInput.inputNum, 10); log.debug(`Baking input ${nextInput.inputNum}.`); this.manager.output.updateOutputStatus("baking", nextInput.inputNum); this.manager.output.updateOutputMessage(`Baking input ${nextInput.inputNum}...`, nextInput.inputNum); - this.chefWorkers[workerIdx].inputNum = nextInput.inputNum; this.chefWorkers[workerIdx].active = true; const input = nextInput.input; @@ -384,6 +388,21 @@ class WorkerWaiter { * @param {number} inputData.inputNum */ queueInput(inputData) { + for (let i = 0; i < this.inputs.length; i++) { + if (this.inputs[i].inputNum === inputData.inputNum) { + this.inputs[i] = inputData; + return; + } + } + for (let i = 0; i < this.chefWorkers; i++) { + if (this.chefWorkers[i].inputNum === inputData.inputNum) { + this.chefWorkers[i].worker.terminate(); + this.chefWorkers.splice(i, 1); + this.bakeNextInput(this.addChefWorker()); + this.bakingInputs--; + break; + } + } this.manager.output.updateOutputStatus("pending", inputData.inputNum); this.manager.output.updateOutputMessage(`Input ${inputData.inputNum} has not been baked yet.`);