cyberchef 11.0.0 → 11.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/CHANGELOG.md +170 -1
  2. package/Dockerfile +2 -2
  3. package/Gruntfile.js +10 -5
  4. package/README.md +10 -7
  5. package/SECURITY.md +11 -19
  6. package/package.json +35 -34
  7. package/src/core/Chef.mjs +2 -0
  8. package/src/core/config/Categories.json +6 -0
  9. package/src/core/config/OperationConfig.json +144 -19
  10. package/src/core/config/modules/Default.mjs +8 -0
  11. package/src/core/config/modules/PGP.mjs +2 -0
  12. package/src/core/config/scripts/generateOpsIndex.mjs +63 -0
  13. package/src/core/config/scripts/newOperation.mjs +31 -4
  14. package/src/core/dishTypes/DishType.mjs +1 -1
  15. package/src/core/errors/ExcludedOperationError.mjs +1 -1
  16. package/src/core/lib/Charts.mjs +3 -3
  17. package/src/core/lib/Protocol.mjs +8 -6
  18. package/src/core/operations/AESDecrypt.mjs +61 -16
  19. package/src/core/operations/AESEncrypt.mjs +26 -11
  20. package/src/core/operations/BLAKE3.mjs +13 -7
  21. package/src/core/operations/BSONDeserialise.mjs +2 -2
  22. package/src/core/operations/BSONSerialise.mjs +3 -2
  23. package/src/core/operations/Bcrypt.mjs +1 -1
  24. package/src/core/operations/BcryptCompare.mjs +1 -1
  25. package/src/core/operations/DecodeText.mjs +4 -0
  26. package/src/core/operations/EncodeText.mjs +4 -0
  27. package/src/core/operations/EscapeSmartCharacters.mjs +129 -0
  28. package/src/core/operations/GenerateDeBruijnSequence.mjs +8 -0
  29. package/src/core/operations/GenerateLoremIpsum.mjs +34 -3
  30. package/src/core/operations/GeneratePGPKeyPair.mjs +8 -7
  31. package/src/core/operations/PGPSign.mjs +83 -0
  32. package/src/core/operations/ParityBit.mjs +1 -1
  33. package/src/core/operations/ParseEthernetFrame.mjs +1 -1
  34. package/src/core/operations/ParseIPv4Header.mjs +2 -2
  35. package/src/core/operations/ParseObjectIDTimestamp.mjs +2 -2
  36. package/src/core/operations/ParseUserAgent.mjs +1 -1
  37. package/src/core/operations/ROR13.mjs +83 -0
  38. package/src/core/operations/RemoveANSIEscapeCodes.mjs +41 -0
  39. package/src/core/operations/SHA2.mjs +1 -1
  40. package/src/core/operations/SeriesChart.mjs +16 -0
  41. package/src/core/operations/ToHexdump.mjs +7 -1
  42. package/src/core/operations/Wrap.mjs +47 -0
  43. package/src/core/operations/XORChecksum.mjs +10 -3
  44. package/src/core/operations/index.mjs +10 -0
  45. package/src/node/index.mjs +25 -0
  46. package/src/web/App.mjs +19 -1
  47. package/src/web/HTMLIngredient.mjs +1 -0
  48. package/src/web/html/index.html +3 -3
  49. package/src/web/static/sitemap.mjs +3 -3
  50. package/src/web/waiters/RecipeWaiter.mjs +9 -1
  51. package/tests/browser/02_ops.js +7 -7
  52. package/tests/browser/03_recipe_load.js +48 -0
  53. package/tests/browser/browserUtils.js +6 -3
  54. package/tests/node/index.mjs +2 -0
  55. package/tests/node/tests/PGP.mjs +69 -0
  56. package/tests/node/tests/lib/ChartsProtocolPrototypePollution.mjs +90 -0
  57. package/tests/node/tests/operations.mjs +41 -2
  58. package/tests/operations/index.mjs +71 -66
  59. package/tests/operations/tests/BLAKE3.mjs +18 -0
  60. package/tests/operations/tests/CharEnc.mjs +26 -0
  61. package/tests/operations/tests/Charts.mjs +11 -0
  62. package/tests/operations/tests/Crypt.mjs +288 -62
  63. package/tests/operations/tests/EscapeSmartCharacters.mjs +132 -0
  64. package/tests/operations/tests/FlaskSession.mjs +11 -8
  65. package/tests/operations/tests/GenerateLoremIpsum.mjs +80 -0
  66. package/tests/operations/tests/Hexdump.mjs +11 -0
  67. package/tests/operations/tests/IPv6Transition.mjs +4 -4
  68. package/tests/operations/tests/PGP.mjs +178 -154
  69. package/tests/operations/tests/ParseEthernetFrame.mjs +11 -0
  70. package/tests/operations/tests/ParseIPv4Header.mjs +34 -0
  71. package/tests/operations/tests/ParseX509CRL.mjs +16 -16
  72. package/tests/operations/tests/ROR13.mjs +45 -0
  73. package/tests/operations/tests/Register.mjs +3 -1
  74. package/tests/operations/tests/RemoveANSIEscapeCodes.mjs +62 -0
  75. package/tests/operations/tests/Wrap.mjs +44 -0
@@ -868,15 +868,15 @@
868
868
  Be aware that the standalone version will never update itself, meaning it will not receive bug fixes or new features until you re-download newer versions manually.
869
869
  </p>
870
870
 
871
- <h6>CyberChef v<%= htmlWebpackPlugin.options.version %></h6>
871
+ <h6>CyberChef <%= htmlWebpackPlugin.options.version %></h6>
872
872
  <ul>
873
873
  <li>Build time: <%= htmlWebpackPlugin.options.compileTime %></li>
874
- <li>The changelog for this version can be viewed <a href="https://github.com/gchq/CyberChef/blob/v<%= htmlWebpackPlugin.options.version %>/CHANGELOG.md">here</a></li>
874
+ <li>The changelog for this version can be viewed <a href="https://github.com/gchq/CyberChef/blob/v<%= htmlWebpackPlugin.options.latestReleaseVersion %>/CHANGELOG.md">here</a></li>
875
875
  <li>&copy; Crown Copyright 2016-<%= htmlWebpackPlugin.options.compileYear %></li>
876
876
  <li>Released under the Apache Licence, Version 2.0</li>
877
877
  <li>SHA256 hash: DOWNLOAD_HASH_PLACEHOLDER</li>
878
878
  </ul>
879
- <a href="CyberChef_v<%= htmlWebpackPlugin.options.version %>.zip" download class="btn btn-outline-primary">Download ZIP file</a>
879
+ <a href="<%= htmlWebpackPlugin.options.downloadZipFilename %>" download class="btn btn-outline-primary">Download ZIP file</a>
880
880
  </div>
881
881
  <div class="modal-footer">
882
882
  <button type="button" class="btn btn-primary" data-dismiss="modal">Ok</button>
@@ -1,4 +1,4 @@
1
- import sm from "sitemap";
1
+ import { SitemapStream, streamToPromise } from "sitemap";
2
2
  import OperationConfig from "../../core/config/OperationConfig.json" with { type: "json" };
3
3
 
4
4
  /**
@@ -11,7 +11,7 @@ import OperationConfig from "../../core/config/OperationConfig.json" with { type
11
11
 
12
12
  const baseUrl = "https://gchq.github.io/CyberChef/";
13
13
 
14
- const smStream = new sm.SitemapStream({});
14
+ const smStream = new SitemapStream({});
15
15
 
16
16
  smStream.write({
17
17
  url: baseUrl,
@@ -28,6 +28,6 @@ for (const op in OperationConfig) {
28
28
  }
29
29
  smStream.end();
30
30
 
31
- sm.streamToPromise(smStream).then(
31
+ streamToPromise(smStream).then(
32
32
  (buffer) => console.log(buffer.toString()), // eslint-disable-line no-console
33
33
  );
@@ -487,11 +487,19 @@ class RecipeWaiter {
487
487
  * @param {HTMLElement} op
488
488
  */
489
489
  triggerArgEvents(op) {
490
- // Trigger populateOption and argSelector events
490
+ // Trigger argSelector events and populateOption events only where the target is empty.
491
+ // When loading a saved recipe, arguments are populated before this method is called, so
492
+ // re-triggering populateOption events would overwrite saved custom values with defaults.
493
+ const args = op.querySelectorAll(".arg");
491
494
  const triggerableOptions = op.querySelectorAll(".populate-option, .arg-selector");
492
495
  const evt = new Event("change", {bubbles: true});
496
+
493
497
  if (triggerableOptions.length) {
494
498
  for (const el of triggerableOptions) {
499
+ if (el.classList.contains("populate-option")) {
500
+ const target = args[el.getAttribute("data-target")];
501
+ if (target && target.value !== "") continue;
502
+ }
495
503
  el.dispatchEvent(evt);
496
504
  }
497
505
  }
@@ -30,8 +30,8 @@ module.exports = {
30
30
  testOp(browser, "A1Z26 Cipher Decode", "20 5 19 20 15 21 20 16 21 20", "testoutput");
31
31
  testOp(browser, "A1Z26 Cipher Encode", "test input", "20 5 19 20 9 14 16 21 20");
32
32
  testOp(browser, "ADD", "test input", "Ê»ÉÊv¿ÄÆËÊ", [{ "option": "Hex", "string": "56" }]);
33
- testOp(browser, "AES Decrypt", "b443f7f7c16ac5396a34273f6f639caa", "test output", [{ "option": "Hex", "string": "00112233445566778899aabbccddeeff" }, { "option": "Hex", "string": "00000000000000000000000000000000" }, "CBC", "Hex", "Raw", { "option": "Hex", "string": "" }]);
34
- testOp(browser, "AES Encrypt", "test input", "e42eb8fbfb7a98fff061cd2c1a794d92", [{"option": "Hex", "string": "00112233445566778899aabbccddeeff"}, {"option": "Hex", "string": "00000000000000000000000000000000"}, "CBC", "Raw", "Hex"]);
33
+ testOp(browser, "AES Decrypt", "b443f7f7c16ac5396a34273f6f639caa", "test output", [{ "option": "Hex", "string": "00112233445566778899aabbccddeeff" }, { "option": "Hex", "string": "00000000000000000000000000000000" }, 16, "CBC", "Hex", "Raw", { "option": "Hex", "string": "" }, { "option": "Hex", "string": "" }, "Off"]);
34
+ testOp(browser, "AES Encrypt", "test input", "e42eb8fbfb7a98fff061cd2c1a794d92", [{"option": "Hex", "string": "00112233445566778899aabbccddeeff"}, {"option": "Hex", "string": "00000000000000000000000000000000"}, "CBC", "Raw", "Hex", "Off"]);
35
35
  testOp(browser, "AND", "test input", "4$04 $044", [{ "option": "Hex", "string": "34" }]);
36
36
  testOp(browser, "Add line numbers", "test input", "1 test input");
37
37
  testOp(browser, ["From Hex", "Add Text To Image", "SHA2"], Images.PNG_HEX, "50cdf8ea483c55564a091650c2bccb4586f919b721e5fe9d6a61660505b4346d6ebdb2ef0cf075a7728cd84cb26ea3e477b5bd86a94a49a27d79423994afb60a", [[], ["Chef", "Center", "Middle", 0, 0, 16, "Roboto"], []]);
@@ -64,7 +64,7 @@ module.exports = {
64
64
  testOp(browser, "BSON serialise", '{"a":"test"}', "\u0011\u0000\u0000\u0000\u0002a\u0000\u0005\u0000\u0000\u0000test\u0000\u0000");
65
65
  // testOp(browser, "Bacon Cipher Decode", "test input", "test_output");
66
66
  // testOp(browser, "Bacon Cipher Encode", "test input", "test_output");
67
- testOp(browser, "Bcrypt", "test input", /^\$2a\$06\$.{53}$/, [6]);
67
+ testOp(browser, "Bcrypt", "test input", /^\$2b\$06\$.{53}$/, [6]);
68
68
  testOp(browser, "Bcrypt compare", "test input", "Match: test input", ["$2a$05$FCfBSVX7OeRkK.9kQVFCiOYu9XtwtIbePqUiroD1lkASW9q5QClzG"]);
69
69
  testOp(browser, "Bcrypt parse", "$2a$05$kXWtAIGB/R8VEzInoM5ocOTBtyc0m2YTIwFiBU/0XoW032f9QrkWW", /Rounds: 5/);
70
70
  testOp(browser, "Bifid Cipher Decode", "qblb tfovy", "test input", ["pass"]);
@@ -80,8 +80,8 @@ module.exports = {
80
80
  testOpHtml(browser, "Bombe", "XTSYN WAEUG EZALY NRQIM AMLZX MFUOD AWXLY LZCUZ QOQBQ JLCPK NDDRW F", "table tr:last-child td:first-child", "ECG", ["3-rotor", "LEYJVCNIXWPBQMDRTAKZGFUHOS", "BDFHJLCPRTXVZNYEIWGAKMUSQO<W", "AJDKSIRUXBLHWTMCQGZNPYFVOE<F", "ESOVPZJAYQUIRHXLNFTGKDCMWB<K", "AY BR CU DH EQ FS GL IP JX KN MO TZ VW", "HELLO CYBER CHEFU SER", 0, true]);
81
81
  testOp(browser, ["Bzip2 Compress", "To Hex"], "test input", "42 5a 68 39 31 41 59 26 53 59 cf 96 82 1d 00 00 03 91 80 40 00 02 21 4e 00 20 00 21 90 c2 10 c0 88 33 92 8e df 17 72 45 38 50 90 cf 96 82 1d");
82
82
  testOp(browser, ["From Hex", "Bzip2 Decompress"], "425a68393141592653597b0884b7000003038000008200ce00200021a647a4218013709517c5dc914e14241ec2212dc0", "test_output", [[], [true]]);
83
- // testOp(browser, "CBOR Decode", "test input", "test output");
84
- // testOp(browser, "CBOR Encode", "test input", "test output");
83
+ testOp(browser, ["From Hex", "CBOR Decode"], "f9 3e 00", "1.5");
84
+ testOp(browser, ["CBOR Encode", "To Hex"], "1.5", "f9 3e 00");
85
85
  testOp(browser, "CRC Checksum", "test input", "77c7", ["CRC-16"]);
86
86
  testOp(browser, "CRC Checksum", "test input", "29822bc8", ["CRC-32"]);
87
87
  testOp(browser, "CRC Checksum", "test input", "9d", ["CRC-8"]);
@@ -278,11 +278,11 @@ module.exports = {
278
278
  testOpHtml(browser, "Parse UDP", "04 89 00 35 00 2c 01 01", "tr:last-child td:last-child", "0x0101");
279
279
  // testOp(browser, "Parse UNIX file permissions", "test input", "test_output");
280
280
  // testOp(browser, "Parse URI", "test input", "test_output");
281
- // testOp(browser, "Parse User Agent", "test input", "test_output");
281
+ testOp(browser, "Parse User Agent", "Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0 ", /Architecture: amd64/);
282
282
  // testOp(browser, "Parse X.509 certificate", "test input", "test_output");
283
283
  testOpFile(browser, "Play Media", "files/mp3example.mp3", "audio", "");
284
284
  // testOp(browser, "Power Set", "test input", "test_output");
285
- // testOp(browser, "Protobuf Decode", "test input", "test_output");
285
+ testOp(browser, ["From Hex", "Protobuf Decode"], "0d1c0000001203596f751a024d65202b2a0a0a066162633132331200", /"1": "abc123"/, [[], ["", false, false]]);
286
286
  // testOp(browser, "Pseudo-Random Number Generator", "test input", "test_output");
287
287
  // testOp(browser, "RC2 Decrypt", "test input", "test_output");
288
288
  // testOp(browser, "RC2 Encrypt", "test input", "test_output");
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Regression tests for recipe loading behaviour.
3
+ *
4
+ * @author C85297 [95289555+C85297@users.noreply.github.com]
5
+ * @copyright Crown Copyright
6
+ * @license Apache-2.0
7
+ */
8
+
9
+ const utils = require("./browserUtils.js");
10
+
11
+ module.exports = {
12
+ before: browser => {
13
+ browser
14
+ .resizeWindow(1280, 800)
15
+ .url(browser.launchUrl)
16
+ .useCss()
17
+ .waitForElementNotPresent("#preloader", 10000);
18
+ },
19
+
20
+ "Recipe load preserves populated arguments": browser => {
21
+ const inputFormat = "HH:mm:ss a MMM DD, YYYY ";
22
+ const input = "10:20:30 pm Sep 26, 2019 ";
23
+
24
+ utils.loadRecipe(
25
+ browser,
26
+ "Translate DateTime Format",
27
+ input,
28
+ [
29
+ "Standard date and time",
30
+ inputFormat,
31
+ "UTC",
32
+ "DD/MM/YYYY HH:mm:ss",
33
+ "UTC"
34
+ ]
35
+ );
36
+
37
+ browser.execute(() => {
38
+ return Array.from(document.querySelectorAll("#rec-list li.operation .arg"))
39
+ .map(arg => arg.value);
40
+ }, [], function({value}) {
41
+ browser.expect(value[1]).to.equal(inputFormat);
42
+ });
43
+ },
44
+
45
+ after: browser => {
46
+ browser.end();
47
+ }
48
+ };
@@ -51,14 +51,17 @@ function setInput(browser, input, type=true) {
51
51
  */
52
52
  function bake(browser) {
53
53
  browser
54
+ // Let any pending debounced inputChange/stateChange (~20ms each) fire so the
55
+ // worker has the latest input buffer before we ask it to bake.
56
+ .pause(50)
54
57
  // Ensure we're not currently busy
55
- .waitForElementNotVisible("#output-loader", 5000)
58
+ .waitForElementNotVisible("#output-loader", 10000)
56
59
  .expect.element("#bake span").text.to.equal("BAKE!");
57
60
 
58
61
  browser
59
62
  .click("#bake")
60
- .waitForElementNotVisible("#stale-indicator", 5000)
61
- .waitForElementNotVisible("#output-loader", 5000);
63
+ .waitForElementNotVisible("#stale-indicator", 10000)
64
+ .waitForElementNotVisible("#output-loader", 10000);
62
65
  }
63
66
 
64
67
  /** @function
@@ -18,12 +18,14 @@ import {
18
18
  import TestRegister from "../lib/TestRegister.mjs";
19
19
  import "./tests/nodeApi.mjs";
20
20
  import "./tests/operations.mjs";
21
+ import "./tests/PGP.mjs";
21
22
  import "./tests/File.mjs";
22
23
  import "./tests/Dish.mjs";
23
24
  import "./tests/NodeDish.mjs";
24
25
  import "./tests/Utils.mjs";
25
26
  import "./tests/Categories.mjs";
26
27
  import "./tests/lib/BigIntUtils.mjs";
28
+ import "./tests/lib/ChartsProtocolPrototypePollution.mjs";
27
29
 
28
30
  const testStatus = {
29
31
  allTestsPassing: true,
@@ -0,0 +1,69 @@
1
+ /**
2
+ * PGP node tests.
3
+ *
4
+ * @author C85297 [95289555+C85297@users.noreply.github.com]
5
+ * @copyright Crown Copyright 2026
6
+ * @license Apache-2.0
7
+ */
8
+
9
+ import assert from "assert";
10
+ import kbpgp from "kbpgp";
11
+ import * as es6promisify from "es6-promisify";
12
+
13
+ import TestRegister from "../../lib/TestRegister.mjs";
14
+ import it from "../assertionHandler.mjs";
15
+ import GeneratePGPKeyPair from "../../../src/core/operations/GeneratePGPKeyPair.mjs";
16
+
17
+ const promisify = es6promisify.default ? es6promisify.default.promisify : es6promisify.promisify;
18
+
19
+ const PUBLIC_KEY_BLOCK = /-----BEGIN PGP PUBLIC KEY BLOCK-----[\s\S]*-----END PGP PUBLIC KEY BLOCK-----/;
20
+
21
+ /**
22
+ * Generate a PGP key pair and import the generated public key.
23
+ *
24
+ * @param {string} keyType
25
+ * @returns {Promise<Object>}
26
+ */
27
+ async function generateAndImportPublicKey(keyType) {
28
+ const operation = new GeneratePGPKeyPair();
29
+ const generatedKeyPair = await operation.run("", [
30
+ keyType,
31
+ "",
32
+ "User",
33
+ "akb@notreal.gchq.gov.uk"
34
+ ]);
35
+
36
+ const publicKey = generatedKeyPair.match(PUBLIC_KEY_BLOCK);
37
+
38
+ assert(publicKey, "Generated key pair should contain an ASCII-armoured public key");
39
+
40
+ return promisify(kbpgp.KeyManager.import_from_armored_pgp)({
41
+ armored: publicKey[0],
42
+ opts: {
43
+ "no_check_keys": true
44
+ }
45
+ });
46
+ }
47
+
48
+ TestRegister.addApiTests([
49
+ it("Generate PGP Key Pair: ECC keys should include ECDSA signing and ECDH encryption subkeys", async () => {
50
+ const publicKey = await generateAndImportPublicKey("ECC-256");
51
+ const subkeyAlgorithms = publicKey.subkeys.map(subkey => subkey.key.type);
52
+
53
+ assert.strictEqual(
54
+ publicKey.primary.key.type,
55
+ kbpgp.const.openpgp.public_key_algorithms.ECDSA,
56
+ "Generated ECC PGP primary key should use ECDSA"
57
+ );
58
+
59
+ assert(
60
+ subkeyAlgorithms.includes(kbpgp.const.openpgp.public_key_algorithms.ECDSA),
61
+ "Generated ECC PGP key should include an ECDSA signing subkey"
62
+ );
63
+
64
+ assert(
65
+ subkeyAlgorithms.includes(kbpgp.const.openpgp.public_key_algorithms.ECDH),
66
+ "Generated ECC PGP key should include an ECDH encryption subkey"
67
+ );
68
+ })
69
+ ]);
@@ -0,0 +1,90 @@
1
+ import TestRegister from "../../../lib/TestRegister.mjs";
2
+ import {getSeriesValues} from "../../../../src/core/lib/Charts.mjs";
3
+ import {objToTable} from "../../../../src/core/lib/Protocol.mjs";
4
+ import SeriesChart from "../../../../src/core/operations/SeriesChart.mjs";
5
+ import ParseUDP from "../../../../src/core/operations/ParseUDP.mjs";
6
+ import it from "../../assertionHandler.mjs";
7
+ import assert from "assert";
8
+
9
+ const hasOwn = (obj, key) => Object.prototype.hasOwnProperty.call(obj, key);
10
+
11
+ TestRegister.addApiTests([
12
+ it("Charts: should not pollute Object.prototype from a __proto__ series name", () => {
13
+ const xVal = "<img src=x onerror=alert(1)>";
14
+ delete Object.prototype[xVal];
15
+
16
+ try {
17
+ const result = getSeriesValues(`__proto__,${xVal},1`, "\n", ",", false);
18
+
19
+ assert.equal(Object.prototype[xVal], undefined);
20
+ assert.deepEqual(result.xValues, [xVal]);
21
+ assert.equal(result.series.length, 1);
22
+ assert.equal(result.series[0].name, "__proto__");
23
+ assert.equal(Object.getPrototypeOf(result.series[0].data), null);
24
+ assert(hasOwn(result.series[0].data, xVal));
25
+ assert.equal(result.series[0].data[xVal], 1);
26
+ } finally {
27
+ delete Object.prototype[xVal];
28
+ }
29
+ }),
30
+
31
+ it("Charts: should keep __proto__ x-axis names as own data keys", () => {
32
+ const result = getSeriesValues("safe,__proto__,1", "\n", ",", false);
33
+
34
+ assert.equal(result.series.length, 1);
35
+ assert.equal(Object.getPrototypeOf(result.series[0].data), null);
36
+ assert(hasOwn(result.series[0].data, "__proto__"));
37
+ assert.equal(result.series[0].data.__proto__, 1);
38
+ }),
39
+
40
+ it("Protocol: should ignore inherited properties when rendering tables", () => {
41
+ const inheritedKey = "<img src=x onerror=alert(1)>";
42
+ delete Object.prototype[inheritedKey];
43
+
44
+ try {
45
+ Object.prototype[inheritedKey] = "polluted";
46
+
47
+ const html = objToTable({safe: "value"});
48
+
49
+ assert(!html.includes(inheritedKey));
50
+ assert(!html.includes("polluted"));
51
+ assert(html.includes("safe"));
52
+ assert(html.includes("value"));
53
+ } finally {
54
+ delete Object.prototype[inheritedKey];
55
+ }
56
+ }),
57
+
58
+ it("Protocol: should escape table keys and scalar values", () => {
59
+ const obj = {
60
+ "<b>field</b>": "<img src=x onerror=alert(1)>",
61
+ };
62
+
63
+ const html = objToTable(obj);
64
+
65
+ assert(!html.includes("<b>field</b>"));
66
+ assert(!html.includes("<img src=x onerror=alert(1)>"));
67
+ assert(html.includes("&lt;b&gt;field&lt;/b&gt;"));
68
+ assert(html.includes("&lt;img src=x onerror=alert(1)&gt;"));
69
+ }),
70
+
71
+ it("Series chart and Parse UDP: should not expose polluted prototype data as HTML", () => {
72
+ const xVal = "<img src=x onerror=alert(document.domain)>";
73
+ delete Object.prototype[xVal];
74
+
75
+ try {
76
+ const chartHtml = new SeriesChart().run(
77
+ `__proto__,${xVal},1`,
78
+ ["Line feed", "Comma", "", 1, "red"]
79
+ );
80
+ assert.equal(Object.prototype[xVal], undefined);
81
+
82
+ const parseUDP = new ParseUDP();
83
+ const tableHtml = parseUDP.present(parseUDP.run(chartHtml, ["Raw"]));
84
+
85
+ assert(!/<img|onerror|alert\(/.test(tableHtml));
86
+ } finally {
87
+ delete Object.prototype[xVal];
88
+ }
89
+ }),
90
+ ]);
@@ -79,7 +79,46 @@ TestRegister.addApiTests([
79
79
  string: "some iv some iv1",
80
80
  option: "utf8",
81
81
  },
82
+ ivLength: 16,
82
83
  mode: "OFB",
84
+ inputType: "Hex",
85
+ outputType: "Raw",
86
+ gcmTag: {
87
+ option: "Hex",
88
+ string: ""
89
+ },
90
+ aad: {
91
+ option: "Hex",
92
+ string: ""
93
+ },
94
+ ivFromInput: "Off"
95
+ });
96
+ assert.equal(result.toString(), "a slightly longer sampleinput?");
97
+ }),
98
+
99
+ it("AES decrypt: IV from input", () => {
100
+ const result = AESDecrypt("4a123af235a507bbc9d5871721d61b98504d569a9a5a7847e2d78315fec7736f6d6520697620736f6d6520697631", {
101
+ key: {
102
+ string: "some longer key1",
103
+ option: "utf8",
104
+ },
105
+ iv: {
106
+ string: "",
107
+ option: "Hex",
108
+ },
109
+ ivLength: 16,
110
+ mode: "OFB",
111
+ inputType: "Hex",
112
+ outputType: "Raw",
113
+ gcmTag: {
114
+ option: "Hex",
115
+ string: ""
116
+ },
117
+ aad: {
118
+ option: "Hex",
119
+ string: ""
120
+ },
121
+ ivFromInput: "From end"
83
122
  });
84
123
  assert.equal(result.toString(), "a slightly longer sampleinput?");
85
124
  }),
@@ -136,8 +175,8 @@ Tiger-128`;
136
175
  it("Bcrypt", async () => {
137
176
  const result = await chef.bcrypt("Put a Sock In It");
138
177
  const strResult = result.toString();
139
- assert.equal(strResult.length, 60);
140
- assert.equal(strResult.slice(0, 7), "$2a$10$");
178
+ assert.match(strResult, /^\$2b\$10\$[./A-Za-z0-9]{53}$/);
179
+ assert.equal(strResult.split("$").length, 4);
141
180
  }),
142
181
 
143
182
  it("bcryptCompare", async() => {