Highlighting now works with the web worker

This commit is contained in:
n1474335 2017-09-19 23:34:03 +01:00
parent 8c960f0661
commit 13f07abb8a
10 changed files with 200 additions and 95 deletions

View File

@ -123,4 +123,38 @@ Chef.prototype.silentBake = function(recipeConfig) {
return new Date().getTime() - startTime;
};
/**
* Calculates highlight offsets if possible.
*
* @param {Object[]} recipeConfig
* @param {string} direction
* @param {Object} pos - The position object for the highlight.
* @param {number} pos.start - The start offset.
* @param {number} pos.end - The end offset.
* @returns {Object}
*/
Chef.prototype.calculateHighlights = function(recipeConfig, direction, pos) {
const recipe = new Recipe(recipeConfig);
const highlights = recipe.generateHighlightList();
if (!highlights) return false;
for (let i = 0; i < highlights.length; i++) {
// Remove multiple highlights before processing again
pos = [pos[0]];
const func = direction === "forward" ? highlights[i].f : highlights[i].b;
if (typeof func == "function") {
pos = func(pos, highlights[i].args);
}
}
return {
pos: pos,
direction: direction
};
};
export default Chef;

View File

@ -53,6 +53,13 @@ self.addEventListener("message", function(e) {
// imported into an inline worker.
self.docURL = e.data.data;
break;
case "highlight":
calculateHighlights(
e.data.data.recipeConfig,
e.data.data.direction,
e.data.data.pos
);
break;
default:
break;
}
@ -121,6 +128,25 @@ function loadRequiredModules(recipeConfig) {
}
/**
* Calculates highlight offsets if possible.
*
* @param {Object[]} recipeConfig
* @param {string} direction
* @param {Object} pos - The position object for the highlight.
* @param {number} pos.start - The start offset.
* @param {number} pos.end - The end offset.
*/
function calculateHighlights(recipeConfig, direction, pos) {
pos = self.chef.calculateHighlights(recipeConfig, direction, pos);
self.postMessage({
action: "highlightsCalculated",
data: pos
});
}
/**
* Send status update to the app.
*

View File

@ -54,6 +54,14 @@ Operation.prototype._parseConfig = function(operationConfig) {
const ingredient = new Ingredient(ingredientConfig);
this.addIngredient(ingredient);
}
if (this.highlight === "func") {
this.highlight = OpModules[this.module][`${this.name}-highlight`];
}
if (this.highlightReverse === "func") {
this.highlightReverse = OpModules[this.module][`${this.name}-highlightReverse`];
}
};

View File

@ -215,4 +215,37 @@ Recipe.prototype.fromString = function(recipeStr) {
this._parseConfig(recipeConfig);
};
/**
* Generates a list of all the highlight functions assigned to operations in the recipe, if the
* entire recipe supports highlighting.
*
* @returns {Object[]} highlights
* @returns {function} highlights[].f
* @returns {function} highlights[].b
* @returns {Object[]} highlights[].args
*/
Recipe.prototype.generateHighlightList = function() {
const highlights = [];
for (let i = 0; i < this.opList.length; i++) {
let op = this.opList[i];
if (op.isDisabled()) continue;
// If any breakpoints are set, do not attempt to highlight
if (op.isBreakpoint()) return false;
// If any of the operations do not support highlighting, fail immediately.
if (op.highlight === false || op.highlight === undefined) return false;
highlights.push({
f: op.highlight,
b: op.highlightReverse,
args: op.getIngValues()
});
}
return highlights;
};
export default Recipe;

View File

@ -184,8 +184,8 @@ const OperationConfig = {
"From Base64": {
module: "Default",
description: "Base64 is a notation for encoding arbitrary byte data using a restricted set of symbols that can be conveniently used by humans and processed by computers.<br><br>This operation decodes data from an ASCII Base64 string back into its raw format.<br><br>e.g. <code>aGVsbG8=</code> becomes <code>hello</code>",
highlight: Base64.highlightFrom,
highlightReverse: Base64.highlightTo,
highlight: "func",
highlightReverse: "func",
inputType: "string",
outputType: "byteArray",
args: [
@ -195,7 +195,7 @@ const OperationConfig = {
value: Base64.ALPHABET_OPTIONS
},
{
name: "Remove non&#8209;alphabet chars",
name: "Remove non-alphabet chars",
type: "boolean",
value: Base64.REMOVE_NON_ALPH_CHARS
}
@ -204,8 +204,8 @@ const OperationConfig = {
"To Base64": {
module: "Default",
description: "Base64 is a notation for encoding arbitrary byte data using a restricted set of symbols that can be conveniently used by humans and processed by computers.<br><br>This operation encodes data in an ASCII Base64 string.<br><br>e.g. <code>hello</code> becomes <code>aGVsbG8=</code>",
highlight: Base64.highlightTo,
highlightReverse: Base64.highlightFrom,
highlight: "func",
highlightReverse: "func",
inputType: "byteArray",
outputType: "string",
args: [
@ -228,7 +228,7 @@ const OperationConfig = {
value: Base58.ALPHABET_OPTIONS
},
{
name: "Remove non&#8209;alphabet chars",
name: "Remove non-alphabet chars",
type: "boolean",
value: Base58.REMOVE_NON_ALPH_CHARS
}
@ -259,7 +259,7 @@ const OperationConfig = {
value: Base64.BASE32_ALPHABET
},
{
name: "Remove non&#8209;alphabet chars",
name: "Remove non-alphabet chars",
type: "boolean",
value: Base64.REMOVE_NON_ALPH_CHARS
}
@ -446,8 +446,8 @@ const OperationConfig = {
"From Hex": {
module: "Default",
description: "Converts a hexadecimal byte string back into its raw value.<br><br>e.g. <code>ce 93 ce b5 ce b9 ce ac 20 cf 83 ce bf cf 85 0a</code> becomes the UTF-8 encoded string <code>Γειά σου</code>",
highlight: ByteRepr.highlightFrom,
highlightReverse: ByteRepr.highlightTo,
highlight: "func",
highlightReverse: "func",
inputType: "string",
outputType: "byteArray",
args: [
@ -461,8 +461,8 @@ const OperationConfig = {
"To Hex": {
module: "Default",
description: "Converts the input string to hexadecimal bytes separated by the specified delimiter.<br><br>e.g. The UTF-8 encoded string <code>Γειά σου</code> becomes <code>ce 93 ce b5 ce b9 ce ac 20 cf 83 ce bf cf 85 0a</code>",
highlight: ByteRepr.highlightTo,
highlightReverse: ByteRepr.highlightFrom,
highlight: "func",
highlightReverse: "func",
inputType: "byteArray",
outputType: "string",
args: [
@ -506,8 +506,8 @@ const OperationConfig = {
"From Charcode": {
module: "Default",
description: "Converts unicode character codes back into text.<br><br>e.g. <code>0393 03b5 03b9 03ac 20 03c3 03bf 03c5</code> becomes <code>Γειά σου</code>",
highlight: ByteRepr.highlightFrom,
highlightReverse: ByteRepr.highlightTo,
highlight: "func",
highlightReverse: "func",
inputType: "string",
outputType: "byteArray",
args: [
@ -527,8 +527,8 @@ const OperationConfig = {
"To Charcode": {
module: "Default",
description: "Converts text to its unicode character code equivalent.<br><br>e.g. <code>Γειά σου</code> becomes <code>0393 03b5 03b9 03ac 20 03c3 03bf 03c5</code>",
highlight: ByteRepr.highlightTo,
highlightReverse: ByteRepr.highlightFrom,
highlight: "func",
highlightReverse: "func",
inputType: "string",
outputType: "string",
args: [
@ -547,8 +547,8 @@ const OperationConfig = {
"From Binary": {
module: "Default",
description: "Converts a binary string back into its raw form.<br><br>e.g. <code>01001000 01101001</code> becomes <code>Hi</code>",
highlight: ByteRepr.highlightFromBinary,
highlightReverse: ByteRepr.highlightToBinary,
highlight: "func",
highlightReverse: "func",
inputType: "string",
outputType: "byteArray",
args: [
@ -562,8 +562,8 @@ const OperationConfig = {
"To Binary": {
module: "Default",
description: "Displays the input data as a binary string.<br><br>e.g. <code>Hi</code> becomes <code>01001000 01101001</code>",
highlight: ByteRepr.highlightToBinary,
highlightReverse: ByteRepr.highlightFromBinary,
highlight: "func",
highlightReverse: "func",
inputType: "byteArray",
outputType: "string",
args: [
@ -603,8 +603,8 @@ const OperationConfig = {
"From Hexdump": {
module: "Default",
description: "Attempts to convert a hexdump back into raw data. This operation supports many different hexdump variations, but probably not all. Make sure you verify that the data it gives you is correct before continuing analysis.",
highlight: Hexdump.highlightFrom,
highlightReverse: Hexdump.highlightTo,
highlight: "func",
highlightReverse: "func",
inputType: "string",
outputType: "byteArray",
args: []
@ -612,8 +612,8 @@ const OperationConfig = {
"To Hexdump": {
module: "Default",
description: "Creates a hexdump of the input data, displaying both the hexadecimal values of each byte and an ASCII representation alongside.",
highlight: Hexdump.highlightTo,
highlightReverse: Hexdump.highlightFrom,
highlight: "func",
highlightReverse: "func",
inputType: "byteArray",
outputType: "string",
args: [

View File

@ -158,6 +158,34 @@ OpModules.Default = {
"Conditional Jump": FlowControl.runCondJump,
"Return": FlowControl.runReturn,
"Comment": FlowControl.runComment,
/*
Highlighting functions.
This is a temporary solution as highlighting should be entirely
overhauled at some point.
*/
"From Base64-highlight": Base64.highlightFrom,
"From Base64-highlightReverse": Base64.highlightTo,
"To Base64-highlight": Base64.highlightTo,
"To Base64-highlightReverse": Base64.highlightFrom,
"From Hex-highlight": ByteRepr.highlightFrom,
"From Hex-highlightReverse": ByteRepr.highlightTo,
"To Hex-highlight": ByteRepr.highlightTo,
"To Hex-highlightReverse": ByteRepr.highlightFrom,
"From Charcode-highlight": ByteRepr.highlightFrom,
"From Charcode-highlightReverse": ByteRepr.highlightTo,
"To Charcode-highlight": ByteRepr.highlightTo,
"To Charcode-highlightReverse": ByteRepr.highlightFrom,
"From Binary-highlight": ByteRepr.highlightFromBinary,
"From Binary-highlightReverse": ByteRepr.highlightToBinary,
"To Binary-highlight": ByteRepr.highlightToBinary,
"To Binary-highlightReverse": ByteRepr.highlightFromBinary,
"From Hexdump-highlight": Hexdump.highlightFrom,
"From Hexdump-highlightReverse": Hexdump.highlightTo,
"To Hexdump-highlight": Hexdump.highlightTo,
"To Hexdump-highlightReverse": Hexdump.highlightFrom,
};
export default OpModules;

View File

@ -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) {
if (self) self.setOption("attemptHighlight", false);
//TODO if (self) self.setOption("attemptHighlight", false);
}
return output;
},

View File

@ -10,9 +10,11 @@ import Utils from "../core/Utils.js";
*
* @constructor
* @param {App} app - The main view object for CyberChef.
* @param {Manager} manager - The CyberChef event manager.
*/
const HighlighterWaiter = function(app) {
const HighlighterWaiter = function(app, manager) {
this.app = app;
this.manager = manager;
this.mouseButtonDown = false;
this.mouseTarget = null;
@ -329,41 +331,6 @@ HighlighterWaiter.prototype.removeHighlights = function() {
};
/**
* Generates a list of all the highlight functions assigned to operations in the recipe, if the
* entire recipe supports highlighting.
*
* @returns {Object[]} highlights
* @returns {function} highlights[].f
* @returns {function} highlights[].b
* @returns {Object[]} highlights[].args
*/
HighlighterWaiter.prototype.generateHighlightList = function() {
const recipeConfig = this.app.getRecipeConfig();
const highlights = [];
for (let i = 0; i < recipeConfig.length; i++) {
if (recipeConfig[i].disabled) continue;
// If any breakpoints are set, do not attempt to highlight
if (recipeConfig[i].breakpoint) return false;
const op = this.app.operations[recipeConfig[i].op];
// If any of the operations do not support highlighting, fail immediately.
if (op.highlight === false || op.highlight === undefined) return false;
highlights.push({
f: op.highlight,
b: op.highlightReverse,
args: recipeConfig[i].args
});
}
return highlights;
};
/**
* Highlights the given offsets in the output.
* We will only highlight if:
@ -376,26 +343,8 @@ HighlighterWaiter.prototype.generateHighlightList = function() {
* @param {number} pos.end - The end offset.
*/
HighlighterWaiter.prototype.highlightOutput = function(pos) {
const highlights = this.generateHighlightList();
if (!highlights || !this.app.autoBake_) {
return false;
}
for (let i = 0; i < highlights.length; i++) {
// Remove multiple highlights before processing again
pos = [pos[0]];
if (typeof highlights[i].f == "function") {
pos = highlights[i].f(pos, highlights[i].args);
}
}
document.getElementById("output-selection-info").innerHTML = this.selectionInfo(pos[0].start, pos[0].end);
this.highlight(
document.getElementById("output-text"),
document.getElementById("output-highlighter"),
pos);
if (!this.app.autoBake_ || this.app.baking) return false;
this.manager.worker.highlight(this.app.getRecipeConfig(), "forward", pos);
};
@ -411,25 +360,28 @@ HighlighterWaiter.prototype.highlightOutput = function(pos) {
* @param {number} pos.end - The end offset.
*/
HighlighterWaiter.prototype.highlightInput = function(pos) {
const highlights = this.generateHighlightList();
if (!this.app.autoBake_ || this.app.baking) return false;
this.manager.worker.highlight(this.app.getRecipeConfig(), "reverse", pos);
};
if (!highlights || !this.app.autoBake_) {
return false;
}
for (let i = 0; i < highlights.length; i++) {
// Remove multiple highlights before processing again
pos = [pos[0]];
/**
* Displays highlight offsets sent back from the Chef.
*
* @param {Object} pos - The position object for the highlight.
* @param {number} pos.start - The start offset.
* @param {number} pos.end - The end offset.
* @param {string} direction
*/
HighlighterWaiter.prototype.displayHighlights = function(pos, direction) {
if (!pos) return;
if (typeof highlights[i].b == "function") {
pos = highlights[i].b(pos, highlights[i].args);
}
}
const io = direction === "forward" ? "output" : "input";
document.getElementById("input-selection-info").innerHTML = this.selectionInfo(pos[0].start, pos[0].end);
document.getElementById(io + "-selection-info").innerHTML = this.selectionInfo(pos[0].start, pos[0].end);
this.highlight(
document.getElementById("input-text"),
document.getElementById("input-highlighter"),
document.getElementById(io + "-text"),
document.getElementById(io + "-highlighter"),
pos);
};

View File

@ -58,7 +58,7 @@ const Manager = function(app) {
this.input = new InputWaiter(this.app, this);
this.output = new OutputWaiter(this.app, this);
this.options = new OptionsWaiter(this.app);
this.highlighter = new HighlighterWaiter(this.app);
this.highlighter = new HighlighterWaiter(this.app, this);
this.seasonal = new SeasonalWaiter(this.app, this);
// Object to store dynamic handlers to fire on elements that may not exist yet

View File

@ -57,6 +57,9 @@ WorkerWaiter.prototype.handleChefMessage = function(e) {
case "statusMessage":
this.manager.output.setStatusMsg(e.data.data);
break;
case "highlightsCalculated":
this.manager.highlighter.displayHighlights(e.data.data.pos, e.data.data.direction);
break;
default:
console.error("Unrecognised message from ChefWorker", e);
break;
@ -150,4 +153,25 @@ WorkerWaiter.prototype.silentBake = function(recipeConfig) {
};
/**
* Asks the ChefWorker to calculate highlight offsets if possible.
*
* @param {Object[]} recipeConfig
* @param {string} direction
* @param {Object} pos - The position object for the highlight.
* @param {number} pos.start - The start offset.
* @param {number} pos.end - The end offset.
*/
WorkerWaiter.prototype.highlight = function(recipeConfig, direction, pos) {
this.chefWorker.postMessage({
action: "highlight",
data: {
recipeConfig: recipeConfig,
direction: direction,
pos: pos
}
});
};
export default WorkerWaiter;