CyberChef/src/core/FlowControl.js

253 lines
7.9 KiB
JavaScript
Raw Normal View History

import Recipe from "./Recipe.js";
import Dish from "./Dish.js";
2016-11-28 11:42:58 +01:00
/**
* Flow Control operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2016
* @license Apache-2.0
*
* @namespace
*/
const FlowControl = {
2016-11-28 11:42:58 +01:00
/**
* Fork operation.
*
* @param {Object} state - The current state of the recipe.
* @param {number} state.progress - The current position in the recipe.
* @param {Dish} state.dish - The Dish being operated on.
* @param {Operation[]} state.opList - The list of operations in the recipe.
2016-11-28 11:42:58 +01:00
* @returns {Object} The updated state of the recipe.
*/
runFork: async function(state) {
2017-04-13 19:08:50 +02:00
let opList = state.opList,
inputType = opList[state.progress].inputType,
outputType = opList[state.progress].outputType,
input = state.dish.get(inputType),
ings = opList[state.progress].getIngValues(),
splitDelim = ings[0],
mergeDelim = ings[1],
ignoreErrors = ings[2],
subOpList = [],
2017-04-13 19:31:26 +02:00
inputs = [],
i;
2017-02-09 16:09:33 +01:00
2016-11-28 11:42:58 +01:00
if (input)
inputs = input.split(splitDelim);
2017-02-09 16:09:33 +01:00
// Create subOpList for each tranche to operate on
2016-11-28 11:42:58 +01:00
// (all remaining operations unless we encounter a Merge)
2017-04-13 19:31:26 +02:00
for (i = state.progress + 1; i < opList.length; i++) {
if (opList[i].name === "Merge" && !opList[i].isDisabled()) {
2016-11-28 11:42:58 +01:00
break;
} else {
subOpList.push(opList[i]);
2016-11-28 11:42:58 +01:00
}
}
2017-02-09 16:09:33 +01:00
2017-04-13 19:08:50 +02:00
let recipe = new Recipe(),
2016-11-28 11:42:58 +01:00
output = "",
progress = 0;
2017-02-09 16:09:33 +01:00
recipe.addOperations(subOpList);
2017-02-09 16:09:33 +01:00
2016-11-28 11:42:58 +01:00
// Run recipe over each tranche
for (i = 0; i < inputs.length; i++) {
2017-04-13 19:08:50 +02:00
const dish = new Dish(inputs[i], inputType);
try {
progress = await recipe.execute(dish, 0);
2017-02-09 16:09:33 +01:00
} catch (err) {
if (!ignoreErrors) {
throw err;
}
progress = err.progress + 1;
}
output += dish.get(outputType) + mergeDelim;
2016-11-28 11:42:58 +01:00
}
2017-02-09 16:09:33 +01:00
state.dish.set(output, outputType);
2016-11-28 11:42:58 +01:00
state.progress += progress;
return state;
},
2017-02-09 16:09:33 +01:00
2016-11-28 11:42:58 +01:00
/**
* Merge operation.
*
* @param {Object} state - The current state of the recipe.
* @param {number} state.progress - The current position in the recipe.
* @param {Dish} state.dish - The Dish being operated on.
* @param {Operation[]} state.opList - The list of operations in the recipe.
2016-11-28 11:42:58 +01:00
* @returns {Object} The updated state of the recipe.
*/
runMerge: function(state) {
2016-11-28 11:42:58 +01:00
// No need to actually do anything here. The fork operation will
// merge when it sees this operation.
return state;
},
2017-02-09 16:09:33 +01:00
2017-09-28 18:27:39 +02:00
/**
* Register operation.
*
* @param {Object} state - The current state of the recipe.
* @param {number} state.progress - The current position in the recipe.
* @param {Dish} state.dish - The Dish being operated on.
* @param {Operation[]} state.opList - The list of operations in the recipe.
* @returns {Object} The updated state of the recipe.
*/
runRegister: function(state) {
const ings = state.opList[state.progress].getIngValues(),
extractorStr = ings[0],
i = ings[1],
m = ings[2];
let modifiers = "";
if (i) modifiers += "i";
if (m) modifiers += "m";
const extractor = new RegExp(extractorStr, modifiers),
input = state.dish.get(Dish.STRING),
registers = input.match(extractor);
if (!registers) return state;
if (ENVIRONMENT_IS_WORKER()) {
self.setRegisters(state.progress, registers.slice(1));
}
2017-09-28 18:27:39 +02:00
/**
* Replaces references to registers (e.g. $R0) with the contents of those registers.
*
* @param {string} str
* @returns {string}
*/
function replaceRegister(str) {
// Replace references to registers ($Rn) with contents of registers
str = str.replace(/((?:^|[^\\])(?:\\.|[^\\])*?)\$R(\d{1,2})/g, (match, pre, regNum) => {
const index = parseInt(regNum, 10) + 1;
return (index >= registers.length) ? match : pre + registers[index];
});
// Unescape remaining register references
return str.replace(/\\\$R(\d{1,2})/, "$R$1");
}
// Step through all subsequent ops and replace registers in args with extracted content
for (let i = state.progress + 1; i < state.opList.length; i++) {
let args = state.opList[i].getIngValues();
args = args.map(arg => {
if (typeof arg !== "string" && typeof arg !== "object") return arg;
if (typeof arg === "object" && arg.string) {
arg.string = replaceRegister(arg.string);
return arg;
}
return replaceRegister(arg);
});
state.opList[i].setIngValues(args);
}
return state;
},
2016-11-28 11:42:58 +01:00
/**
* Jump operation.
*
* @param {Object} state - The current state of the recipe.
* @param {number} state.progress - The current position in the recipe.
* @param {Dish} state.dish - The Dish being operated on.
* @param {Operation[]} state.opList - The list of operations in the recipe.
* @param {number} state.numJumps - The number of jumps taken so far.
2016-11-28 11:42:58 +01:00
* @returns {Object} The updated state of the recipe.
*/
runJump: function(state) {
2017-04-13 19:08:50 +02:00
let ings = state.opList[state.progress].getIngValues(),
jumpNum = ings[0],
maxJumps = ings[1];
2017-02-09 16:09:33 +01:00
if (jumpNum < 0) {
jumpNum--;
}
if (state.numJumps >= maxJumps) {
return state;
2016-11-28 11:42:58 +01:00
}
2017-02-09 16:09:33 +01:00
state.progress += jumpNum;
state.numJumps++;
2016-11-28 11:42:58 +01:00
return state;
},
2017-02-09 16:09:33 +01:00
2016-11-28 11:42:58 +01:00
/**
* Conditional Jump operation.
*
* @param {Object} state - The current state of the recipe.
* @param {number} state.progress - The current position in the recipe.
* @param {Dish} state.dish - The Dish being operated on.
* @param {Operation[]} state.opList - The list of operations in the recipe.
* @param {number} state.numJumps - The number of jumps taken so far.
2016-11-28 11:42:58 +01:00
* @returns {Object} The updated state of the recipe.
*/
runCondJump: function(state) {
2017-04-13 19:08:50 +02:00
let ings = state.opList[state.progress].getIngValues(),
dish = state.dish,
regexStr = ings[0],
jumpNum = ings[1],
maxJumps = ings[2];
2017-02-09 16:09:33 +01:00
if (jumpNum < 0) {
jumpNum--;
}
if (state.numJumps >= maxJumps) {
return state;
2016-11-28 11:42:58 +01:00
}
2017-02-09 16:09:33 +01:00
if (regexStr !== "" && dish.get(Dish.STRING).search(regexStr) > -1) {
state.progress += jumpNum;
state.numJumps++;
2016-11-28 11:42:58 +01:00
}
2017-02-09 16:09:33 +01:00
2016-11-28 11:42:58 +01:00
return state;
},
2017-02-09 16:09:33 +01:00
2016-11-28 11:42:58 +01:00
/**
* Return operation.
*
* @param {Object} state - The current state of the recipe.
* @param {number} state.progress - The current position in the recipe.
* @param {Dish} state.dish - The Dish being operated on.
* @param {Operation[]} state.opList - The list of operations in the recipe.
2016-11-28 11:42:58 +01:00
* @returns {Object} The updated state of the recipe.
*/
runReturn: function(state) {
state.progress = state.opList.length;
2016-11-28 11:42:58 +01:00
return state;
},
2017-02-09 16:09:33 +01:00
/**
* Comment operation.
2017-04-27 15:12:45 +02:00
*
* @param {Object} state - The current state of the recipe.
* @param {number} state.progress - The current position in the recipe.
* @param {Dish} state.dish - The Dish being operated on.
* @param {Operation[]} state.opList - The list of operations in the recipe.
* @returns {Object} The updated state of the recipe.
*/
runComment: function(state) {
return state;
},
2016-11-28 11:42:58 +01:00
};
export default FlowControl;