diff --git a/src/web/BindingsWaiter.js b/src/web/BindingsWaiter.js new file mode 100644 index 00000000..8c06e18a --- /dev/null +++ b/src/web/BindingsWaiter.js @@ -0,0 +1,118 @@ +/** + * Waiter to handle keybindings to CyberChef functions (i.e. Bake, Step, Save, Load etc.) + * + * @author Matt C [matt@artemisbot.uk] + * @copyright Crown Copyright 2016 + * @license Apache-2.0 + * + * @constructor + * @param {App} app - The main view object for CyberChef. + * @param {Manager} manager - The CyberChef event manager. + */ +const BindingsWaiter = function (app, manager) { + this.app = app; + this.manager = manager; +}; + + +/** + * Handler for all keydown events + * Checks whether valid keyboard shortcut has been instated + * + * @fires Manager#statechange + * @param {event} e + */ +BindingsWaiter.prototype.parseInput = function(e) { + if (e.ctrlKey && e.altKey) { + let elem; + switch (e.code) { + case "KeyF": + e.preventDefault(); + document.getElementById("search").focus(); // Focus search + break; + case "KeyI": + e.preventDefault(); + document.getElementById("input-text").focus(); // Focus input + break; + case "KeyO": + e.preventDefault(); + document.getElementById("output-text").focus(); // Focus output + break; + case "Period": + try { + elem = document.activeElement.closest(".operation"); + if (elem.parentNode.lastChild === elem) { + elem.parentNode.firstChild.querySelectorAll(".arg")[0].focus(); // if operation is last in recipe, loop around to the top operation's first argument + } else { + elem.nextSibling.querySelectorAll(".arg")[0].focus(); //focus first argument of next operation + } + } catch (e) { + // do nothing, just don't throw an error + } + break; + case "KeyB": + try { + elem = document.activeElement.closest(".operation").querySelectorAll(".breakpoint")[0]; + if (elem.getAttribute("break") === "false") { + elem.setAttribute("break", "true"); // add break point if not already enabled + elem.classList.add("breakpoint-selected"); + } else { + elem.setAttribute("break", "false"); // remove break point if already enabled + elem.classList.remove("breakpoint-selected"); + } + window.dispatchEvent(this.manager.statechange); + } catch (e) { + // do nothing, just don't throw an error + } + break; + case "KeyD": + try { + elem = document.activeElement.closest(".operation").querySelectorAll(".disable-icon")[0]; + if (elem.getAttribute("disabled") === "false") { + elem.setAttribute("disabled", "true"); // disable operation if enabled + elem.classList.add("disable-elem-selected"); + elem.parentNode.parentNode.classList.add("disabled"); + } else { + elem.setAttribute("disabled", "false"); // enable operation if disabled + elem.classList.remove("disable-elem-selected"); + elem.parentNode.parentNode.classList.remove("disabled"); + } + this.app.progress = 0; + window.dispatchEvent(this.manager.statechange); + } catch (e) { + // do nothing, just don't throw an error + } + break; + case "Space": + this.app.bake(); // bake the recipe + break; + case "Quote": + this.app.bake(true); // step through the recipe + break; + case "KeyC": + this.manager.recipe.clearRecipe(); // clear recipe + break; + case "KeyS": + this.manager.output.saveClick(); // save output to file + break; + case "KeyL": + this.manager.controls.loadClick(); // load a recipe + break; + case "KeyM": + this.manager.controls.switchClick(); // switch input & output + break; + default: + if (e.code.match(/Digit[0-9]/g)) { + e.preventDefault(); + try { + document.querySelector(`li:nth-child(${e.code.substr(-1)}) .arg`).focus(); // select the first argument of the operation corresponding to the number pressed + } catch (e) { + // do nothing, just don't throw an error + } + } + break; + } + } +}; + +export default BindingsWaiter; diff --git a/src/web/Manager.js b/src/web/Manager.js index 1d32758c..de1df8e4 100755 --- a/src/web/Manager.js +++ b/src/web/Manager.js @@ -8,6 +8,7 @@ import OutputWaiter from "./OutputWaiter.js"; import OptionsWaiter from "./OptionsWaiter.js"; import HighlighterWaiter from "./HighlighterWaiter.js"; import SeasonalWaiter from "./SeasonalWaiter.js"; +import BindingsWaiter from "./BindingsWaiter.js"; /** @@ -60,6 +61,7 @@ const Manager = function(app) { this.options = new OptionsWaiter(this.app); this.highlighter = new HighlighterWaiter(this.app, this); this.seasonal = new SeasonalWaiter(this.app, this); + this.bindings = new BindingsWaiter(this.app, this); // Object to store dynamic handlers to fire on elements that may not exist yet this.dynamicHandlers = {}; @@ -89,7 +91,7 @@ Manager.prototype.initialiseEventListeners = function() { window.addEventListener("focus", this.window.windowFocus.bind(this.window)); window.addEventListener("statechange", this.app.stateChange.bind(this.app)); window.addEventListener("popstate", this.app.popState.bind(this.app)); - + window.addEventListener("keydown", this.bindings.parseInput.bind(this.bindings)); // Controls document.getElementById("bake").addEventListener("click", this.controls.bakeClick.bind(this.controls)); document.getElementById("auto-bake").addEventListener("change", this.controls.autoBakeChange.bind(this.controls)); diff --git a/src/web/html/index.html b/src/web/html/index.html index 8d23aed4..e1f300e7 100755 --- a/src/web/html/index.html +++ b/src/web/html/index.html @@ -1,17 +1,17 @@ + + Keybindings +
@@ -448,20 +453,20 @@
What

A simple, intuitive web app for analysing and decoding data without having to deal with complex tools or programming languages. CyberChef encourages both technical and non-technical people to explore data formats, encryption and compression.


- +
Why

Digital data comes in all shapes, sizes and formats in the modern world – CyberChef helps to make sense of this data all on one easy-to-use platform.


- +
How

The interface is designed with simplicity at its heart. Complex techniques are now as trivial as drag-and-drop. Simple functions can be combined to build up a "recipe", potentially resulting in complex analysis, which can be shared with other users and used with their input.

For those comfortable writing code, CyberChef is a quick and efficient way to prototype solutions to a problem which can then be scripted once proven to work.


- +
Who

It is expected that CyberChef will be useful for cybersecurity and antivirus companies. It should also appeal to the academic world and any individuals or companies involved in the analysis of digital data, be that software developers, analysts, mathematicians or casual puzzle solvers.


- +
Aim

It is hoped that by releasing CyberChef through GitHub, contributions can be added which can be rolled out into future versions of the tool.


@@ -470,6 +475,79 @@

There are around 150 useful operations in CyberChef for anyone working on anything vaguely Internet-related, whether you just want to convert a timestamp to a different format, decompress gzipped data, create a SHA3 hash, or parse an X.509 certificate to find out who issued it.

It’s the Cyber Swiss Army Knife.

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
CommandShortcut (Win/Linux)Shortcut (Mac)
Place cursor in search fieldCtrl+Alt+fCtrl+Opt+f
Place cursor in input boxCtrl+Alt+iCtrl+Opt+i
Place cursor in output boxCtrl+Alt+oCtrl+Opt+o
Place cursor in first argument field
of the next operation in the recipe
Ctrl+Alt+.Ctrl+Opt+.
Place cursor in first argument field
of the nth operation in the recipe
Ctrl+Alt+[1-9]Ctrl+Opt+[1-9]
Disable current operationCtrl+Alt+dCtrl+Opt+d
Set/clear breakpointCtrl+Alt+bCtrl+Opt+b
BakeCtrl+Alt+SpaceCtrl+Opt+Space
StepCtrl+Alt+'Ctrl+Opt+'
Clear recipeCtrl+Alt+cCtrl+Opt+c
Save to fileCtrl+Alt+sCtrl+Opt+s
Load recipeCtrl+Alt+lCtrl+Opt+l
Move output to inputCtrl+Alt+mCtrl+Opt+m
+
@@ -482,7 +560,7 @@ - + - +