cyberchef 10.23.0 → 11.0.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 (50) hide show
  1. package/.devcontainer/devcontainer.json +1 -1
  2. package/.nvmrc +1 -1
  3. package/CHANGELOG.md +79 -0
  4. package/CONTRIBUTING.md +4 -1
  5. package/Dockerfile +2 -2
  6. package/Gruntfile.js +3 -17
  7. package/README.md +3 -3
  8. package/babel.config.js +4 -1
  9. package/package.json +31 -27
  10. package/src/core/ChefWorker.js +1 -1
  11. package/src/core/Recipe.mjs +1 -1
  12. package/src/core/config/Categories.json +2 -1
  13. package/src/core/config/OperationConfig.json +54 -3
  14. package/src/core/config/modules/Default.mjs +2 -0
  15. package/src/core/config/scripts/fixCryptoApiImports.mjs +54 -0
  16. package/src/core/config/scripts/fixSnackBarMarkup.mjs +28 -0
  17. package/src/core/lib/Extract.mjs +5 -0
  18. package/src/core/lib/Magic.mjs +1 -1
  19. package/src/core/lib/ParityBit.mjs +50 -0
  20. package/src/core/operations/AnalyseUUID.mjs +109 -6
  21. package/src/core/operations/ExtractEmailAddresses.mjs +2 -3
  22. package/src/core/operations/FromPunycode.mjs +1 -1
  23. package/src/core/operations/ParityBit.mjs +128 -0
  24. package/src/core/operations/RegularExpression.mjs +2 -1
  25. package/src/core/operations/RenderMarkdown.mjs +35 -4
  26. package/src/core/operations/ShowBase64Offsets.mjs +28 -28
  27. package/src/core/operations/ToPunycode.mjs +1 -1
  28. package/src/core/operations/index.mjs +2 -0
  29. package/src/node/NodeRecipe.mjs +8 -7
  30. package/src/node/api.mjs +4 -4
  31. package/src/node/index.mjs +5 -0
  32. package/src/web/HTMLOperation.mjs +8 -2
  33. package/src/web/html/index.html +1 -1
  34. package/src/web/index.js +2 -2
  35. package/src/web/static/sitemap.mjs +1 -1
  36. package/src/web/waiters/OperationsWaiter.mjs +30 -13
  37. package/tests/lib/wasmFetchPolyfill.mjs +31 -0
  38. package/tests/node/consumers/cjs-consumer.js +2 -2
  39. package/tests/node/consumers/esm-consumer.mjs +2 -2
  40. package/tests/node/tests/Categories.mjs +2 -2
  41. package/tests/node/tests/nodeApi.mjs +55 -58
  42. package/tests/node/tests/operations.mjs +2 -3
  43. package/tests/operations/index.mjs +6 -0
  44. package/tests/operations/tests/AnalyseUUID.mjs +66 -0
  45. package/tests/operations/tests/Base64.mjs +11 -0
  46. package/tests/operations/tests/ExtractEmailAddresses.mjs +38 -12
  47. package/tests/operations/tests/Fernet.mjs +18 -3
  48. package/tests/operations/tests/ParityBit.mjs +147 -0
  49. package/tests/operations/tests/RegularExpression.mjs +75 -0
  50. package/tests/operations/tests/RenderMarkdown.mjs +110 -0
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Parity Bit functions.
3
+ *
4
+ * @author j83305 [awz22@protonmail.com]
5
+ * @copyright Crown Copyright 2020
6
+ * @license Apache-2.0
7
+ *
8
+ */
9
+
10
+ import OperationError from "../errors/OperationError.mjs";
11
+
12
+ /**
13
+ * Function to take the user input and encode using the given arguments
14
+ * @param input string of binary
15
+ * @param args array
16
+ */
17
+ export function calculateParityBit(input, args) {
18
+ let count1s = 0;
19
+ for (let i = 0; i < input.length; i++) {
20
+ const character = input.charAt(i);
21
+ if (character === "1") {
22
+ count1s++;
23
+ } else if (character !== args[3] && character !== "0" && character !== " ") {
24
+ throw new OperationError("unexpected character encountered: \"" + character + "\"");
25
+ }
26
+ }
27
+ let parityBit = "1";
28
+ const flipflop = args[0] === "Even Parity" ? 0 : 1;
29
+ if (count1s % 2 === flipflop) {
30
+ parityBit = "0";
31
+ }
32
+ if (args[1] === "End") {
33
+ return input + parityBit;
34
+ } else {
35
+ return parityBit + input;
36
+ }
37
+ }
38
+
39
+ /**
40
+ * just removes the parity bit to return the original data
41
+ * @param input string of binary, encoded
42
+ * @param args array
43
+ */
44
+ export function decodeParityBit(input, args) {
45
+ if (args[1] === "End") {
46
+ return input.slice(0, -1);
47
+ } else {
48
+ return input.slice(1);
49
+ }
50
+ }
@@ -1,5 +1,6 @@
1
1
  /**
2
2
  * @author n1474335 [n1474335@gmail.com]
3
+ * @author ko80240 [csk.dev@proton.me]
3
4
  * @copyright Crown Copyright 2023
4
5
  * @license Apache-2.0
5
6
  */
@@ -8,6 +9,7 @@ import * as uuid from "uuid";
8
9
 
9
10
  import Operation from "../Operation.mjs";
10
11
  import OperationError from "../errors/OperationError.mjs";
12
+ import { toHex } from "../lib/Hex.mjs";
11
13
 
12
14
  /**
13
15
  * Analyse UUID operation
@@ -22,27 +24,128 @@ class AnalyseUUID extends Operation {
22
24
 
23
25
  this.name = "Analyse UUID";
24
26
  this.module = "Crypto";
25
- this.description = "Tries to determine information about a given UUID and suggests which version may have been used to generate it";
27
+ this.description = "Operation for extracting metadata and detecting the version of a given UUID.";
26
28
  this.infoURL = "https://wikipedia.org/wiki/Universally_unique_identifier";
27
29
  this.inputType = "string";
28
30
  this.outputType = "string";
29
- this.args = [];
31
+ this.args = [
32
+ {
33
+ name: "Include Metadata",
34
+ type: "boolean",
35
+ value: true
36
+ }
37
+ ];
30
38
  }
31
39
 
32
40
  /**
33
- * @param {string} input
41
+ * @param {string} input - Expects a valid UUID string
34
42
  * @param {Object[]} args
35
43
  * @returns {string}
36
44
  */
37
45
  run(input, args) {
46
+ input = input.trim();
47
+
48
+ let uuidVersion, uuidBytes;
38
49
  try {
39
- const uuidVersion = uuid.version(input);
40
- return "UUID version: " + uuidVersion;
50
+ uuidVersion = uuid.version(input); // Re-using the uuid library to extract version
51
+ uuidBytes = uuid.parse(input); // Re-using the uuid library to parse bytes
41
52
  } catch (error) {
42
53
  throw new OperationError("Invalid UUID");
43
54
  }
44
- }
45
55
 
56
+ const [includeMetadata] = args;
57
+ const dv = new DataView(uuidBytes.buffer, uuidBytes.byteOffset, uuidBytes.byteLength); // Dataview helps handle the multi-byte ints
58
+ const uuidInteger = (dv.getBigUint64(0) << 64n) | dv.getBigUint64(8);
59
+
60
+ const sections = [`Version:\n${uuidVersion}`];
61
+
62
+ if (includeMetadata) {
63
+ const parser = UUID_PARSERS[uuidVersion];
64
+ const decoded = parser?.(uuidBytes, dv);
65
+ sections.push(formatDecoded(decoded));
66
+ }
67
+
68
+ sections.push(`UUID Integer:\n${uuidInteger}`);
69
+
70
+ return sections.filter(Boolean).join("\n\n");
71
+ }
46
72
  }
47
73
 
48
74
  export default AnalyseUUID;
75
+
76
+ /**
77
+ * Metadata can be extracted for versions 1, 6, and 7.
78
+ * Enum-like frozen mapping of UUID version to parser function.
79
+ */
80
+ const UUID_PARSERS = Object.freeze({
81
+ 1: parsev1v6,
82
+ 6: parsev1v6,
83
+ 7: parsev7,
84
+ });
85
+
86
+ /**
87
+ * Versions 1 and 6. Note 6 is a re-order of 1.
88
+ * Version 1 == layout: timeLow(32) | timeMid(16) | timeHi(12)
89
+ * Version 6 == layout: timeHi(32) | timeMid(16) | timeLow(12)
90
+ */
91
+ function parsev1v6(uuidBytes, dv) {
92
+ const isV1 = (uuidBytes[6] >> 4) === 1;
93
+
94
+ const timeStamp =
95
+ isV1 ? (
96
+ (BigInt(dv.getUint16(6) & 0x0fff) << 48n) | // mask off version bits
97
+ (BigInt(dv.getUint16(4)) << 32n) |
98
+ BigInt(dv.getUint32(0))
99
+ ) : (
100
+ (BigInt(dv.getUint32(0)) << 28n) |
101
+ (BigInt(dv.getUint16(4)) << 12n) |
102
+ (BigInt(dv.getUint16(6) & 0x0fff))
103
+ );
104
+
105
+ // Convert to Unix time
106
+ const milliseconds =
107
+ Number(
108
+ (timeStamp - 122192928000000000n) / 10000n
109
+ );
110
+
111
+ return {
112
+ timestamp: milliseconds,
113
+ isoTimestamp: new Date(milliseconds).toISOString(),
114
+ clock: ((uuidBytes[8] & 0x3f) << 8) | uuidBytes[9],
115
+ node: toHex(uuidBytes.slice(10), ":").toUpperCase()
116
+ };
117
+ }
118
+
119
+ /** Version 7 */
120
+ function parsev7(uuidBytes, dv) {
121
+ const milliseconds = Number((BigInt(dv.getUint32(0)) << 16n) | BigInt(dv.getUint16(4)));
122
+
123
+ return {
124
+ timestamp: milliseconds,
125
+ isoTimestamp: new Date(milliseconds).toISOString(),
126
+ randA: ((uuidBytes[6] & 0x0f) << 8) | uuidBytes[7],
127
+ randB: toHex(uuidBytes.slice(8), "").toUpperCase()
128
+ };
129
+ }
130
+
131
+ /**
132
+ * Formats metadata
133
+ *
134
+ * @param {Object|undefined} decoded
135
+ * @returns {string}
136
+ */
137
+ function formatDecoded(decoded) {
138
+ if (!decoded) return "No metadata available. Only versions 1, 6, 7 are supported.";
139
+
140
+ return Object.entries({
141
+ "Timestamp": decoded.timestamp,
142
+ "Timestamp (ISO)": decoded.isoTimestamp,
143
+ "Node": decoded.node,
144
+ "Clock": decoded.clock,
145
+ "Rand A": decoded.randA,
146
+ "Rand B": decoded.randB
147
+ })
148
+ .filter(([, value]) => value !== undefined)
149
+ .map(([label, value]) => `${label}:\n${value}`)
150
+ .join("\n\n");
151
+ }
@@ -5,7 +5,7 @@
5
5
  */
6
6
 
7
7
  import Operation from "../Operation.mjs";
8
- import { search } from "../lib/Extract.mjs";
8
+ import { EMAIL_REGEX, search } from "../lib/Extract.mjs";
9
9
  import { caseInsensitiveSort } from "../lib/Sort.mjs";
10
10
 
11
11
  /**
@@ -50,8 +50,7 @@ class ExtractEmailAddresses extends Operation {
50
50
  */
51
51
  run(input, args) {
52
52
  const [displayTotal, sort, unique] = args,
53
- // email regex from: https://www.regextester.com/98066
54
- regex = /(?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9](?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9-]*[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9])?\.)+[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9](?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9-]*[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\])/ig;
53
+ regex = EMAIL_REGEX;
55
54
 
56
55
  const results = search(
57
56
  input,
@@ -5,7 +5,7 @@
5
5
  */
6
6
 
7
7
  import Operation from "../Operation.mjs";
8
- import punycode from "punycode";
8
+ import punycode from "punycode.js";
9
9
 
10
10
  /**
11
11
  * From Punycode operation
@@ -0,0 +1,128 @@
1
+ /**
2
+ * @author j83305 [awz22@protonmail.com]
3
+ * @copyright Crown Copyright 2020
4
+ * @license Apache-2.0
5
+ */
6
+
7
+ import Operation from "../Operation.mjs";
8
+ import { calculateParityBit, decodeParityBit } from "../lib/ParityBit.mjs";
9
+
10
+ /**
11
+ * Parity Bit operation
12
+ */
13
+ class ParityBit extends Operation {
14
+
15
+ /**
16
+ * ParityBit constructor
17
+ */
18
+ constructor() {
19
+ super();
20
+
21
+ this.name = "Parity Bit";
22
+ this.module = "Default";
23
+ this.description = "A parity bit, or check bit, is the simplest form of error detection. It is a bit which is added to a string of bits and represents if the number of 1's in the binary string is an even number or odd number.<br><br>If a delimiter is specified, the parity bit calculation will be performed on each 'block' of the input data, where the blocks are created by slicing the input at each occurence of the delimiter character";
24
+ this.infoURL = "https://wikipedia.org/wiki/Parity_bit";
25
+ this.inputType = "string";
26
+ this.outputType = "string";
27
+ this.args = [
28
+ {
29
+ name: "Mode",
30
+ type: "option",
31
+ value: [
32
+ "Even Parity",
33
+ "Odd Parity"
34
+ ]
35
+ },
36
+ {
37
+ name: "Postion",
38
+ type: "option",
39
+ value: [
40
+ "Start",
41
+ "End"
42
+ ]
43
+ },
44
+ {
45
+ name: "Encode or Decode",
46
+ type: "option",
47
+ value: [
48
+ "Encode",
49
+ "Decode"
50
+ ]
51
+ },
52
+ {
53
+ name: "Delimiter",
54
+ type: "shortString",
55
+ value: ""
56
+ }
57
+ ];
58
+ }
59
+
60
+ /**
61
+ * @param {string} input
62
+ * @param {Object[]} args
63
+ * @returns {string}
64
+ */
65
+ run(input, args) {
66
+ if (input.length === 0) {
67
+ return input;
68
+ }
69
+ /**
70
+ * determines weather to use the encode or decode method based off args[2]
71
+ * @param input input to be encoded or decoded
72
+ * @param args array
73
+ */
74
+ const method = (input, args) => args[2] === "Encode" ? calculateParityBit(input, args) : decodeParityBit(input, args);
75
+ if (args[3].length > 0) {
76
+ const byteStrings = input.split(args[3]);
77
+ for (let byteStringsArrayIndex = 0; byteStringsArrayIndex < byteStrings.length; byteStringsArrayIndex++) {
78
+ byteStrings[byteStringsArrayIndex] = method(byteStrings[byteStringsArrayIndex], args);
79
+ }
80
+ return byteStrings.join(args[3]);
81
+ }
82
+ return method(input, args);
83
+ }
84
+
85
+ /**
86
+ * Highlight Parity Bit
87
+ *
88
+ * @param {Object[]} pos
89
+ * @param {number} pos[].start
90
+ * @param {number} pos[].end
91
+ * @param {Object[]} args
92
+ * @returns {Object[]} pos
93
+ */
94
+ highlight(pos, args) {
95
+ if (args[3].length === 0) {
96
+ if (args[1] === "Prepend") {
97
+ pos[0].start += 1;
98
+ pos[0].end += 1;
99
+ }
100
+ return pos;
101
+ }
102
+ // need to be able to read input to do the highlighting when there is a delimiter
103
+ }
104
+
105
+ /**
106
+ * Highlight Parity Bit in reverse
107
+ *
108
+ * @param {Object[]} pos
109
+ * @param {number} pos[].start
110
+ * @param {number} pos[].end
111
+ * @param {Object[]} args
112
+ * @returns {Object[]} pos
113
+ */
114
+ highlightReverse(pos, args) {
115
+ if (args[3].length === 0) {
116
+ if (args[1] === "Prepend") {
117
+ if (pos[0].start > 0) {
118
+ pos[0].start -= 1;
119
+ }
120
+ pos[0].end -= 1;
121
+ }
122
+ return pos;
123
+ }
124
+ }
125
+
126
+ }
127
+
128
+ export default ParityBit;
@@ -7,6 +7,7 @@
7
7
  import XRegExp from "xregexp";
8
8
  import Operation from "../Operation.mjs";
9
9
  import Utils from "../Utils.mjs";
10
+ import { EMAIL_REGEX } from "../lib/Extract.mjs";
10
11
  import OperationError from "../errors/OperationError.mjs";
11
12
 
12
13
  /**
@@ -45,7 +46,7 @@ class RegularExpression extends Operation {
45
46
  },
46
47
  {
47
48
  name: "Email address",
48
- value: "(?:[\\u00A0-\\uD7FF\\uE000-\\uFFFFa-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\\.[\\u00A0-\\uD7FF\\uE000-\\uFFFFa-z0-9!#$%&'*+/=?^_`{|}~-]+)*|\"(?:[\\x01-\\x08\\x0b\\x0c\\x0e-\\x1f\\x21\\x23-\\x5b\\x5d-\\x7f]|\\[\\x01-\\x09\\x0b\\x0c\\x0e-\\x7f])*\")@(?:(?:[\\u00A0-\\uD7FF\\uE000-\\uFFFFa-z0-9](?:[\\u00A0-\\uD7FF\\uE000-\\uFFFF-a-z0-9-]*[\\u00A0-\\uD7FF\\uE000-\\uFFFFa-z0-9])?\\.)+[\\u00A0-\\uD7FF\\uE000-\\uFFFFa-z0-9](?:[\\u00A0-\\uD7FF\\uE000-\\uFFFFa-z0-9-]*[\\u00A0-\\uD7FF\\uE000-\\uFFFFa-z0-9])?|\\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\\.){3}\\])"
49
+ value: EMAIL_REGEX.source // We use a different regex library, so just take the source regex string here
49
50
  },
50
51
  {
51
52
  name: "URL",
@@ -35,6 +35,11 @@ class RenderMarkdown extends Operation {
35
35
  name: "Enable syntax highlighting",
36
36
  type: "boolean",
37
37
  value: true
38
+ },
39
+ {
40
+ name: "Open links in new tab.",
41
+ type: "boolean",
42
+ value: false
38
43
  }
39
44
  ];
40
45
  }
@@ -45,7 +50,7 @@ class RenderMarkdown extends Operation {
45
50
  * @returns {html}
46
51
  */
47
52
  run(input, args) {
48
- const [convertLinks, enableHighlighting] = args,
53
+ const [convertLinks, enableHighlighting, openLinksBlank] = args,
49
54
  md = new MarkdownIt({
50
55
  linkify: convertLinks,
51
56
  html: false, // Explicitly disable HTML rendering
@@ -58,12 +63,38 @@ class RenderMarkdown extends Operation {
58
63
 
59
64
  return "";
60
65
  }
61
- }),
62
- rendered = md.render(input);
63
-
66
+ });
67
+ if (openLinksBlank) {
68
+ this.makeLinksOpenInNewTab(md);
69
+ }
70
+ const rendered = md.render(input);
64
71
  return `<div style="font-family: var(--primary-font-family)">${rendered}</div>`;
65
72
  }
66
73
 
74
+ /**
75
+ * Adds target="_blank" to links.
76
+ * @param {MarkdownIt} md
77
+ */
78
+ makeLinksOpenInNewTab(md) {
79
+ // Adapted from: https://github.com/markdown-it/markdown-it/blob/master/docs/architecture.md#renderer
80
+ // Remember old renderer, if overridden, or proxy to default renderer
81
+ const defaultRender = md.renderer.rules.link_open || function(tokens, idx, options, env, self) {
82
+ return self.renderToken(tokens, idx, options);
83
+ };
84
+
85
+ // eslint-disable-next-line camelcase
86
+ md.renderer.rules.link_open = function (tokens, idx, options, env, self) {
87
+ const token = tokens[idx];
88
+ if (token.attrIndex("target") >= 0) {
89
+ // Target attribute already set, do not replace.
90
+ return;
91
+ }
92
+ token.attrPush(["target", "_blank"]); // add new attribute
93
+
94
+ // pass token to default renderer.
95
+ return defaultRender(tokens, idx, options, env, self);
96
+ };
97
+ }
67
98
  }
68
99
 
69
100
  export default RenderMarkdown;
@@ -77,84 +77,84 @@ class ShowBase64Offsets extends Operation {
77
77
  staticSection = offset0.slice(0, -3);
78
78
  offset0 = "<span data-toggle='tooltip' data-placement='top' title='" +
79
79
  Utils.escapeHtml(fromBase64(staticSection, alphabet).slice(0, -2)) + "'>" +
80
- staticSection + "</span>" +
81
- "<span class='hl5'>" + offset0.substr(offset0.length - 3, 1) + "</span>" +
82
- "<span class='hl3'>" + offset0.substr(offset0.length - 2) + "</span>";
80
+ Utils.escapeHtml(staticSection) + "</span>" +
81
+ "<span class='hl5'>" + Utils.escapeHtml(offset0.substr(offset0.length - 3, 1)) + "</span>" +
82
+ "<span class='hl3'>" + Utils.escapeHtml(offset0.substr(offset0.length - 2)) + "</span>";
83
83
  } else if (len0 % 4 === 3) {
84
84
  staticSection = offset0.slice(0, -2);
85
85
  offset0 = "<span data-toggle='tooltip' data-placement='top' title='" +
86
86
  Utils.escapeHtml(fromBase64(staticSection, alphabet).slice(0, -1)) + "'>" +
87
- staticSection + "</span>" +
88
- "<span class='hl5'>" + offset0.substr(offset0.length - 2, 1) + "</span>" +
89
- "<span class='hl3'>" + offset0.substr(offset0.length - 1) + "</span>";
87
+ Utils.escapeHtml(staticSection) + "</span>" +
88
+ "<span class='hl5'>" + Utils.escapeHtml(offset0.substr(offset0.length - 2, 1)) + "</span>" +
89
+ "<span class='hl3'>" + Utils.escapeHtml(offset0.substr(offset0.length - 1)) + "</span>";
90
90
  } else {
91
91
  staticSection = offset0;
92
92
  offset0 = "<span data-toggle='tooltip' data-placement='top' title='" +
93
93
  Utils.escapeHtml(fromBase64(staticSection, alphabet)) + "'>" +
94
- staticSection + "</span>";
94
+ Utils.escapeHtml(staticSection) + "</span>";
95
95
  }
96
96
 
97
97
  if (!showVariable) {
98
- offset0 = staticSection;
98
+ offset0 = Utils.escapeHtml(staticSection);
99
99
  }
100
100
 
101
101
 
102
102
  // Highlight offset 1
103
- padding = "<span class='hl3'>" + offset1.substr(0, 1) + "</span>" +
104
- "<span class='hl5'>" + offset1.substr(1, 1) + "</span>";
103
+ padding = "<span class='hl3'>" + Utils.escapeHtml(offset1.substr(0, 1)) + "</span>" +
104
+ "<span class='hl5'>" + Utils.escapeHtml(offset1.substr(1, 1)) + "</span>";
105
105
  offset1 = offset1.substr(2);
106
106
  if (len1 % 4 === 2) {
107
107
  staticSection = offset1.slice(0, -3);
108
108
  offset1 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
109
109
  Utils.escapeHtml(fromBase64("AA" + staticSection, alphabet).slice(1, -2)) + "'>" +
110
- staticSection + "</span>" +
111
- "<span class='hl5'>" + offset1.substr(offset1.length - 3, 1) + "</span>" +
112
- "<span class='hl3'>" + offset1.substr(offset1.length - 2) + "</span>";
110
+ Utils.escapeHtml(staticSection) + "</span>" +
111
+ "<span class='hl5'>" + Utils.escapeHtml(offset1.substr(offset1.length - 3, 1)) + "</span>" +
112
+ "<span class='hl3'>" + Utils.escapeHtml(offset1.substr(offset1.length - 2)) + "</span>";
113
113
  } else if (len1 % 4 === 3) {
114
114
  staticSection = offset1.slice(0, -2);
115
115
  offset1 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
116
116
  Utils.escapeHtml(fromBase64("AA" + staticSection, alphabet).slice(1, -1)) + "'>" +
117
- staticSection + "</span>" +
118
- "<span class='hl5'>" + offset1.substr(offset1.length - 2, 1) + "</span>" +
119
- "<span class='hl3'>" + offset1.substr(offset1.length - 1) + "</span>";
117
+ Utils.escapeHtml(staticSection) + "</span>" +
118
+ "<span class='hl5'>" + Utils.escapeHtml(offset1.substr(offset1.length - 2, 1)) + "</span>" +
119
+ "<span class='hl3'>" + Utils.escapeHtml(offset1.substr(offset1.length - 1)) + "</span>";
120
120
  } else {
121
121
  staticSection = offset1;
122
122
  offset1 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
123
123
  Utils.escapeHtml(fromBase64("AA" + staticSection, alphabet).slice(1)) + "'>" +
124
- staticSection + "</span>";
124
+ Utils.escapeHtml(staticSection) + "</span>";
125
125
  }
126
126
 
127
127
  if (!showVariable) {
128
- offset1 = staticSection;
128
+ offset1 = Utils.escapeHtml(staticSection);
129
129
  }
130
130
 
131
131
  // Highlight offset 2
132
- padding = "<span class='hl3'>" + offset2.substr(0, 2) + "</span>" +
133
- "<span class='hl5'>" + offset2.substr(2, 1) + "</span>";
132
+ padding = "<span class='hl3'>" + Utils.escapeHtml(offset2.substr(0, 2)) + "</span>" +
133
+ "<span class='hl5'>" + Utils.escapeHtml(offset2.substr(2, 1)) + "</span>";
134
134
  offset2 = offset2.substr(3);
135
135
  if (len2 % 4 === 2) {
136
136
  staticSection = offset2.slice(0, -3);
137
137
  offset2 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
138
138
  Utils.escapeHtml(fromBase64("AAA" + staticSection, alphabet).slice(2, -2)) + "'>" +
139
- staticSection + "</span>" +
140
- "<span class='hl5'>" + offset2.substr(offset2.length - 3, 1) + "</span>" +
141
- "<span class='hl3'>" + offset2.substr(offset2.length - 2) + "</span>";
139
+ Utils.escapeHtml(staticSection) + "</span>" +
140
+ "<span class='hl5'>" + Utils.escapeHtml(offset2.substr(offset2.length - 3, 1)) + "</span>" +
141
+ "<span class='hl3'>" + Utils.escapeHtml(offset2.substr(offset2.length - 2)) + "</span>";
142
142
  } else if (len2 % 4 === 3) {
143
143
  staticSection = offset2.slice(0, -2);
144
144
  offset2 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
145
145
  Utils.escapeHtml(fromBase64("AAA" + staticSection, alphabet).slice(2, -2)) + "'>" +
146
- staticSection + "</span>" +
147
- "<span class='hl5'>" + offset2.substr(offset2.length - 2, 1) + "</span>" +
148
- "<span class='hl3'>" + offset2.substr(offset2.length - 1) + "</span>";
146
+ Utils.escapeHtml(staticSection) + "</span>" +
147
+ "<span class='hl5'>" + Utils.escapeHtml(offset2.substr(offset2.length - 2, 1)) + "</span>" +
148
+ "<span class='hl3'>" + Utils.escapeHtml(offset2.substr(offset2.length - 1)) + "</span>";
149
149
  } else {
150
150
  staticSection = offset2;
151
151
  offset2 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
152
152
  Utils.escapeHtml(fromBase64("AAA" + staticSection, alphabet).slice(2)) + "'>" +
153
- staticSection + "</span>";
153
+ Utils.escapeHtml(staticSection) + "</span>";
154
154
  }
155
155
 
156
156
  if (!showVariable) {
157
- offset2 = staticSection;
157
+ offset2 = Utils.escapeHtml(staticSection);
158
158
  }
159
159
 
160
160
  return (showVariable ? "Characters highlighted in <span class='hl5'>green</span> could change if the input is surrounded by more data." +
@@ -5,7 +5,7 @@
5
5
  */
6
6
 
7
7
  import Operation from "../Operation.mjs";
8
- import punycode from "punycode";
8
+ import punycode from "punycode.js";
9
9
 
10
10
  /**
11
11
  * To Punycode operation
@@ -288,6 +288,7 @@ import PHPDeserialize from "./PHPDeserialize.mjs";
288
288
  import PHPSerialize from "./PHPSerialize.mjs";
289
289
  import PLISTViewer from "./PLISTViewer.mjs";
290
290
  import PadLines from "./PadLines.mjs";
291
+ import ParityBit from "./ParityBit.mjs";
291
292
  import ParseASN1HexString from "./ParseASN1HexString.mjs";
292
293
  import ParseCSR from "./ParseCSR.mjs";
293
294
  import ParseColourCode from "./ParseColourCode.mjs";
@@ -765,6 +766,7 @@ export {
765
766
  PHPSerialize,
766
767
  PLISTViewer,
767
768
  PadLines,
769
+ ParityBit,
768
770
  ParseASN1HexString,
769
771
  ParseCSR,
770
772
  ParseColourCode,
@@ -88,16 +88,17 @@ class NodeRecipe {
88
88
  * @param {NodeDish} dish
89
89
  * @returns {NodeDish}
90
90
  */
91
- execute(dish) {
92
- return this.opList.reduce((prev, curr) => {
93
- // CASE where opList item is op and args
91
+ async execute(dish) {
92
+ let prev = dish;
93
+ for (const curr of this.opList) {
94
94
  if (Object.prototype.hasOwnProperty.call(curr, "op") &&
95
95
  Object.prototype.hasOwnProperty.call(curr, "args")) {
96
- return curr.op(prev, curr.args);
96
+ prev = await curr.op(prev, curr.args);
97
+ } else {
98
+ prev = await curr(prev);
97
99
  }
98
- // CASE opList item is just op.
99
- return curr(prev);
100
- }, dish);
100
+ }
101
+ return prev;
101
102
  }
102
103
  }
103
104
 
package/src/node/api.mjs CHANGED
@@ -10,7 +10,7 @@
10
10
 
11
11
  import NodeDish from "./NodeDish.mjs";
12
12
  import NodeRecipe from "./NodeRecipe.mjs";
13
- import OperationConfig from "../core/config/OperationConfig.json" assert {type: "json"};
13
+ import OperationConfig from "../core/config/OperationConfig.json" with { type: "json" };
14
14
  import { sanitise, removeSubheadingsFromArray, sentenceToCamelCase } from "./apiUtils.mjs";
15
15
  import ExcludedOperationError from "../core/errors/ExcludedOperationError.mjs";
16
16
 
@@ -324,10 +324,10 @@ export function help(input) {
324
324
  * @returns {NodeDish} of the result
325
325
  * @throws {TypeError} if invalid recipe given.
326
326
  */
327
- export function bake(input, recipeConfig) {
328
- const recipe = new NodeRecipe(recipeConfig);
327
+ export async function bake(input, recipeConfig) {
328
+ const recipe = new NodeRecipe(recipeConfig);
329
329
  const dish = ensureIsDish(input);
330
- return recipe.execute(dish);
330
+ return await recipe.execute(dish);
331
331
  }
332
332
 
333
333
 
@@ -289,6 +289,7 @@ import {
289
289
  PHPSerialize as core_PHPSerialize,
290
290
  PLISTViewer as core_PLISTViewer,
291
291
  PadLines as core_PadLines,
292
+ ParityBit as core_ParityBit,
292
293
  ParseASN1HexString as core_ParseASN1HexString,
293
294
  ParseCSR as core_ParseCSR,
294
295
  ParseColourCode as core_ParseColourCode,
@@ -766,6 +767,7 @@ function generateChef() {
766
767
  "PHPSerialize": _wrap(core_PHPSerialize),
767
768
  "PLISTViewer": _wrap(core_PLISTViewer),
768
769
  "padLines": _wrap(core_PadLines),
770
+ "parityBit": _wrap(core_ParityBit),
769
771
  "parseASN1HexString": _wrap(core_ParseASN1HexString),
770
772
  "parseCSR": _wrap(core_ParseCSR),
771
773
  "parseColourCode": _wrap(core_ParseColourCode),
@@ -1260,6 +1262,7 @@ const PHPDeserialize = chef.PHPDeserialize;
1260
1262
  const PHPSerialize = chef.PHPSerialize;
1261
1263
  const PLISTViewer = chef.PLISTViewer;
1262
1264
  const padLines = chef.padLines;
1265
+ const parityBit = chef.parityBit;
1263
1266
  const parseASN1HexString = chef.parseASN1HexString;
1264
1267
  const parseCSR = chef.parseCSR;
1265
1268
  const parseColourCode = chef.parseColourCode;
@@ -1739,6 +1742,7 @@ const operations = [
1739
1742
  PHPSerialize,
1740
1743
  PLISTViewer,
1741
1744
  padLines,
1745
+ parityBit,
1742
1746
  parseASN1HexString,
1743
1747
  parseCSR,
1744
1748
  parseColourCode,
@@ -2222,6 +2226,7 @@ export {
2222
2226
  PHPSerialize,
2223
2227
  PLISTViewer,
2224
2228
  padLines,
2229
+ parityBit,
2225
2230
  parseASN1HexString,
2226
2231
  parseCSR,
2227
2232
  parseColourCode,