diff --git a/package-lock.json b/package-lock.json index f5f6137f..7a33b297 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4553,6 +4553,15 @@ "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", "dev": true }, + "cbor": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/cbor/-/cbor-5.2.0.tgz", + "integrity": "sha512-5IMhi9e1QU76ppa5/ajP1BmMWZ2FHkhAhjeVKQ/EFCgYSEaeVaoGtL7cxJskf9oCCk+XjzaIdc3IuU/dbA/o2A==", + "requires": { + "bignumber.js": "^9.0.1", + "nofilter": "^1.0.4" + } + }, "chai-nightwatch": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/chai-nightwatch/-/chai-nightwatch-0.4.0.tgz", @@ -10881,6 +10890,11 @@ "resolved": "https://registry.npmjs.org/nodom/-/nodom-2.4.0.tgz", "integrity": "sha512-qhfYgpoCSi37HLiViMlf94YqMQdvk3n3arI1uGbAWZK9NKCYRSI42W8lATeGloYGLYxb8us1C5rTvtsXjwdWQg==" }, + "nofilter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/nofilter/-/nofilter-1.0.4.tgz", + "integrity": "sha512-N8lidFp+fCz+TD51+haYdbDGrcBWwuHX40F5+z0qkUjMJ5Tp+rdSuAkMJ9N9eoolDlEVTf6u5icM+cNKkKW2mA==" + }, "nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", diff --git a/package.json b/package.json index ddefbc7a..d657580b 100644 --- a/package.json +++ b/package.json @@ -98,6 +98,7 @@ "browserify-zlib": "^0.2.0", "bson": "^4.2.2", "buffer": "^6.0.3", + "cbor": "^5.0.1", "chi-squared": "^1.1.0", "codepage": "^1.14.0", "core-js": "^3.8.3", diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 3a5eb0d5..95e5870e 100755 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -61,7 +61,9 @@ "Parse TLV", "CSV to JSON", "JSON to CSV", - "Avro to JSON" + "Avro to JSON", + "CBOR Encode", + "CBOR Decode" ] }, { diff --git a/src/core/operations/CBORDecode.mjs b/src/core/operations/CBORDecode.mjs new file mode 100644 index 00000000..f4bda7c0 --- /dev/null +++ b/src/core/operations/CBORDecode.mjs @@ -0,0 +1,41 @@ +/** + * @author Danh4 [dan.h4@ncsc.gov.uk] + * @copyright Crown Copyright 2020 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import Cbor from "cbor"; + +/** + * CBOR Decode operation + */ +class CBORDecode extends Operation { + + /** + * CBORDecode constructor + */ + constructor() { + super(); + + this.name = "CBOR Decode"; + this.module = "Serialise"; + this.description = "Concise Binary Object Representation (CBOR) is a binary data serialization format loosely based on JSON. Like JSON it allows the transmission of data objects that contain name–value pairs, but in a more concise manner. This increases processing and transfer speeds at the cost of human readability. It is defined in IETF RFC 8949."; + this.infoURL = "https://wikipedia.org/wiki/CBOR"; + this.inputType = "ArrayBuffer"; + this.outputType = "JSON"; + this.args = []; + } + + /** + * @param {ArrayBuffer} input + * @param {Object[]} args + * @returns {JSON} + */ + run(input, args) { + return Cbor.decodeFirstSync(Buffer.from(input).toString("hex")); + } + +} + +export default CBORDecode; diff --git a/src/core/operations/CBOREncode.mjs b/src/core/operations/CBOREncode.mjs new file mode 100644 index 00000000..c6e094a9 --- /dev/null +++ b/src/core/operations/CBOREncode.mjs @@ -0,0 +1,41 @@ +/** + * @author Danh4 [dan.h4@ncsc.gov.uk] + * @copyright Crown Copyright 2020 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import Cbor from "cbor"; + +/** + * CBOR Encode operation + */ +class CBOREncode extends Operation { + + /** + * CBOREncode constructor + */ + constructor() { + super(); + + this.name = "CBOR Encode"; + this.module = "Serialise"; + this.description = "Concise Binary Object Representation (CBOR) is a binary data serialization format loosely based on JSON. Like JSON it allows the transmission of data objects that contain name–value pairs, but in a more concise manner. This increases processing and transfer speeds at the cost of human readability. It is defined in IETF RFC 8949."; + this.infoURL = "https://wikipedia.org/wiki/CBOR"; + this.inputType = "JSON"; + this.outputType = "ArrayBuffer"; + this.args = []; + } + + /** + * @param {JSON} input + * @param {Object[]} args + * @returns {ArrayBuffer} + */ + run(input, args) { + return new Uint8Array(Cbor.encodeCanonical(input)).buffer; + } + +} + +export default CBOREncode; diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs index d20ccc61..f2225fc6 100644 --- a/tests/operations/index.mjs +++ b/tests/operations/index.mjs @@ -102,6 +102,9 @@ import "./tests/Colossus.mjs"; import "./tests/ParseObjectIDTimestamp.mjs"; import "./tests/Unicode.mjs"; import "./tests/RSA.mjs"; +import "./tests/CBOREncode.mjs"; +import "./tests/CBORDecode.mjs"; + // Cannot test operations that use the File type yet // import "./tests/SplitColourChannels.mjs"; diff --git a/tests/operations/tests/CBORDecode.mjs b/tests/operations/tests/CBORDecode.mjs new file mode 100644 index 00000000..e3015d4e --- /dev/null +++ b/tests/operations/tests/CBORDecode.mjs @@ -0,0 +1,144 @@ +/** + * CBOR Decode Tests + * + * @author Danh4 [dan.h4@ncsc.gov.uk] + * @copyright Crown Copyright 2019 + * @license Apache-2.0 + */ + +import TestRegister from "../../lib/TestRegister.mjs"; + +TestRegister.addTests([ + { + name: "CBOR Decode: Can decode integer", + input: "0f", + expectedOutput: "15", + recipeConfig: [ + { + op: "From Hex", + args: [] + }, + { + op: "CBOR Decode", + args: [] + } + ] + }, + { + name: "CBOR Decode: Can decode decimal", + input: "f9 3e 00", + expectedOutput: "1.5", + recipeConfig: [ + { + op: "From Hex", + args: [] + }, + { + op: "CBOR Decode", + args: [] + } + ] + }, + { + name: "From Hex: Can decode text", + input: "64 54 65 78 74", + expectedOutput: "\"Text\"", + recipeConfig: [ + { + op: "From Hex", + args: [] + }, + { + op: "CBOR Decode", + args: [] + } + ] + }, + { + name: "From Hex: Can decode boolean true", + input: "f5", + expectedOutput: "true", + recipeConfig: [ + { + op: "From Hex", + args: [] + }, + { + op: "CBOR Decode", + args: [] + } + ] + }, + { + name: "From Hex: Can decode boolean false", + input: "f4", + expectedOutput: "false", + recipeConfig: [ + { + op: "From Hex", + args: [] + }, + { + op: "CBOR Decode", + args: [] + } + ] + }, + { + name: "From Hex: Can decode map", + input: "a3 61 61 01 61 62 02 61 63 03", + expectedOutput: JSON.stringify({a: 1, b: 2, c: 3}), + recipeConfig: [ + { + op: "From Hex", + args: [] + }, + { + op: "CBOR Decode", + args: [] + }, + { + op: "JSON Minify", + args: [] + } + ] + }, + { + name: "From Hex: Can decode list", + input: "83 00 01 02", + expectedOutput: "[0,1,2]", + recipeConfig: [ + { + op: "From Hex", + args: [] + }, + { + op: "CBOR Decode", + args: [] + }, + { + op: "JSON Minify", + args: [] + } + ] + }, + { + name: "From Hex: Can round trip with encode", + input: JSON.stringify({a: 1, b: false, c: [1, 2, 3]}), + expectedOutput: JSON.stringify({a: 1, b: false, c: [1, 2, 3]}), + recipeConfig: [ + { + op: "CBOR Encode", + args: [] + }, + { + op: "CBOR Decode", + args: [] + }, + { + op: "JSON Minify", + args: [] + } + ] + } +]); diff --git a/tests/operations/tests/CBOREncode.mjs b/tests/operations/tests/CBOREncode.mjs new file mode 100644 index 00000000..a12ba686 --- /dev/null +++ b/tests/operations/tests/CBOREncode.mjs @@ -0,0 +1,117 @@ +/** + * CBOR Encode Tests. + * + * @author Danh4 [dan.h4@ncsc.gov.uk] + * @copyright Crown Copyright 2019 + * @license Apache-2.0 + */ + +import TestRegister from "../../lib/TestRegister.mjs"; + +TestRegister.addTests([ + { + name: "CBOR Encode: Can encode integer", + input: "15", + expectedOutput: "0f", + recipeConfig: [ + { + op: "CBOR Encode", + args: [] + }, + { + op: "To Hex", + args: [] + } + ] + }, + { + name: "CBOR Decode: Can encode decimal", + input: "1.5", + expectedOutput: "f9 3e 00", + recipeConfig: [ + { + op: "CBOR Encode", + args: [] + }, + { + op: "To Hex", + args: [] + } + ] + }, + { + name: "CBOR Encode: Can encode text", + input: "\"Text\"", + expectedOutput: "64 54 65 78 74", + recipeConfig: [ + { + op: "CBOR Encode", + args: [] + }, + { + op: "To Hex", + args: [] + } + ] + }, + { + name: "CBOR Encode: Can encode boolean true", + input: "true", + expectedOutput: "f5", + recipeConfig: [ + { + op: "CBOR Encode", + args: [] + }, + { + op: "To Hex", + args: [] + } + ] + }, + { + name: "CBOR Encode: Can encode boolean false", + input: "false", + expectedOutput: "f4", + recipeConfig: [ + { + op: "CBOR Encode", + args: [] + }, + { + op: "To Hex", + args: [] + } + ] + }, + { + name: "CBOR Encode: Can encode map", + input: JSON.stringify({a: 1, b: 2, c: 3}), + expectedOutput: "a3 61 61 01 61 62 02 61 63 03", + recipeConfig: [ + { + op: "CBOR Encode", + args: [] + }, + { + op: "To Hex", + args: [] + } + ] + }, + { + name: "CBOR Encode: Can encode list", + input: "[0,1,2]", + expectedOutput: "83 00 01 02", + recipeConfig: [ + { + op: "CBOR Encode", + args: [] + }, + { + op: "To Hex", + args: [] + } + ] + } +]);