fix(node): enable asynchronous operation support in Node.js API (#2342)
Authored-by: engin0223 <engineda2014@hotmail.com> Changes cherry-picked by GCHQDeveloper581 <63102987+GCHQDeveloper581@users.noreply.github.com> Breaking change: Alters Node API - "bake" and "execute" are now declared async.
This commit is contained in:
parent
9e5f94f5dc
commit
e0ba5d2812
@ -88,16 +88,17 @@ class NodeRecipe {
|
|||||||
* @param {NodeDish} dish
|
* @param {NodeDish} dish
|
||||||
* @returns {NodeDish}
|
* @returns {NodeDish}
|
||||||
*/
|
*/
|
||||||
execute(dish) {
|
async execute(dish) {
|
||||||
return this.opList.reduce((prev, curr) => {
|
let prev = dish;
|
||||||
// CASE where opList item is op and args
|
for (const curr of this.opList) {
|
||||||
if (Object.prototype.hasOwnProperty.call(curr, "op") &&
|
if (Object.prototype.hasOwnProperty.call(curr, "op") &&
|
||||||
Object.prototype.hasOwnProperty.call(curr, "args")) {
|
Object.prototype.hasOwnProperty.call(curr, "args")) {
|
||||||
return curr.op(prev, curr.args);
|
prev = await curr.op(prev, curr.args);
|
||||||
|
} else {
|
||||||
|
prev = await curr(prev);
|
||||||
}
|
}
|
||||||
// CASE opList item is just op.
|
}
|
||||||
return curr(prev);
|
return prev;
|
||||||
}, dish);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -324,10 +324,10 @@ export function help(input) {
|
|||||||
* @returns {NodeDish} of the result
|
* @returns {NodeDish} of the result
|
||||||
* @throws {TypeError} if invalid recipe given.
|
* @throws {TypeError} if invalid recipe given.
|
||||||
*/
|
*/
|
||||||
export function bake(input, recipeConfig) {
|
export async function bake(input, recipeConfig) {
|
||||||
const recipe = new NodeRecipe(recipeConfig);
|
const recipe = new NodeRecipe(recipeConfig);
|
||||||
const dish = ensureIsDish(input);
|
const dish = ensureIsDish(input);
|
||||||
return recipe.execute(dish);
|
return await recipe.execute(dish);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -8,9 +8,9 @@
|
|||||||
|
|
||||||
const assert = require("assert");
|
const assert = require("assert");
|
||||||
|
|
||||||
require("cyberchef").then(chef => {
|
require("cyberchef").then(async chef => {
|
||||||
|
|
||||||
const d = chef.bake("Testing, 1 2 3", [
|
const d = await chef.bake("Testing, 1 2 3", [
|
||||||
chef.toHex,
|
chef.toHex,
|
||||||
chef.reverse,
|
chef.reverse,
|
||||||
{
|
{
|
||||||
|
|||||||
@ -9,7 +9,7 @@ import assert from "assert";
|
|||||||
import chef from "cyberchef";
|
import chef from "cyberchef";
|
||||||
import { bake, toHex, reverse, unique, multiply } from "cyberchef";
|
import { bake, toHex, reverse, unique, multiply } from "cyberchef";
|
||||||
|
|
||||||
const a = bake("Testing, 1 2 3", [
|
const a = await bake("Testing, 1 2 3", [
|
||||||
toHex,
|
toHex,
|
||||||
reverse,
|
reverse,
|
||||||
{
|
{
|
||||||
@ -28,7 +28,7 @@ const a = bake("Testing, 1 2 3", [
|
|||||||
|
|
||||||
assert.equal(a.value, "630957449041920");
|
assert.equal(a.value, "630957449041920");
|
||||||
|
|
||||||
const b = chef.bake("Testing, 1 2 3", [
|
const b = await chef.bake("Testing, 1 2 3", [
|
||||||
chef.toHex,
|
chef.toHex,
|
||||||
chef.reverse,
|
chef.reverse,
|
||||||
{
|
{
|
||||||
|
|||||||
@ -170,77 +170,77 @@ TestRegister.addApiTests([
|
|||||||
assert(chef.bake);
|
assert(chef.bake);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("chef.bake: should return NodeDish", () => {
|
it("chef.bake: should return NodeDish", async () => {
|
||||||
const result = chef.bake("input", "to base 64");
|
const result = await chef.bake("input", "to base 64");
|
||||||
assert(result instanceof NodeDish);
|
assert(result instanceof NodeDish);
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("chef.bake: should take an input and an op name and perform it", () => {
|
it("chef.bake: should take an input and an op name and perform it", async () => {
|
||||||
const result = chef.bake("some input", "to base 32");
|
const result = await chef.bake("some input", "to base 32");
|
||||||
assert.strictEqual(result.toString(), "ONXW2ZJANFXHA5LU");
|
assert.strictEqual(result.toString(), "ONXW2ZJANFXHA5LU");
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("chef.bake: should complain if recipe isnt a valid object", () => {
|
it("chef.bake: should complain if recipe isnt a valid object", async () => {
|
||||||
assert.throws(() => chef.bake("some input", 3264), {
|
await assert.rejects(() => chef.bake("some input", 3264), {
|
||||||
name: "TypeError",
|
name: "TypeError",
|
||||||
message: "Recipe can only contain function names or functions"
|
message: "Recipe can only contain function names or functions"
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("chef.bake: Should complain if string op is invalid", () => {
|
it("chef.bake: Should complain if string op is invalid", async () => {
|
||||||
assert.throws(() => chef.bake("some input", "not a valid operation"), {
|
await assert.rejects(() => chef.bake("some input", "not a valid operation"), {
|
||||||
name: "TypeError",
|
name: "TypeError",
|
||||||
message: "Couldn't find an operation with name 'not a valid operation'."
|
message: "Couldn't find an operation with name 'not a valid operation'."
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("chef.bake: Should take an input and an operation and perform it", () => {
|
it("chef.bake: Should take an input and an operation and perform it", async () => {
|
||||||
const result = chef.bake("https://google.com/search?q=help", chef.parseURI);
|
const result = await chef.bake("https://google.com/search?q=help", chef.parseURI);
|
||||||
assert.strictEqual(result.toString(), "Protocol:\thttps:\nHostname:\tgoogle.com\nPath name:\t/search\nArguments:\n\tq = help\n");
|
assert.strictEqual(result.toString(), "Protocol:\thttps:\nHostname:\tgoogle.com\nPath name:\t/search\nArguments:\n\tq = help\n");
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("chef.bake: Should complain if an invalid operation is inputted", () => {
|
it("chef.bake: Should complain if an invalid operation is inputted", async () => {
|
||||||
assert.throws(() => chef.bake("https://google.com/search?q=help", () => {}), {
|
await assert.rejects(() => chef.bake("https://google.com/search?q=help", () => {}), {
|
||||||
name: "TypeError",
|
name: "TypeError",
|
||||||
message: "Inputted function not a Chef operation."
|
message: "Inputted function not a Chef operation."
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("chef.bake: accepts an array of operation names and performs them all in order", () => {
|
it("chef.bake: accepts an array of operation names and performs them all in order", async () => {
|
||||||
const result = chef.bake("https://google.com/search?q=that's a complicated question", ["URL encode", "URL decode", "Parse URI"]);
|
const result = await chef.bake("https://google.com/search?q=that's a complicated question", ["URL encode", "URL decode", "Parse URI"]);
|
||||||
assert.strictEqual(result.toString(), "Protocol:\thttps:\nHostname:\tgoogle.com\nPath name:\t/search\nArguments:\n\tq = that's a complicated question\n");
|
assert.strictEqual(result.toString(), "Protocol:\thttps:\nHostname:\tgoogle.com\nPath name:\t/search\nArguments:\n\tq = that's a complicated question\n");
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("chef.bake: forgiving with operation names", () =>{
|
it("chef.bake: forgiving with operation names", async () =>{
|
||||||
const result = chef.bake("https://google.com/search?q=that's a complicated question", ["urlencode", "url decode", "parseURI"]);
|
const result = await chef.bake("https://google.com/search?q=that's a complicated question", ["urlencode", "url decode", "parseURI"]);
|
||||||
assert.strictEqual(result.toString(), "Protocol:\thttps:\nHostname:\tgoogle.com\nPath name:\t/search\nArguments:\n\tq = that's a complicated question\n");
|
assert.strictEqual(result.toString(), "Protocol:\thttps:\nHostname:\tgoogle.com\nPath name:\t/search\nArguments:\n\tq = that's a complicated question\n");
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("chef.bake: forgiving with operation names", () =>{
|
it("chef.bake: forgiving with operation names", async () =>{
|
||||||
const result = chef.bake("hello", ["to base 64"]);
|
const result = await chef.bake("hello", ["to base 64"]);
|
||||||
assert.strictEqual(result.toString(), "aGVsbG8=");
|
assert.strictEqual(result.toString(), "aGVsbG8=");
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("chef.bake: if recipe is empty array, return input as dish", () => {
|
it("chef.bake: if recipe is empty array, return input as dish", async () => {
|
||||||
const result = chef.bake("some input", []);
|
const result = await chef.bake("some input", []);
|
||||||
assert.strictEqual(result.toString(), "some input");
|
assert.strictEqual(result.toString(), "some input");
|
||||||
assert(result instanceof NodeDish, "Result is not instance of NodeDish");
|
assert(result instanceof NodeDish, "Result is not instance of NodeDish");
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("chef.bake: accepts an array of operations as recipe", () => {
|
it("chef.bake: accepts an array of operations as recipe", async () => {
|
||||||
const result = chef.bake("https://google.com/search?q=that's a complicated question", [chef.URLEncode, chef.URLDecode, chef.parseURI]);
|
const result = await chef.bake("https://google.com/search?q=that's a complicated question", [chef.URLEncode, chef.URLDecode, chef.parseURI]);
|
||||||
assert.strictEqual(result.toString(), "Protocol:\thttps:\nHostname:\tgoogle.com\nPath name:\t/search\nArguments:\n\tq = that's a complicated question\n");
|
assert.strictEqual(result.toString(), "Protocol:\thttps:\nHostname:\tgoogle.com\nPath name:\t/search\nArguments:\n\tq = that's a complicated question\n");
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("should complain if an invalid operation is inputted as part of array", () => {
|
it("should complain if an invalid operation is inputted as part of array", async () => {
|
||||||
assert.throws(() => chef.bake("something", [() => {}]), {
|
await assert.rejects(() => chef.bake("something", [() => {}]), {
|
||||||
name: "TypeError",
|
name: "TypeError",
|
||||||
message: "Inputted function not a Chef operation."
|
message: "Inputted function not a Chef operation."
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("chef.bake: should take single JSON object describing op and args OBJ", () => {
|
it("chef.bake: should take single JSON object describing op and args OBJ", async () => {
|
||||||
const result = chef.bake("some input", {
|
const result = await chef.bake("some input", {
|
||||||
op: chef.toHex,
|
op: chef.toHex,
|
||||||
args: {
|
args: {
|
||||||
Delimiter: "Colon"
|
Delimiter: "Colon"
|
||||||
@ -249,23 +249,23 @@ TestRegister.addApiTests([
|
|||||||
assert.strictEqual(result.toString(), "73:6f:6d:65:20:69:6e:70:75:74");
|
assert.strictEqual(result.toString(), "73:6f:6d:65:20:69:6e:70:75:74");
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("chef.bake: should take single JSON object desribing op with optional args", () => {
|
it("chef.bake: should take single JSON object desribing op with optional args", async () => {
|
||||||
const result = chef.bake("some input", {
|
const result = await chef.bake("some input", {
|
||||||
op: chef.toHex,
|
op: chef.toHex,
|
||||||
});
|
});
|
||||||
assert.strictEqual(result.toString(), "73 6f 6d 65 20 69 6e 70 75 74");
|
assert.strictEqual(result.toString(), "73 6f 6d 65 20 69 6e 70 75 74");
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("chef.bake: should take single JSON object describing op and args ARRAY", () => {
|
it("chef.bake: should take single JSON object describing op and args ARRAY", async () => {
|
||||||
const result = chef.bake("some input", {
|
const result = await chef.bake("some input", {
|
||||||
op: chef.toHex,
|
op: chef.toHex,
|
||||||
args: ["Colon"]
|
args: ["Colon"]
|
||||||
});
|
});
|
||||||
assert.strictEqual(result.toString(), "73:6f:6d:65:20:69:6e:70:75:74");
|
assert.strictEqual(result.toString(), "73:6f:6d:65:20:69:6e:70:75:74");
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("chef.bake: should error if op in JSON is not chef op", () => {
|
it("chef.bake: should error if op in JSON is not chef op", async () => {
|
||||||
assert.throws(() => chef.bake("some input", {
|
await assert.rejects(() => chef.bake("some input", {
|
||||||
op: () => {},
|
op: () => {},
|
||||||
args: ["Colon"],
|
args: ["Colon"],
|
||||||
}), {
|
}), {
|
||||||
@ -274,8 +274,8 @@ TestRegister.addApiTests([
|
|||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("chef.bake: should take multiple ops in JSON object form, some ops by string", () => {
|
it("chef.bake: should take multiple ops in JSON object form, some ops by string", async () => {
|
||||||
const result = chef.bake("some input", [
|
const result = await chef.bake("some input", [
|
||||||
{
|
{
|
||||||
op: chef.toHex,
|
op: chef.toHex,
|
||||||
args: ["Colon"]
|
args: ["Colon"]
|
||||||
@ -290,8 +290,8 @@ TestRegister.addApiTests([
|
|||||||
assert.strictEqual(result.toString(), "67;63;72;66;146;72;66;144;72;66;65;72;62;60;72;66;71;72;66;145;72;67;60;72;67;65;72;67;64");
|
assert.strictEqual(result.toString(), "67;63;72;66;146;72;66;144;72;66;65;72;62;60;72;66;71;72;66;145;72;67;60;72;67;65;72;67;64");
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("chef.bake: should take multiple ops in JSON object form, some without args", () => {
|
it("chef.bake: should take multiple ops in JSON object form, some without args", async () => {
|
||||||
const result = chef.bake("some input", [
|
const result = await chef.bake("some input", [
|
||||||
{
|
{
|
||||||
op: chef.toHex,
|
op: chef.toHex,
|
||||||
},
|
},
|
||||||
@ -305,8 +305,8 @@ TestRegister.addApiTests([
|
|||||||
assert.strictEqual(result.toString(), "67;63;40;66;146;40;66;144;40;66;65;40;62;60;40;66;71;40;66;145;40;67;60;40;67;65;40;67;64");
|
assert.strictEqual(result.toString(), "67;63;40;66;146;40;66;144;40;66;65;40;62;60;40;66;71;40;66;145;40;67;60;40;67;65;40;67;64");
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("chef.bake: should handle op with multiple args", () => {
|
it("chef.bake: should handle op with multiple args", async () => {
|
||||||
const result = chef.bake("some input", {
|
const result = await chef.bake("some input", {
|
||||||
op: "to morse code",
|
op: "to morse code",
|
||||||
args: {
|
args: {
|
||||||
formatOptions: "Dash/Dot",
|
formatOptions: "Dash/Dot",
|
||||||
@ -317,13 +317,13 @@ TestRegister.addApiTests([
|
|||||||
assert.strictEqual(result.toString(), "DotDotDot\\DashDashDash\\DashDash\\Dot,DotDot\\DashDot\\DotDashDashDot\\DotDotDash\\Dash");
|
assert.strictEqual(result.toString(), "DotDotDot\\DashDashDash\\DashDash\\Dot,DotDot\\DashDot\\DotDashDashDot\\DotDotDash\\Dash");
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("chef.bake: should take compact JSON format from Chef Website as recipe", () => {
|
it("chef.bake: should take compact JSON format from Chef Website as recipe", async () => {
|
||||||
const result = chef.bake("some input", [{"op": "To Morse Code", "args": ["Dash/Dot", "Backslash", "Comma"]}, {"op": "Hex to PEM", "args": ["SOMETHING"]}, {"op": "To Snake case", "args": [false]}]);
|
const result = await chef.bake("some input", [{"op": "To Morse Code", "args": ["Dash/Dot", "Backslash", "Comma"]}, {"op": "Hex to PEM", "args": ["SOMETHING"]}, {"op": "To Snake case", "args": [false]}]);
|
||||||
assert.strictEqual(result.toString(), "begin_something_anananaaaaak_da_aaak_da_aaaaananaaaaaaan_da_aaaaaaanan_da_aaak_end_something");
|
assert.strictEqual(result.toString(), "begin_something_anananaaaaak_da_aaak_da_aaaaananaaaaaaan_da_aaaaaaanan_da_aaak_end_something");
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("chef.bake: should accept Clean JSON format from Chef website as recipe", () => {
|
it("chef.bake: should accept Clean JSON format from Chef website as recipe", async () => {
|
||||||
const result = chef.bake("some input", [
|
const result = await chef.bake("some input", [
|
||||||
{ "op": "To Morse Code",
|
{ "op": "To Morse Code",
|
||||||
"args": ["Dash/Dot", "Backslash", "Comma"] },
|
"args": ["Dash/Dot", "Backslash", "Comma"] },
|
||||||
{ "op": "Hex to PEM",
|
{ "op": "Hex to PEM",
|
||||||
@ -334,8 +334,8 @@ TestRegister.addApiTests([
|
|||||||
assert.strictEqual(result.toString(), "begin_something_anananaaaaak_da_aaak_da_aaaaananaaaaaaan_da_aaaaaaanan_da_aaak_end_something");
|
assert.strictEqual(result.toString(), "begin_something_anananaaaaak_da_aaak_da_aaaaananaaaaaaan_da_aaaaaaanan_da_aaak_end_something");
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("chef.bake: should accept Clean JSON format from Chef website - args optional", () => {
|
it("chef.bake: should accept Clean JSON format from Chef website - args optional", async () => {
|
||||||
const result = chef.bake("some input", [
|
const result = await chef.bake("some input", [
|
||||||
{ "op": "To Morse Code" },
|
{ "op": "To Morse Code" },
|
||||||
{ "op": "Hex to PEM",
|
{ "op": "Hex to PEM",
|
||||||
"args": ["SOMETHING"] },
|
"args": ["SOMETHING"] },
|
||||||
@ -345,31 +345,28 @@ 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 operation names from Chef Website which contain forward slash", () => {
|
it("chef.bake: should accept operation names from Chef Website which contain forward slash", async () => {
|
||||||
const result = chef.bake("I'll have the test salmon", [
|
const result = await chef.bake("I'll have the test salmon", [
|
||||||
{ "op": "Find / Replace",
|
{ "op": "Find / Replace",
|
||||||
"args": [{ "option": "Regex", "string": "test" }, "good", true, false, true, false]}
|
"args": [{ "option": "Regex", "string": "test" }, "good", true, false, true, false]}
|
||||||
]);
|
]);
|
||||||
assert.strictEqual(result.toString(), "I'll have the good salmon");
|
assert.strictEqual(result.toString(), "I'll have the good salmon");
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("chef.bake: should accept operation names from Chef Website which contain a hyphen", () => {
|
it("chef.bake: should accept operation names from Chef Website which contain a hyphen", async () => {
|
||||||
const result = chef.bake("I'll have the test salmon", [
|
const result = await chef.bake("I'll have the test salmon", [
|
||||||
{ "op": "Adler-32 Checksum",
|
{ "op": "Adler-32 Checksum",
|
||||||
"args": [] }
|
"args": [] }
|
||||||
]);
|
]);
|
||||||
assert.strictEqual(result.toString(), "6e4208f8");
|
assert.strictEqual(result.toString(), "6e4208f8");
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("chef.bake: should accept operation names from Chef Website which contain a period", () => {
|
it("chef.bake: should accept operation names from Chef Website which contain a period", async () => {
|
||||||
const result = chef.bake("30 13 02 01 05 16 0e 41 6e 79 62 6f 64 79 20 74 68 65 72 65 3f", [
|
const result = await chef.bake("30 13 02 01 05 16 0e 41 6e 79 62 6f 64 79 20 74 68 65 72 65 3f", [
|
||||||
{ "op": "Parse ASN.1 hex string",
|
{ "op": "Parse ASN.1 hex string",
|
||||||
"args": [0, 32] }
|
"args": [0, 32] }
|
||||||
]);
|
]);
|
||||||
assert.strictEqual(result.toString(), `SEQUENCE
|
assert.strictEqual(result.toString(), `SEQUENCE\n INTEGER 05\n IA5String 'Anybody there?'\n`);
|
||||||
INTEGER 05
|
|
||||||
IA5String 'Anybody there?'
|
|
||||||
`);
|
|
||||||
}),
|
}),
|
||||||
|
|
||||||
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", () => {
|
||||||
@ -381,16 +378,16 @@ TestRegister.addApiTests([
|
|||||||
}
|
}
|
||||||
}),
|
}),
|
||||||
|
|
||||||
it("chef.bake: cannot accept flowControl operations in recipe", () => {
|
it("chef.bake: cannot accept flowControl operations in recipe", async () => {
|
||||||
assert.throws(() => chef.bake("some input", "magic"), {
|
await assert.rejects(() => chef.bake("some input", "magic"), {
|
||||||
name: "TypeError",
|
name: "TypeError",
|
||||||
message: "flowControl operations like Magic are not currently allowed in recipes for chef.bake in the Node API"
|
message: "flowControl operations like Magic are not currently allowed in recipes for chef.bake in the Node API"
|
||||||
});
|
});
|
||||||
assert.throws(() => chef.bake("some input", magic), {
|
await assert.rejects(() => chef.bake("some input", magic), {
|
||||||
name: "TypeError",
|
name: "TypeError",
|
||||||
message: "flowControl operations like Magic are not currently allowed in recipes for chef.bake in the Node API"
|
message: "flowControl operations like Magic are not currently allowed in recipes for chef.bake in the Node API"
|
||||||
});
|
});
|
||||||
assert.throws(() => chef.bake("some input", ["to base 64", "magic"]), {
|
await assert.rejects(() => chef.bake("some input", ["to base 64", "magic"]), {
|
||||||
name: "TypeError",
|
name: "TypeError",
|
||||||
message: "flowControl operations like Magic are not currently allowed in recipes for chef.bake in the Node API"
|
message: "flowControl operations like Magic are not currently allowed in recipes for chef.bake in the Node API"
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user