From a07b8f693b047c2e7a8e8de458b832bb339d87b0 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Fri, 16 Sep 2022 19:24:57 +0100 Subject: [PATCH] Input and Output character encodings are now stored in the URL, allowing for accuate deeplinking --- src/web/App.mjs | 19 ++++++++++++---- src/web/utils/statusBar.mjs | 8 ++++--- src/web/waiters/ControlsWaiter.mjs | 5 +++++ src/web/waiters/InputWaiter.mjs | 36 ++++++++++++------------------ src/web/waiters/OutputWaiter.mjs | 13 ++++++++++- 5 files changed, 51 insertions(+), 30 deletions(-) diff --git a/src/web/App.mjs b/src/web/App.mjs index 4ead8bc4..d09d1e4f 100755 --- a/src/web/App.mjs +++ b/src/web/App.mjs @@ -451,6 +451,7 @@ class App { * Searches the URI parameters for recipe and input parameters. * If recipe is present, replaces the current recipe with the recipe provided in the URI. * If input is present, decodes and sets the input to the one provided in the URI. + * If character encodings are present, sets them appropriately. * If theme is present, uses the theme. * * @fires Manager#statechange @@ -490,6 +491,16 @@ class App { } catch (err) {} } + // Input Character Encoding + if (this.uriParams.ienc) { + this.manager.input.chrEncChange(parseInt(this.uriParams.ienc, 10)); + } + + // Output Character Encoding + if (this.uriParams.oenc) { + this.manager.output.chrEncChange(parseInt(this.uriParams.oenc, 10)); + } + // Read in theme from URI params if (this.uriParams.theme) { this.manager.options.changeTheme(Utils.escapeHtml(this.uriParams.theme)); @@ -731,19 +742,19 @@ class App { debounce(function() { this.progress = 0; this.autoBake(); - this.updateTitle(true, null, true); + this.updateURL(true, null, true); }, 20, "stateChange", this, [])(); } /** - * Update the page title to contain the new recipe + * Update the page title and URL to contain the new recipe * * @param {boolean} includeInput - * @param {string} input + * @param {string} [input=null] * @param {boolean} [changeUrl=true] */ - updateTitle(includeInput, input, changeUrl=true) { + updateURL(includeInput, input=null, changeUrl=true) { // Set title const recipeConfig = this.getRecipeConfig(); let title = "CyberChef"; diff --git a/src/web/utils/statusBar.mjs b/src/web/utils/statusBar.mjs index efabea81..97c6cff1 100644 --- a/src/web/utils/statusBar.mjs +++ b/src/web/utils/statusBar.mjs @@ -21,6 +21,7 @@ class StatusBarPanel { this.bakeStats = opts.bakeStats ? opts.bakeStats : null; this.eolHandler = opts.eolHandler; this.chrEncHandler = opts.chrEncHandler; + this.chrEncGetter = opts.chrEncGetter; this.eolVal = null; this.chrEncVal = null; @@ -222,9 +223,9 @@ class StatusBarPanel { /** * Gets the current character encoding of the document - * @param {number} chrEncVal */ - updateCharEnc(chrEncVal) { + updateCharEnc() { + const chrEncVal = this.chrEncGetter(); if (chrEncVal === this.chrEncVal) return; const name = CHR_ENC_SIMPLE_REVERSE_LOOKUP[chrEncVal] ? CHR_ENC_SIMPLE_REVERSE_LOOKUP[chrEncVal] : "Raw Bytes"; @@ -399,7 +400,7 @@ function makePanel(opts) { return (view) => { sbPanel.updateEOL(view.state); - sbPanel.updateCharEnc(opts.initialChrEncVal); + sbPanel.updateCharEnc(); sbPanel.updateBakeStats(); sbPanel.updateStats(view.state.doc); sbPanel.updateSelection(view.state, false); @@ -408,6 +409,7 @@ function makePanel(opts) { "dom": sbPanel.dom, update(update) { sbPanel.updateEOL(update.state); + sbPanel.updateCharEnc(); sbPanel.updateSelection(update.state, update.selectionSet); sbPanel.updateBakeStats(); if (update.geometryChanged) { diff --git a/src/web/waiters/ControlsWaiter.mjs b/src/web/waiters/ControlsWaiter.mjs index 2879089a..f0a87d6f 100755 --- a/src/web/waiters/ControlsWaiter.mjs +++ b/src/web/waiters/ControlsWaiter.mjs @@ -138,9 +138,14 @@ class ControlsWaiter { } } + const inputChrEnc = this.manager.input.inputChrEnc; + const outputChrEnc = this.manager.output.outputChrEnc; + const params = [ includeRecipe ? ["recipe", recipeStr] : undefined, includeInput && input.length ? ["input", Utils.escapeHtml(input)] : undefined, + inputChrEnc !== 0 ? ["ienc", inputChrEnc] : undefined, + outputChrEnc !== 0 ? ["oenc", outputChrEnc] : undefined ]; const hash = params diff --git a/src/web/waiters/InputWaiter.mjs b/src/web/waiters/InputWaiter.mjs index 86ad9873..c5b417a0 100644 --- a/src/web/waiters/InputWaiter.mjs +++ b/src/web/waiters/InputWaiter.mjs @@ -89,7 +89,7 @@ class InputWaiter { label: "Input", eolHandler: this.eolChange.bind(this), chrEncHandler: this.chrEncChange.bind(this), - initialChrEncVal: this.inputChrEnc + chrEncGetter: this.getChrEnc.bind(this) }), // Mutable state @@ -148,10 +148,19 @@ class InputWaiter { * @param {number} chrEncVal */ chrEncChange(chrEncVal) { + if (typeof chrEncVal !== "number") return; this.inputChrEnc = chrEncVal; this.inputChange(); } + /** + * Getter for the input character encoding + * @returns {number} + */ + getChrEnc() { + return this.inputChrEnc; + } + /** * Sets word wrap on the input editor * @param {boolean} wrap @@ -418,7 +427,7 @@ class InputWaiter { this.app.handleError(r.data); break; case "setUrl": - this.setUrl(r.data); + this.app.updateURL(r.data.includeInput, r.data.input); break; case "getInput": case "getInputNums": @@ -486,10 +495,7 @@ class InputWaiter { // Set URL to current input if (inputVal.length >= 0 && inputVal.length <= 51200) { const inputStr = toBase64(inputVal, "A-Za-z0-9+/"); - this.setUrl({ - includeInput: true, - input: inputStr - }); + this.app.updateURL(true, inputStr); } if (!silent) window.dispatchEvent(this.manager.statechange); @@ -616,10 +622,8 @@ class InputWaiter { const recipeStr = buffer.byteLength < 51200 ? toBase64(buffer, "A-Za-z0-9+/") : ""; // B64 alphabet with no padding - this.setUrl({ - includeInput: recipeStr.length > 0 && buffer.byteLength < 51200, - input: recipeStr - }); + const includeInput = recipeStr.length > 0 && buffer.byteLength < 51200; + this.app.updateURL(includeInput, recipeStr); const transferable = [buffer]; this.inputWorker.postMessage({ @@ -1326,18 +1330,6 @@ class InputWaiter { this.changeTab(inputNum, this.app.options.syncTabs); } - /** - * Update the input URL to the new value - * - * @param {object} urlData - Object containing the URL data - * @param {boolean} urlData.includeInput - If true, the input is included in the title - * @param {string} urlData.input - The input data to be included - */ - setUrl(urlData) { - this.app.updateTitle(urlData.includeInput, urlData.input, true); - } - - } export default InputWaiter; diff --git a/src/web/waiters/OutputWaiter.mjs b/src/web/waiters/OutputWaiter.mjs index f1965c77..5bfa5309 100755 --- a/src/web/waiters/OutputWaiter.mjs +++ b/src/web/waiters/OutputWaiter.mjs @@ -92,7 +92,7 @@ class OutputWaiter { bakeStats: this.bakeStats, eolHandler: this.eolChange.bind(this), chrEncHandler: this.chrEncChange.bind(this), - initialChrEncVal: this.outputChrEnc + chrEncGetter: this.getChrEnc.bind(this) }), htmlPlugin(this.htmlOutput), copyOverride(), @@ -145,9 +145,20 @@ class OutputWaiter { * @param {number} chrEncVal */ chrEncChange(chrEncVal) { + if (typeof chrEncVal !== "number") return; this.outputChrEnc = chrEncVal; // Reset the output, forcing it to re-decode the data with the new character encoding this.setOutput(this.currentOutputCache, true); + // Update the URL manually since we aren't firing a statechange event + this.app.updateURL(true); + } + + /** + * Getter for the input character encoding + * @returns {number} + */ + getChrEnc() { + return this.outputChrEnc; } /**