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
@@ -144,6 +144,11 @@
144
144
  "Base64"
145
145
  ]
146
146
  },
147
+ {
148
+ "name": "IV Length",
149
+ "type": "number",
150
+ "value": 16
151
+ },
147
152
  {
148
153
  "name": "Mode",
149
154
  "type": "argSelector",
@@ -151,57 +156,57 @@
151
156
  {
152
157
  "name": "CBC",
153
158
  "off": [
154
- 5,
155
- 6
159
+ 6,
160
+ 7
156
161
  ]
157
162
  },
158
163
  {
159
164
  "name": "CFB",
160
165
  "off": [
161
- 5,
162
- 6
166
+ 6,
167
+ 7
163
168
  ]
164
169
  },
165
170
  {
166
171
  "name": "OFB",
167
172
  "off": [
168
- 5,
169
- 6
173
+ 6,
174
+ 7
170
175
  ]
171
176
  },
172
177
  {
173
178
  "name": "CTR",
174
179
  "off": [
175
- 5,
176
- 6
180
+ 6,
181
+ 7
177
182
  ]
178
183
  },
179
184
  {
180
185
  "name": "GCM",
181
186
  "on": [
182
- 5,
183
- 6
187
+ 6,
188
+ 7
184
189
  ]
185
190
  },
186
191
  {
187
192
  "name": "ECB",
188
193
  "off": [
189
- 5,
190
- 6
194
+ 6,
195
+ 7
191
196
  ]
192
197
  },
193
198
  {
194
199
  "name": "CBC/NoPadding",
195
200
  "off": [
196
- 5,
197
- 6
201
+ 6,
202
+ 7
198
203
  ]
199
204
  },
200
205
  {
201
206
  "name": "ECB/NoPadding",
202
207
  "off": [
203
- 5,
204
- 6
208
+ 6,
209
+ 7
205
210
  ]
206
211
  }
207
212
  ]
@@ -243,6 +248,39 @@
243
248
  "Latin1",
244
249
  "Base64"
245
250
  ]
251
+ },
252
+ {
253
+ "name": "IV from input",
254
+ "type": "argSelector",
255
+ "value": [
256
+ {
257
+ "name": "Off",
258
+ "on": [
259
+ 1
260
+ ],
261
+ "off": [
262
+ 2
263
+ ]
264
+ },
265
+ {
266
+ "name": "From start",
267
+ "on": [
268
+ 2
269
+ ],
270
+ "off": [
271
+ 1
272
+ ]
273
+ },
274
+ {
275
+ "name": "From end",
276
+ "on": [
277
+ 2
278
+ ],
279
+ "off": [
280
+ 1
281
+ ]
282
+ }
283
+ ]
246
284
  }
247
285
  ]
248
286
  },
@@ -357,6 +395,15 @@
357
395
  "Latin1",
358
396
  "Base64"
359
397
  ]
398
+ },
399
+ {
400
+ "name": "Include IV in output",
401
+ "type": "option",
402
+ "value": [
403
+ "Off",
404
+ "Prepend",
405
+ "Append"
406
+ ]
360
407
  }
361
408
  ]
362
409
  },
@@ -7552,6 +7599,26 @@
7552
7599
  }
7553
7600
  ]
7554
7601
  },
7602
+ "Escape Smart Characters": {
7603
+ "module": "Default",
7604
+ "description": "Converts smart (typographic) Unicode characters — e.g. smart quotes, em/en dashes, ellipses, ©, ®, ™, arrows — into their plain ASCII equivalents.<br><br>Characters with no ASCII mapping (e.g. <code>☣</code>) are handled according to the 'Unmappable characters' option.<br><br>e.g. <code>“Hello” — world…</code> becomes <code>\"Hello\" -- world...</code>",
7605
+ "infoURL": "",
7606
+ "inputType": "string",
7607
+ "outputType": "string",
7608
+ "flowControl": false,
7609
+ "manualBake": false,
7610
+ "args": [
7611
+ {
7612
+ "name": "Unmappable characters",
7613
+ "type": "option",
7614
+ "value": [
7615
+ "Include",
7616
+ "Remove",
7617
+ "Replace with '.'"
7618
+ ]
7619
+ }
7620
+ ]
7621
+ },
7555
7622
  "Escape string": {
7556
7623
  "module": "Default",
7557
7624
  "description": "Escapes special characters in a string so that they do not cause conflicts. For example, <code>Don't stop me now</code> becomes <code>Don\\'t stop me now</code>.<br><br>Supports the following escape sequences:<ul><li><code>\\n</code> (Line feed/newline)</li><li><code>\\r</code> (Carriage return)</li><li><code>\\t</code> (Horizontal tab)</li><li><code>\\b</code> (Backspace)</li><li><code>\\f</code> (Form feed)</li><li><code>\\xnn</code> (Hex, where n is 0-f)</li><li><code>\\\\</code> (Backslash)</li><li><code>\\'</code> (Single quote)</li><li><code>\\&quot;</code> (Double quote)</li><li><code>\\unnnn</code> (Unicode character)</li><li><code>\\u{nnnnnn}</code> (Unicode code point)</li></ul>",
@@ -13143,6 +13210,27 @@
13143
13210
  }
13144
13211
  ]
13145
13212
  },
13213
+ "PGP Sign": {
13214
+ "module": "PGP",
13215
+ "description": "Input: the message you want to sign\n<br><br>\nArguments: the ASCII-armoured PGP private key of the sender.\n<br><br>\nPretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.\n<br><br>\nThis function uses the Keybase implementation of PGP.",
13216
+ "infoURL": "https://wikipedia.org/wiki/Pretty_Good_Privacy",
13217
+ "inputType": "string",
13218
+ "outputType": "string",
13219
+ "flowControl": false,
13220
+ "manualBake": false,
13221
+ "args": [
13222
+ {
13223
+ "name": "Private key of signer",
13224
+ "type": "text",
13225
+ "value": ""
13226
+ },
13227
+ {
13228
+ "name": "Private key passphrase (optional)",
13229
+ "type": "string",
13230
+ "value": ""
13231
+ }
13232
+ ]
13233
+ },
13146
13234
  "PGP Verify": {
13147
13235
  "module": "PGP",
13148
13236
  "description": "Input: the ASCII-armoured encrypted PGP message you want to verify.\n<br><br>\nArgument: the ASCII-armoured PGP public key of the signer\n<br><br>\nThis operation uses PGP to decrypt a clearsigned message.\n<br><br>\nPretty Good Privacy is an encryption standard (OpenPGP) used for encrypting, decrypting, and signing messages.\n<br><br>\nThis function uses the Keybase implementation of PGP.",
@@ -13226,7 +13314,7 @@
13226
13314
  },
13227
13315
  "Parity Bit": {
13228
13316
  "module": "Default",
13229
- "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",
13317
+ "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 occurrence of the delimiter character",
13230
13318
  "infoURL": "https://wikipedia.org/wiki/Parity_bit",
13231
13319
  "inputType": "string",
13232
13320
  "outputType": "string",
@@ -14918,6 +15006,16 @@
14918
15006
  }
14919
15007
  ]
14920
15008
  },
15009
+ "ROR13": {
15010
+ "module": "Default",
15011
+ "description": "Computes a ROR13 hash used in API hashing techniques.",
15012
+ "infoURL": "",
15013
+ "inputType": "byteArray",
15014
+ "outputType": "string",
15015
+ "flowControl": false,
15016
+ "manualBake": false,
15017
+ "args": []
15018
+ },
14921
15019
  "ROT13": {
14922
15020
  "module": "Default",
14923
15021
  "description": "A simple caesar substitution cipher which rotates alphabet characters by the specified amount (default 13).",
@@ -15574,6 +15672,16 @@
15574
15672
  }
15575
15673
  ]
15576
15674
  },
15675
+ "Remove ANSI Escape Codes": {
15676
+ "module": "Default",
15677
+ "description": "Removes ANSI Escape Codes.",
15678
+ "infoURL": "https://wikipedia.org/wiki/ANSI_escape_code",
15679
+ "inputType": "string",
15680
+ "outputType": "string",
15681
+ "flowControl": false,
15682
+ "manualBake": false,
15683
+ "args": []
15684
+ },
15577
15685
  "Remove Diacritics": {
15578
15686
  "module": "Default",
15579
15687
  "description": "Replaces accented characters with their latin character equivalent. Accented characters are made up of Unicode combining characters, so unicode text formatting such as strikethroughs and underlines will also be removed.",
@@ -15928,7 +16036,7 @@
15928
16036
  },
15929
16037
  "SHA2": {
15930
16038
  "module": "Crypto",
15931
- "description": "The SHA-2 (Secure Hash Algorithm 2) hash functions were designed by the NSA. SHA-2 includes significant changes from its predecessor, SHA-1. The SHA-2 family consists of hash functions with digests (hash values) that are 224, 256, 384 or 512 bits: SHA224, SHA256, SHA384, SHA512.<br><br><ul><li>SHA-512 operates on 64-bit words.</li><li>SHA-256 operates on 32-bit words.</li><li>SHA-384 is largely identical to SHA-512 but is truncated to 384 bytes.</li><li>SHA-224 is largely identical to SHA-256 but is truncated to 224 bytes.</li><li>SHA-512/224 and SHA-512/256 are truncated versions of SHA-512, but the initial values are generated using the method described in Federal Information Processing Standards (FIPS) PUB 180-4.</li></ul> The message digest algorithm for SHA256 variants consists, by default, of 64 rounds, and for SHA512 variants, it is, by default, 160.",
16039
+ "description": "The SHA-2 (Secure Hash Algorithm 2) hash functions were designed by the NSA. SHA-2 includes significant changes from its predecessor, SHA-1. The SHA-2 family consists of hash functions with digests (hash values) that are 224, 256, 384 or 512 bits: SHA224, SHA256, SHA384, SHA512.<br><br><ul><li>SHA-512 operates on 64-bit words.</li><li>SHA-256 operates on 32-bit words.</li><li>SHA-384 is largely identical to SHA-512 but is truncated to 384 bits.</li><li>SHA-224 is largely identical to SHA-256 but is truncated to 224 bits.</li><li>SHA-512/224 and SHA-512/256 are truncated versions of SHA-512, but the initial values are generated using the method described in Federal Information Processing Standards (FIPS) PUB 180-4.</li></ul> The message digest algorithm for SHA256 variants consists, by default, of 64 rounds, and for SHA512 variants, it is, by default, 160.",
15932
16040
  "infoURL": "https://wikipedia.org/wiki/SHA-2",
15933
16041
  "inputType": "ArrayBuffer",
15934
16042
  "outputType": "string",
@@ -19288,7 +19396,8 @@
19288
19396
  "name": "Width",
19289
19397
  "type": "number",
19290
19398
  "value": 16,
19291
- "min": 1
19399
+ "min": 1,
19400
+ "max": 65536
19292
19401
  },
19293
19402
  {
19294
19403
  "name": "Upper case hex",
@@ -21895,6 +22004,22 @@
21895
22004
  }
21896
22005
  ]
21897
22006
  },
22007
+ "Wrap": {
22008
+ "module": "Default",
22009
+ "description": "Wraps the input text at a specified number of characters per line.",
22010
+ "infoURL": null,
22011
+ "inputType": "string",
22012
+ "outputType": "string",
22013
+ "flowControl": false,
22014
+ "manualBake": false,
22015
+ "args": [
22016
+ {
22017
+ "name": "Line Width",
22018
+ "type": "number",
22019
+ "value": 64
22020
+ }
22021
+ ]
22022
+ },
21898
22023
  "XKCD Random Number": {
21899
22024
  "module": "Default",
21900
22025
  "description": "RFC 1149.5 specifies 4 as the standard IEEE-vetted random number.",
@@ -41,6 +41,7 @@ import DropBytes from "../../operations/DropBytes.mjs";
41
41
  import DropNthBytes from "../../operations/DropNthBytes.mjs";
42
42
  import ELFInfo from "../../operations/ELFInfo.mjs";
43
43
  import EncodeNetBIOSName from "../../operations/EncodeNetBIOSName.mjs";
44
+ import EscapeSmartCharacters from "../../operations/EscapeSmartCharacters.mjs";
44
45
  import EscapeString from "../../operations/EscapeString.mjs";
45
46
  import EscapeUnicodeCharacters from "../../operations/EscapeUnicodeCharacters.mjs";
46
47
  import ExpandAlphabetRange from "../../operations/ExpandAlphabetRange.mjs";
@@ -131,11 +132,13 @@ import ParseUNIXFilePermissions from "../../operations/ParseUNIXFilePermissions.
131
132
  import PlayMedia from "../../operations/PlayMedia.mjs";
132
133
  import PowerSet from "../../operations/PowerSet.mjs";
133
134
  import RAKE from "../../operations/RAKE.mjs";
135
+ import ROR13 from "../../operations/ROR13.mjs";
134
136
  import ROT13 from "../../operations/ROT13.mjs";
135
137
  import ROT13BruteForce from "../../operations/ROT13BruteForce.mjs";
136
138
  import ROT47 from "../../operations/ROT47.mjs";
137
139
  import ROT47BruteForce from "../../operations/ROT47BruteForce.mjs";
138
140
  import ROT8000 from "../../operations/ROT8000.mjs";
141
+ import RemoveANSIEscapeCodes from "../../operations/RemoveANSIEscapeCodes.mjs";
139
142
  import RemoveDiacritics from "../../operations/RemoveDiacritics.mjs";
140
143
  import RemoveLineNumbers from "../../operations/RemoveLineNumbers.mjs";
141
144
  import RemoveNullBytes from "../../operations/RemoveNullBytes.mjs";
@@ -207,6 +210,7 @@ import Unique from "../../operations/Unique.mjs";
207
210
  import VarIntDecode from "../../operations/VarIntDecode.mjs";
208
211
  import VarIntEncode from "../../operations/VarIntEncode.mjs";
209
212
  import WindowsFiletimeToUNIXTimestamp from "../../operations/WindowsFiletimeToUNIXTimestamp.mjs";
213
+ import Wrap from "../../operations/Wrap.mjs";
210
214
  import XKCDRandomNumber from "../../operations/XKCDRandomNumber.mjs";
211
215
  import XOR from "../../operations/XOR.mjs";
212
216
  import XORBruteForce from "../../operations/XORBruteForce.mjs";
@@ -251,6 +255,7 @@ OpModules.Default = {
251
255
  "Drop nth bytes": DropNthBytes,
252
256
  "ELF Info": ELFInfo,
253
257
  "Encode NetBIOS Name": EncodeNetBIOSName,
258
+ "Escape Smart Characters": EscapeSmartCharacters,
254
259
  "Escape string": EscapeString,
255
260
  "Escape Unicode Characters": EscapeUnicodeCharacters,
256
261
  "Expand alphabet range": ExpandAlphabetRange,
@@ -341,11 +346,13 @@ OpModules.Default = {
341
346
  "Play Media": PlayMedia,
342
347
  "Power Set": PowerSet,
343
348
  "RAKE": RAKE,
349
+ "ROR13": ROR13,
344
350
  "ROT13": ROT13,
345
351
  "ROT13 Brute Force": ROT13BruteForce,
346
352
  "ROT47": ROT47,
347
353
  "ROT47 Brute Force": ROT47BruteForce,
348
354
  "ROT8000": ROT8000,
355
+ "Remove ANSI Escape Codes": RemoveANSIEscapeCodes,
349
356
  "Remove Diacritics": RemoveDiacritics,
350
357
  "Remove line numbers": RemoveLineNumbers,
351
358
  "Remove null bytes": RemoveNullBytes,
@@ -417,6 +424,7 @@ OpModules.Default = {
417
424
  "VarInt Decode": VarIntDecode,
418
425
  "VarInt Encode": VarIntEncode,
419
426
  "Windows Filetime to UNIX Timestamp": WindowsFiletimeToUNIXTimestamp,
427
+ "Wrap": Wrap,
420
428
  "XKCD Random Number": XKCDRandomNumber,
421
429
  "XOR": XOR,
422
430
  "XOR Brute Force": XORBruteForce,
@@ -10,6 +10,7 @@ import PGPDecrypt from "../../operations/PGPDecrypt.mjs";
10
10
  import PGPDecryptAndVerify from "../../operations/PGPDecryptAndVerify.mjs";
11
11
  import PGPEncrypt from "../../operations/PGPEncrypt.mjs";
12
12
  import PGPEncryptAndSign from "../../operations/PGPEncryptAndSign.mjs";
13
+ import PGPSign from "../../operations/PGPSign.mjs";
13
14
  import PGPVerify from "../../operations/PGPVerify.mjs";
14
15
 
15
16
  const OpModules = typeof self === "undefined" ? {} : self.OpModules || {};
@@ -20,6 +21,7 @@ OpModules.PGP = {
20
21
  "PGP Decrypt and Verify": PGPDecryptAndVerify,
21
22
  "PGP Encrypt": PGPEncrypt,
22
23
  "PGP Encrypt and Sign": PGPEncryptAndSign,
24
+ "PGP Sign": PGPSign,
23
25
  "PGP Verify": PGPVerify,
24
26
  };
25
27
 
@@ -58,3 +58,66 @@ fs.writeFileSync(
58
58
  code
59
59
  );
60
60
  console.log("Written operation index.");
61
+
62
+ // find all test files
63
+ const testsDir = path.join(process.cwd() + "/tests/operations/tests/");
64
+ const testObjs = [];
65
+ fs.readdirSync(testsDir).forEach(file => {
66
+ if (!file.endsWith(".mjs")) return;
67
+ testObjs.push(file.split(".mjs")[0]);
68
+ });
69
+
70
+ // Construct test index file
71
+ code = `/**
72
+ * THIS FILE IS AUTOMATICALLY GENERATED BY src/core/config/scripts/generateOpsIndex.mjs
73
+ *
74
+ * @author john [john19696@protonmail.com]
75
+ * @author tlwr [toby@toby.codes]
76
+ * @author n1474335 [n1474335@gmail.com]
77
+ * @copyright Crown Copyright ${new Date().getUTCFullYear()}
78
+ * @license Apache-2.0
79
+ */
80
+
81
+ import {
82
+ setLongTestFailure,
83
+ logTestReport,
84
+ } from "../lib/utils.mjs";
85
+
86
+ import "../lib/wasmFetchPolyfill.mjs";
87
+
88
+ import TestRegister from "../lib/TestRegister.mjs";
89
+ `;
90
+
91
+ testObjs.forEach(obj => {
92
+ if (obj !== "SplitColourChannels")
93
+ code += `import "./tests/${obj}.mjs";\n`;
94
+ else
95
+ code += `// Cannot test operations that use the File type yet
96
+ // import "./tests/SplitColourChannels.mjs";\n`;
97
+ });
98
+
99
+ code += `
100
+
101
+ const testStatus = {
102
+ allTestsPassing: true,
103
+ counts: {
104
+ total: 0,
105
+ }
106
+ };
107
+
108
+ setLongTestFailure();
109
+
110
+ const logOpsTestReport = logTestReport.bind(null, testStatus);
111
+
112
+ (async function() {
113
+ const results = await TestRegister.runTests();
114
+ logOpsTestReport(results);
115
+ })();
116
+ `;
117
+
118
+ // Write tests file
119
+ fs.writeFileSync(
120
+ path.join(testsDir, "../index.mjs"),
121
+ code
122
+ );
123
+ console.log("Written operation tests index.");
@@ -23,7 +23,7 @@ if (!fs.existsSync(dir)) {
23
23
  console.log("Example> node --experimental-modules src/core/config/scripts/newOperation.mjs");
24
24
  process.exit(1);
25
25
  }
26
-
26
+ const testDir = path.join(process.cwd() + "/tests/operations/tests/");
27
27
  const ioTypes = ["string", "byteArray", "number", "html", "ArrayBuffer", "BigNumber", "JSON", "File", "List<File>"];
28
28
 
29
29
  const schema = {
@@ -123,6 +123,30 @@ prompt.get(schema, (err, result) => {
123
123
  return txt.charAt(0).toUpperCase() + txt.substr(1);
124
124
  }).replace(/[\s-()./]/g, "");
125
125
 
126
+ const testTemplate = `/**
127
+ * ${moduleName} tests
128
+ *
129
+ * @author ${result.authorName} [${result.authorEmail}]
130
+ * @copyright Crown Copyright ${(new Date()).getFullYear()}
131
+ * @license Apache-2.0
132
+ */
133
+
134
+ import TestRegister from "../../lib/TestRegister.mjs";
135
+
136
+ TestRegister.addTests([
137
+ {
138
+ name: "${result.opName}: test",
139
+ input: "Example input",
140
+ expectedOutput: "Expected output",
141
+ recipeConfig: [
142
+ {
143
+ op: "${result.opName}",
144
+ args: [],
145
+ },
146
+ ],
147
+ },
148
+ ]);
149
+ `;
126
150
 
127
151
  const template = `/**
128
152
  * @author ${result.authorName} [${result.authorEmail}]
@@ -218,13 +242,16 @@ export default ${moduleName};
218
242
  }
219
243
  fs.writeFileSync(filename, template);
220
244
 
245
+ const testFilename = path.join(testDir, `./${moduleName}.mjs`);
246
+ fs.writeFileSync(testFilename, testTemplate);
247
+
221
248
  console.log(`\nOperation template written to ${colors.green(filename)}`);
249
+ console.log(`\nOperation test template written to ${colors.green(testFilename)}`);
222
250
  console.log(`\nNext steps:
223
251
  1. Add your operation to ${colors.green("src/core/config/Categories.json")}
224
- 2. Write your operation code.
225
- 3. Write tests in ${colors.green("tests/operations/tests/")}
252
+ 2. Write your operation code in ${colors.green(filename)}
253
+ 3. Write your operation test code in ${colors.green(testFilename)}
226
254
  4. Run ${colors.cyan("npm run lint")} and ${colors.cyan("npm run test")}
227
255
  5. Submit a Pull Request to get your operation added to the official CyberChef repository.`);
228
256
 
229
257
  });
230
-
@@ -11,7 +11,7 @@
11
11
  class DishType {
12
12
 
13
13
  /**
14
- * Warn translations dont work without value from bind
14
+ * Warn translations don't work without value from bind
15
15
  */
16
16
  static checkForValue(value) {
17
17
  if (value === undefined) {
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Custom error type for handling operation that isnt included in node.js API
2
+ * Custom error type for handling operation that isn't included in node.js API
3
3
  *
4
4
  * @author d98762625 [d98762625@gmail.com]
5
5
  * @copyright Crown Copyright 2018
@@ -153,7 +153,7 @@ export function getSeriesValues(input, recordDelimiter, fieldDelimiter, columnHe
153
153
  );
154
154
 
155
155
  let xValues = new Set();
156
- const series = {};
156
+ const series = Object.create(null);
157
157
 
158
158
  values.forEach(row => {
159
159
  const serie = row[0],
@@ -163,14 +163,14 @@ export function getSeriesValues(input, recordDelimiter, fieldDelimiter, columnHe
163
163
  if (Number.isNaN(val)) throw new OperationError("Values must be numbers in base 10.");
164
164
 
165
165
  xValues.add(xVal);
166
- if (typeof series[serie] === "undefined") series[serie] = {};
166
+ if (typeof series[serie] === "undefined") series[serie] = Object.create(null);
167
167
  series[serie][xVal] = val;
168
168
  });
169
169
 
170
170
  xValues = new Array(...xValues);
171
171
 
172
172
  const seriesList = [];
173
- for (const seriesName in series) {
173
+ for (const seriesName of Object.keys(series)) {
174
174
  const serie = series[seriesName];
175
175
  seriesList.push({name: seriesName, data: serie});
176
176
  }
@@ -8,6 +8,7 @@
8
8
 
9
9
  import BigNumber from "bignumber.js";
10
10
  import {toHexFast} from "../lib/Hex.mjs";
11
+ import Utils from "../Utils.mjs";
11
12
 
12
13
  /**
13
14
  * Recursively displays a JSON object as an HTML table
@@ -25,15 +26,16 @@ export function objToTable(obj, nested=false) {
25
26
  <th>Value</th>
26
27
  </tr>`;
27
28
 
28
- for (const key in obj) {
29
- if (typeof obj[key] === "function")
29
+ for (const key of Object.keys(obj)) {
30
+ const value = obj[key];
31
+ if (typeof value === "function")
30
32
  continue;
31
33
 
32
- html += `<tr><td style='word-wrap: break-word'>${key}</td>`;
33
- if (typeof obj[key] === "object")
34
- html += `<td style='padding: 0'>${objToTable(obj[key], true)}</td>`;
34
+ html += `<tr><td style='word-wrap: break-word'>${Utils.escapeHtml(String(key))}</td>`;
35
+ if (value !== null && typeof value === "object")
36
+ html += `<td style='padding: 0'>${objToTable(value, true)}</td>`;
35
37
  else
36
- html += `<td>${obj[key]}</td>`;
38
+ html += `<td>${Utils.escapeHtml(String(value))}</td>`;
37
39
  html += "</tr>";
38
40
  }
39
41
  html += "</table>";