chef.bake can parse chef format recipe

This commit is contained in:
d98762625 2020-05-28 16:06:08 +01:00
parent 616b38c6fb
commit a289eda7fc
2 changed files with 108 additions and 12 deletions

View file

@ -6,6 +6,8 @@
import {operations} from "./index.mjs"; import {operations} from "./index.mjs";
import { sanitise } from "./apiUtils.mjs"; import { sanitise } from "./apiUtils.mjs";
import Utils from "../core/Utils";
/** /**
* Similar to core/Recipe, Recipe controls a list of operations and * Similar to core/Recipe, Recipe controls a list of operations and
@ -34,9 +36,10 @@ class NodeRecipe {
}); });
if (op) { if (op) {
return op; return op;
} else {
throw new TypeError(`Couldn't find an operation with name '${ing}'.`);
} }
throw new TypeError(`Couldn't find an operation with name '${ing}'.`);
} else if (typeof ing === "function") { } else if (typeof ing === "function") {
if (operations.includes(ing)) { if (operations.includes(ing)) {
return ing; return ing;
@ -47,7 +50,15 @@ class NodeRecipe {
} else if (ing.op) { } else if (ing.op) {
const sanitisedOp = this._validateIngredient(ing.op); const sanitisedOp = this._validateIngredient(ing.op);
if (ing.args) { if (ing.args) {
return {op: sanitisedOp, args: ing.args};
// disabled, breakpoint options sometimes come from parsed
// recipes pasted from UI
return {
op: sanitisedOp,
args: ing.args,
disabled: ing.disabled,
breakpoint: ing.breakpoint
};
} }
return sanitisedOp; return sanitisedOp;
} else { } else {
@ -55,7 +66,6 @@ class NodeRecipe {
} }
} }
/** /**
* Parse config for recipe. * Parse config for recipe.
* @param {String | Function | String[] | Function[] | [String | Function]} recipeConfig * @param {String | Function | String[] | Function[] | [String | Function]} recipeConfig
@ -66,6 +76,14 @@ class NodeRecipe {
return; return;
} }
// Case for when recipeConfig is a chef format recipe string
if (typeof recipeConfig == "string" || recipeConfig instanceof String) {
const attemptedParseResult = Utils.parseRecipeConfig(recipeConfig);
if (attemptedParseResult.length > 0) {
recipeConfig = attemptedParseResult;
}
}
if (!Array.isArray(recipeConfig)) { if (!Array.isArray(recipeConfig)) {
recipeConfig = [recipeConfig]; recipeConfig = [recipeConfig];
} }
@ -79,15 +97,27 @@ class NodeRecipe {
* @returns {NodeDish} * @returns {NodeDish}
*/ */
execute(dish) { execute(dish) {
return this.opList.reduce((prev, curr) => { for (const op of this.opList) {
// CASE where opList item is op and args if (
if (Object.prototype.hasOwnProperty.call(curr, "op") && Object.prototype.hasOwnProperty.call(op, "op") &&
Object.prototype.hasOwnProperty.call(curr, "args")) { Object.prototype.hasOwnProperty.call(op, "args")
return curr.op(prev, curr.args); ) {
if (op.breakpoint) {
break;
}
if (op.disabled) {
continue;
}
dish = op.op(dish, op.args);
} else {
dish = op(dish);
} }
// CASE opList item is just op. }
return curr(prev);
}, dish); return dish;
} }
} }

View file

@ -357,6 +357,58 @@ TestRegister.addApiTests([
assert.strictEqual(result.toString(), "begin_something_aaaaaaaaaaaaaa_end_something"); assert.strictEqual(result.toString(), "begin_something_aaaaaaaaaaaaaa_end_something");
}), }),
it("chef.bake: should accept single operation Chef format recipe as second argument", () => {
const result = chef.bake("throw throw burrito", "To_Hex_Content('All chars',false)");
assert.strictEqual(result.toString(), "|7468726f77207468726f77206275727269746f|");
}),
it("chef.bake: should accept single operation Chef format recipe as second argument with non-default arguments", () => {
const result = chef.bake("Throw Throw Burrito", "ROT13(true,false,14)");
assert.strictEqual(result.toString(), "Tvfck Tvfck Biffwhc");
}),
it("chef.bake: should accept multiple operation Chef format recipe as second argument", () => {
const result = chef.bake("throw throw burrito", "To_Hex('Space',2)Hex_to_Object_Identifier()Extract_IP_addresses(true,false,false,true)");
assert.strictEqual(result.toString(), `Total found: 5
2.36.104.114
111.119.32.116
104.114.111.119
32.98.117.114
114.105.116.111
`);
}),
it("chef.bake: should accept multiple operation Chef format recipe as pasted from UI as second argument", () => {
const result = chef.bake("throw throw burrito", `To_Hex('Space',2)
Hex_to_Object_Identifier()
Extract_IP_addresses(true,false,false,true)
`);
assert.strictEqual(result.toString(), `Total found: 5
2.36.104.114
111.119.32.116
104.114.111.119
32.98.117.114
114.105.116.111
`);
}),
it("chef.bake: should accept multiple operation Chef format recipe with a disabled operation", async () => {
const result = await chef.bake("throw throw burrito", `ROT13(true,true,13)
Atbash_Cipher(/disabled)
MD5()
`);
assert.strictEqual(result.toString(), "f859e9e196c4452d2d25f12dffc67355");
}),
it("chef.bake: should accept multiple operation Chef format recipe with a breakpoint operation", async () => {
const result = await chef.bake("throw throw burrito", `ROT13(true,true,13)
Atbash_Cipher()
MD5(/breakpoint)`);
assert.strictEqual(result.toString(), "tfvyq tfvyq lsvvety");
}),
it("Excluded operations: throw a sensible error when you try and call one", () => { it("Excluded operations: throw a sensible error when you try and call one", () => {
try { try {
chef.fork(); chef.fork();
@ -375,6 +427,20 @@ TestRegister.addApiTests([
} }
}), }),
it("Excluded operations: throw a sensible error when you try and call one as part of a recipe", () => {
try {
chef.bake(`978346800
1012651200
1046696400
1081087200
1115305200
1149609600`, "Fork('\\n','\\n',false)From_UNIX_Timestamp('Seconds (s)')");
} catch (e) {
assert.strictEqual(e.type, "ExcludedOperationError");
assert.strictEqual(e.message, "Sorry, the Fork operation is not available in the Node.js version of CyberChef.");
}
}),
it("Operation arguments: should be accessible from operation object if op has array arg", () => { it("Operation arguments: should be accessible from operation object if op has array arg", () => {
assert.ok(chef.toCharcode.args); assert.ok(chef.toCharcode.args);
assert.deepEqual(chef.unzip.args, { assert.deepEqual(chef.unzip.args, {