From d079420d46f0787664de6f5c856f6ecd5a018092 Mon Sep 17 00:00:00 2001 From: n1474335 Date: Thu, 28 Dec 2017 18:17:38 +0000 Subject: [PATCH 1/4] Added logging with configurable levels to make debugging easier. --- .eslintrc.json | 2 +- package-lock.json | 3 +-- package.json | 1 + src/core/Chef.js | 5 ++++- src/core/ChefWorker.js | 7 ++++++- src/core/Dish.js | 3 +++ src/core/Recipe.js | 3 +++ src/web/App.js | 5 +++-- src/web/InputWaiter.js | 1 + src/web/Manager.js | 3 ++- src/web/OptionsWaiter.js | 24 ++++++++++++++++++++++-- src/web/OutputWaiter.js | 3 ++- src/web/WorkerWaiter.js | 24 ++++++++++++++++++++++-- src/web/html/index.html | 11 +++++++++++ src/web/index.js | 6 ++---- test/index.js | 2 ++ webpack.config.js | 3 ++- 17 files changed, 88 insertions(+), 18 deletions(-) diff --git a/.eslintrc.json b/.eslintrc.json index b892ae6..629f7b1 100755 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -35,7 +35,6 @@ }], // disable rules from base configurations - "no-console": "off", "no-control-regex": "off", // stylistic conventions @@ -90,6 +89,7 @@ "$": false, "jQuery": false, "moment": false, + "log": false, "COMPILE_TIME": false, "COMPILE_MSG": false, diff --git a/package-lock.json b/package-lock.json index 5340292..a90959b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6132,8 +6132,7 @@ "loglevel": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/loglevel/-/loglevel-1.6.0.tgz", - "integrity": "sha1-rgyqVhERSYxboTcj1vtjHSQAOTQ=", - "dev": true + "integrity": "sha1-rgyqVhERSYxboTcj1vtjHSQAOTQ=" }, "longest": { "version": "1.0.1", diff --git a/package.json b/package.json index 18f57fb..99fcccd 100644 --- a/package.json +++ b/package.json @@ -87,6 +87,7 @@ "jsonpath": "^1.0.0", "jsrsasign": "8.0.4", "lodash": "^4.17.4", + "loglevel": "^1.6.0", "moment": "^2.20.1", "moment-timezone": "^0.5.14", "node-md6": "^0.1.0", diff --git a/src/core/Chef.js b/src/core/Chef.js index 8df6d52..0d71ce2 100755 --- a/src/core/Chef.js +++ b/src/core/Chef.js @@ -34,6 +34,7 @@ const Chef = function() { * @returns {number} response.error - The error object thrown by a failed operation (false if no error) */ Chef.prototype.bake = async function(input, recipeConfig, options, progress, step) { + log.debug("Chef baking"); let startTime = new Date().getTime(), recipe = new Recipe(recipeConfig), containsFc = recipe.containsFlowControl(), @@ -69,7 +70,7 @@ Chef.prototype.bake = async function(input, recipeConfig, options, progress, ste try { progress = await recipe.execute(this.dish, progress); } catch (err) { - console.log(err); + log.error(err); error = { displayStr: err.displayStr, }; @@ -112,6 +113,8 @@ Chef.prototype.bake = async function(input, recipeConfig, options, progress, ste * @returns {number} The time it took to run the silent bake in milliseconds. */ Chef.prototype.silentBake = function(recipeConfig) { + log.debug("Running silent bake"); + let startTime = new Date().getTime(), recipe = new Recipe(recipeConfig), dish = new Dish("", Dish.STRING); diff --git a/src/core/ChefWorker.js b/src/core/ChefWorker.js index 4bb7f9e..899f666 100644 --- a/src/core/ChefWorker.js +++ b/src/core/ChefWorker.js @@ -42,6 +42,8 @@ self.postMessage({ self.addEventListener("message", function(e) { // Handle message const r = e.data; + log.debug("ChefWorker receiving command '" + r.action + "'"); + switch (r.action) { case "bake": bake(r.data); @@ -61,6 +63,9 @@ self.addEventListener("message", function(e) { r.data.pos ); break; + case "setLogLevel": + log.setLevel(r.data, false); + break; default: break; } @@ -121,7 +126,7 @@ function loadRequiredModules(recipeConfig) { let module = self.OperationConfig[op.op].module; if (!OpModules.hasOwnProperty(module)) { - console.log("Loading module " + module); + log.info("Loading module " + module); self.sendStatusMessage("Loading module " + module); self.importScripts(self.docURL + "/" + module + ".js"); } diff --git a/src/core/Dish.js b/src/core/Dish.js index 4a16919..001f78e 100755 --- a/src/core/Dish.js +++ b/src/core/Dish.js @@ -111,6 +111,7 @@ Dish.enumLookup = function(typeEnum) { * @param {number} type - The data type of value, see Dish enums. */ Dish.prototype.set = function(value, type) { + log.debug("Dish type: " + Dish.enumLookup(type)); this.value = value; this.type = type; @@ -141,6 +142,8 @@ Dish.prototype.get = function(type) { * @param {number} toType - The data type of value, see Dish enums. */ Dish.prototype.translate = function(toType) { + log.debug(`Translating Dish from ${Dish.enumLookup(this.type)} to ${Dish.enumLookup(toType)}`); + // Convert data to intermediate byteArray type switch (this.type) { case Dish.STRING: diff --git a/src/core/Recipe.js b/src/core/Recipe.js index fdd0694..6f2fb16 100755 --- a/src/core/Recipe.js +++ b/src/core/Recipe.js @@ -150,14 +150,17 @@ Recipe.prototype.execute = async function(dish, startFrom) { for (let i = startFrom; i < this.opList.length; i++) { op = this.opList[i]; if (op.isDisabled()) { + log.debug(`[${i}] '${op.name}' is disabled`); continue; } if (op.isBreakpoint()) { + log.debug(`[${i}] Pausing at breakpoint on '${op.name}'`); return i; } try { input = dish.get(op.inputType); + log.debug(`[${i}] Executing '${op.name}'`); if (op.isFlowControl()) { // Package up the current state diff --git a/src/web/App.js b/src/web/App.js index d877791..eb174e7 100755 --- a/src/web/App.js +++ b/src/web/App.js @@ -91,7 +91,7 @@ App.prototype.loaded = function() { * @param {boolean} [logToConsole=false] */ App.prototype.handleError = function(err, logToConsole) { - if (logToConsole) console.error(err); + if (logToConsole) log.error(err); const msg = err.displayStr || err.toString(); this.alert(msg, "danger", this.options.errorTimeout, !this.options.showErrors); }; @@ -129,6 +129,7 @@ App.prototype.autoBake = function() { if (this.autoBakePause) return false; if (this.autoBake_ && !this.baking) { + log.debug("Auto-baking"); this.bake(); } else { this.manager.controls.showStaleIndicator(); @@ -569,7 +570,7 @@ App.prototype.isLocalStorageAvailable = function() { App.prototype.alert = function(str, style, timeout, silent) { const time = new Date(); - console.log("[" + time.toLocaleString() + "] " + str); + log.info("[" + time.toLocaleString() + "] " + str); if (silent) return; style = style || "danger"; diff --git a/src/web/InputWaiter.js b/src/web/InputWaiter.js index af3f72e..33784ed 100755 --- a/src/web/InputWaiter.js +++ b/src/web/InputWaiter.js @@ -215,6 +215,7 @@ InputWaiter.prototype.handleLoaderMessage = function(e) { } if (r.hasOwnProperty("fileBuffer")) { + log.debug("Input file loaded"); this.fileBuffer = r.fileBuffer; window.dispatchEvent(this.manager.statechange); } diff --git a/src/web/Manager.js b/src/web/Manager.js index 39aaf40..c19ddaf 100755 --- a/src/web/Manager.js +++ b/src/web/Manager.js @@ -58,7 +58,7 @@ const Manager = function(app) { this.ops = new OperationsWaiter(this.app, this); this.input = new InputWaiter(this.app, this); this.output = new OutputWaiter(this.app, this); - this.options = new OptionsWaiter(this.app); + this.options = new OptionsWaiter(this.app, this); this.highlighter = new HighlighterWaiter(this.app, this); this.seasonal = new SeasonalWaiter(this.app, this); this.bindings = new BindingsWaiter(this.app, this); @@ -172,6 +172,7 @@ Manager.prototype.initialiseEventListeners = function() { this.addDynamicListener(".option-item input[type=number]", "change", this.options.numberChange, this.options); this.addDynamicListener(".option-item select", "change", this.options.selectChange, this.options); document.getElementById("theme").addEventListener("change", this.options.themeChange.bind(this.options)); + document.getElementById("logLevel").addEventListener("change", this.options.logLevelChange.bind(this.options)); // Misc window.addEventListener("keydown", this.bindings.parseInput.bind(this.bindings)); diff --git a/src/web/OptionsWaiter.js b/src/web/OptionsWaiter.js index b3eb364..f121c46 100755 --- a/src/web/OptionsWaiter.js +++ b/src/web/OptionsWaiter.js @@ -8,8 +8,9 @@ * @constructor * @param {App} app - The main view object for CyberChef. */ -const OptionsWaiter = function(app) { +const OptionsWaiter = function(app, manager) { this.app = app; + this.manager = manager; }; @@ -86,6 +87,7 @@ OptionsWaiter.prototype.switchChange = function(e, state) { const el = e.target; const option = el.getAttribute("option"); + log.debug(`Setting ${option} to ${state}`); this.app.options[option] = state; if (this.app.isLocalStorageAvailable()) @@ -102,8 +104,10 @@ OptionsWaiter.prototype.switchChange = function(e, state) { OptionsWaiter.prototype.numberChange = function(e) { const el = e.target; const option = el.getAttribute("option"); + const val = parseInt(el.value, 10); - this.app.options[option] = parseInt(el.value, 10); + log.debug(`Setting ${option} to ${val}`); + this.app.options[option] = val; if (this.app.isLocalStorageAvailable()) localStorage.setItem("options", JSON.stringify(this.app.options)); @@ -120,6 +124,7 @@ OptionsWaiter.prototype.selectChange = function(e) { const el = e.target; const option = el.getAttribute("option"); + log.debug(`Setting ${option} to ${el.value}`); this.app.options[option] = el.value; if (this.app.isLocalStorageAvailable()) @@ -149,6 +154,8 @@ OptionsWaiter.prototype.setWordWrap = function() { /** * Changes the theme by setting the class of the element. + * + * @param {Event} e */ OptionsWaiter.prototype.themeChange = function (e) { const themeClass = e.target.value; @@ -156,4 +163,17 @@ OptionsWaiter.prototype.themeChange = function (e) { document.querySelector(":root").className = themeClass; }; + +/** + * Changes the console logging level. + * + * @param {Event} e + */ +OptionsWaiter.prototype.logLevelChange = function (e) { + const level = e.target.value; + log.info("Setting log level to " + level); + log.setLevel(level, false); + this.manager.worker.setLogLevel(); +}; + export default OptionsWaiter; diff --git a/src/web/OutputWaiter.js b/src/web/OutputWaiter.js index 4274273..6012975 100755 --- a/src/web/OutputWaiter.js +++ b/src/web/OutputWaiter.js @@ -41,6 +41,7 @@ OutputWaiter.prototype.get = function() { * @param {boolean} [preserveBuffer=false] - Whether to preserve the dishBuffer */ OutputWaiter.prototype.set = function(data, type, duration, preserveBuffer) { + log.debug("Output type: " + type); const outputText = document.getElementById("output-text"); const outputHtml = document.getElementById("output-html"); const outputFile = document.getElementById("output-file"); @@ -73,7 +74,7 @@ OutputWaiter.prototype.set = function(data, type, duration, preserveBuffer) { try { eval(scriptElements[i].innerHTML); // eslint-disable-line no-eval } catch (err) { - console.error(err); + log.error(err); } } break; diff --git a/src/web/WorkerWaiter.js b/src/web/WorkerWaiter.js index 402b56b..7d4dbf2 100644 --- a/src/web/WorkerWaiter.js +++ b/src/web/WorkerWaiter.js @@ -21,8 +21,10 @@ const WorkerWaiter = function(app, manager) { * Sets up the ChefWorker and associated listeners. */ WorkerWaiter.prototype.registerChefWorker = function() { + log.debug("Registering new ChefWorker"); this.chefWorker = new ChefWorker(); this.chefWorker.addEventListener("message", this.handleChefMessage.bind(this)); + this.setLogLevel(); let docURL = document.location.href.split(/[#?]/)[0]; const index = docURL.lastIndexOf("/"); @@ -40,6 +42,8 @@ WorkerWaiter.prototype.registerChefWorker = function() { */ WorkerWaiter.prototype.handleChefMessage = function(e) { const r = e.data; + log.debug("Receiving '" + r.action + "' from ChefWorker"); + switch (r.action) { case "bakeSuccess": this.bakingComplete(r.data); @@ -58,6 +62,7 @@ WorkerWaiter.prototype.handleChefMessage = function(e) { this.manager.output.setStatusMsg(r.data); break; case "optionUpdate": + log.debug(`Setting ${r.data.option} to ${r.data.value}`); this.app.options[r.data.option] = r.data.value; break; case "setRegisters": @@ -67,7 +72,7 @@ WorkerWaiter.prototype.handleChefMessage = function(e) { this.manager.highlighter.displayHighlights(r.data.pos, r.data.direction); break; default: - console.error("Unrecognised message from ChefWorker", e); + log.error("Unrecognised message from ChefWorker", e); break; } }; @@ -145,7 +150,7 @@ WorkerWaiter.prototype.bake = function(input, recipeConfig, options, progress, s * Asks the ChefWorker to run a silent bake, forcing the browser to load and cache all the relevant * JavaScript code needed to do a real bake. * - * @param {Objectp[]} [recipeConfig] + * @param {Object[]} [recipeConfig] */ WorkerWaiter.prototype.silentBake = function(recipeConfig) { this.chefWorker.postMessage({ @@ -178,4 +183,19 @@ WorkerWaiter.prototype.highlight = function(recipeConfig, direction, pos) { }; +/** + * Sets the console log level in the worker. + * + * @param {string} level + */ +WorkerWaiter.prototype.setLogLevel = function(level) { + if (!this.chefWorker) return; + + this.chefWorker.postMessage({ + action: "setLogLevel", + data: log.getLevel() + }); +}; + + export default WorkerWaiter; diff --git a/src/web/html/index.html b/src/web/html/index.html index ea5fec3..6dd6ff5 100755 --- a/src/web/html/index.html +++ b/src/web/html/index.html @@ -372,6 +372,17 @@ +
+ + +