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; 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; export default Chef;

View File

@ -53,6 +53,13 @@ self.addEventListener("message", function(e) {
// imported into an inline worker. // imported into an inline worker.
self.docURL = e.data.data; self.docURL = e.data.data;
break; break;
case "highlight":
calculateHighlights(
e.data.data.recipeConfig,
e.data.data.direction,
e.data.data.pos
);
break;
default: default:
break; 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. * Send status update to the app.
* *

View File

@ -54,6 +54,14 @@ Operation.prototype._parseConfig = function(operationConfig) {
const ingredient = new Ingredient(ingredientConfig); const ingredient = new Ingredient(ingredientConfig);
this.addIngredient(ingredient); 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); 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; export default Recipe;

View File

@ -184,8 +184,8 @@ const OperationConfig = {
"From Base64": { "From Base64": {
module: "Default", 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>", 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, highlight: "func",
highlightReverse: Base64.highlightTo, highlightReverse: "func",
inputType: "string", inputType: "string",
outputType: "byteArray", outputType: "byteArray",
args: [ args: [
@ -195,7 +195,7 @@ const OperationConfig = {
value: Base64.ALPHABET_OPTIONS value: Base64.ALPHABET_OPTIONS
}, },
{ {
name: "Remove non&#8209;alphabet chars", name: "Remove non-alphabet chars",
type: "boolean", type: "boolean",
value: Base64.REMOVE_NON_ALPH_CHARS value: Base64.REMOVE_NON_ALPH_CHARS
} }
@ -204,8 +204,8 @@ const OperationConfig = {
"To Base64": { "To Base64": {
module: "Default", 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>", 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, highlight: "func",
highlightReverse: Base64.highlightFrom, highlightReverse: "func",
inputType: "byteArray", inputType: "byteArray",
outputType: "string", outputType: "string",
args: [ args: [
@ -228,7 +228,7 @@ const OperationConfig = {
value: Base58.ALPHABET_OPTIONS value: Base58.ALPHABET_OPTIONS
}, },
{ {
name: "Remove non&#8209;alphabet chars", name: "Remove non-alphabet chars",
type: "boolean", type: "boolean",
value: Base58.REMOVE_NON_ALPH_CHARS value: Base58.REMOVE_NON_ALPH_CHARS
} }
@ -259,7 +259,7 @@ const OperationConfig = {
value: Base64.BASE32_ALPHABET value: Base64.BASE32_ALPHABET
}, },
{ {
name: "Remove non&#8209;alphabet chars", name: "Remove non-alphabet chars",
type: "boolean", type: "boolean",
value: Base64.REMOVE_NON_ALPH_CHARS value: Base64.REMOVE_NON_ALPH_CHARS
} }
@ -446,8 +446,8 @@ const OperationConfig = {
"From Hex": { "From Hex": {
module: "Default", 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>", 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, highlight: "func",
highlightReverse: ByteRepr.highlightTo, highlightReverse: "func",
inputType: "string", inputType: "string",
outputType: "byteArray", outputType: "byteArray",
args: [ args: [
@ -461,8 +461,8 @@ const OperationConfig = {
"To Hex": { "To Hex": {
module: "Default", 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>", 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, highlight: "func",
highlightReverse: ByteRepr.highlightFrom, highlightReverse: "func",
inputType: "byteArray", inputType: "byteArray",
outputType: "string", outputType: "string",
args: [ args: [
@ -506,8 +506,8 @@ const OperationConfig = {
"From Charcode": { "From Charcode": {
module: "Default", 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>", 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, highlight: "func",
highlightReverse: ByteRepr.highlightTo, highlightReverse: "func",
inputType: "string", inputType: "string",
outputType: "byteArray", outputType: "byteArray",
args: [ args: [
@ -527,8 +527,8 @@ const OperationConfig = {
"To Charcode": { "To Charcode": {
module: "Default", 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>", 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, highlight: "func",
highlightReverse: ByteRepr.highlightFrom, highlightReverse: "func",
inputType: "string", inputType: "string",
outputType: "string", outputType: "string",
args: [ args: [
@ -547,8 +547,8 @@ const OperationConfig = {
"From Binary": { "From Binary": {
module: "Default", module: "Default",
description: "Converts a binary string back into its raw form.<br><br>e.g. <code>01001000 01101001</code> becomes <code>Hi</code>", 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, highlight: "func",
highlightReverse: ByteRepr.highlightToBinary, highlightReverse: "func",
inputType: "string", inputType: "string",
outputType: "byteArray", outputType: "byteArray",
args: [ args: [
@ -562,8 +562,8 @@ const OperationConfig = {
"To Binary": { "To Binary": {
module: "Default", module: "Default",
description: "Displays the input data as a binary string.<br><br>e.g. <code>Hi</code> becomes <code>01001000 01101001</code>", description: "Displays the input data as a binary string.<br><br>e.g. <code>Hi</code> becomes <code>01001000 01101001</code>",
highlight: ByteRepr.highlightToBinary, highlight: "func",
highlightReverse: ByteRepr.highlightFromBinary, highlightReverse: "func",
inputType: "byteArray", inputType: "byteArray",
outputType: "string", outputType: "string",
args: [ args: [
@ -603,8 +603,8 @@ const OperationConfig = {
"From Hexdump": { "From Hexdump": {
module: "Default", 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.", 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, highlight: "func",
highlightReverse: Hexdump.highlightTo, highlightReverse: "func",
inputType: "string", inputType: "string",
outputType: "byteArray", outputType: "byteArray",
args: [] args: []
@ -612,8 +612,8 @@ const OperationConfig = {
"To Hexdump": { "To Hexdump": {
module: "Default", module: "Default",
description: "Creates a hexdump of the input data, displaying both the hexadecimal values of each byte and an ASCII representation alongside.", description: "Creates a hexdump of the input data, displaying both the hexadecimal values of each byte and an ASCII representation alongside.",
highlight: Hexdump.highlightTo, highlight: "func",
highlightReverse: Hexdump.highlightFrom, highlightReverse: "func",
inputType: "byteArray", inputType: "byteArray",
outputType: "string", outputType: "string",
args: [ args: [

View File

@ -158,6 +158,34 @@ OpModules.Default = {
"Conditional Jump": FlowControl.runCondJump, "Conditional Jump": FlowControl.runCondJump,
"Return": FlowControl.runReturn, "Return": FlowControl.runReturn,
"Comment": FlowControl.runComment, "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; export default OpModules;

View File

@ -92,7 +92,7 @@ const Hexdump = {
const w = (width - 13) / 4; const w = (width - 13) / 4;
// w should be the specified width of the hexdump and therefore a round number // 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 (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; return output;
}, },

View File

@ -10,9 +10,11 @@ import Utils from "../core/Utils.js";
* *
* @constructor * @constructor
* @param {App} app - The main view object for CyberChef. * @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.app = app;
this.manager = manager;
this.mouseButtonDown = false; this.mouseButtonDown = false;
this.mouseTarget = null; 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. * Highlights the given offsets in the output.
* We will only highlight if: * We will only highlight if:
@ -376,26 +343,8 @@ HighlighterWaiter.prototype.generateHighlightList = function() {
* @param {number} pos.end - The end offset. * @param {number} pos.end - The end offset.
*/ */
HighlighterWaiter.prototype.highlightOutput = function(pos) { HighlighterWaiter.prototype.highlightOutput = function(pos) {
const highlights = this.generateHighlightList(); if (!this.app.autoBake_ || this.app.baking) return false;
this.manager.worker.highlight(this.app.getRecipeConfig(), "forward", 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]];
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);
}; };
@ -411,25 +360,28 @@ HighlighterWaiter.prototype.highlightOutput = function(pos) {
* @param {number} pos.end - The end offset. * @param {number} pos.end - The end offset.
*/ */
HighlighterWaiter.prototype.highlightInput = function(pos) { 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 * Displays highlight offsets sent back from the Chef.
pos = [pos[0]]; *
* @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") { const io = direction === "forward" ? "output" : "input";
pos = highlights[i].b(pos, highlights[i].args);
}
}
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( this.highlight(
document.getElementById("input-text"), document.getElementById(io + "-text"),
document.getElementById("input-highlighter"), document.getElementById(io + "-highlighter"),
pos); pos);
}; };

View File

@ -58,7 +58,7 @@ const Manager = function(app) {
this.input = new InputWaiter(this.app, this); this.input = new InputWaiter(this.app, this);
this.output = new OutputWaiter(this.app, this); this.output = new OutputWaiter(this.app, this);
this.options = new OptionsWaiter(this.app); 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); this.seasonal = new SeasonalWaiter(this.app, this);
// Object to store dynamic handlers to fire on elements that may not exist yet // 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": case "statusMessage":
this.manager.output.setStatusMsg(e.data.data); this.manager.output.setStatusMsg(e.data.data);
break; break;
case "highlightsCalculated":
this.manager.highlighter.displayHighlights(e.data.data.pos, e.data.data.direction);
break;
default: default:
console.error("Unrecognised message from ChefWorker", e); console.error("Unrecognised message from ChefWorker", e);
break; 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; export default WorkerWaiter;