cyberchef 10.22.1 → 10.24.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 (118) hide show
  1. package/CHANGELOG.md +182 -0
  2. package/CONTRIBUTING.md +40 -0
  3. package/Dockerfile +2 -0
  4. package/Gruntfile.js +2 -28
  5. package/README.md +1 -1
  6. package/babel.config.js +0 -6
  7. package/package.json +64 -63
  8. package/src/core/Chef.mjs +8 -1
  9. package/src/core/Ingredient.mjs +5 -2
  10. package/src/core/Operation.mjs +6 -1
  11. package/src/core/Recipe.mjs +10 -5
  12. package/src/core/config/Categories.json +20 -4
  13. package/src/core/config/OperationConfig.json +550 -26
  14. package/src/core/config/modules/Ciphers.mjs +6 -0
  15. package/src/core/config/modules/Crypto.mjs +6 -0
  16. package/src/core/config/modules/Default.mjs +8 -0
  17. package/src/core/config/modules/Shellcode.mjs +2 -0
  18. package/src/core/config/scripts/fixCryptoApiImports.mjs +54 -0
  19. package/src/core/config/scripts/fixSnackBarMarkup.mjs +28 -0
  20. package/src/core/lib/AudioBytes.mjs +103 -0
  21. package/src/core/lib/AudioMetaSchema.mjs +82 -0
  22. package/src/core/lib/AudioParsers.mjs +630 -0
  23. package/src/core/lib/BigIntUtils.mjs +73 -0
  24. package/src/core/lib/Extract.mjs +5 -0
  25. package/src/core/lib/Modhex.mjs +2 -0
  26. package/src/core/lib/ParityBit.mjs +50 -0
  27. package/src/core/lib/QRCode.mjs +30 -10
  28. package/src/core/lib/RC6.mjs +625 -0
  29. package/src/core/operations/A1Z26CipherDecode.mjs +1 -1
  30. package/src/core/operations/AddTextToImage.mjs +116 -64
  31. package/src/core/operations/AnalyseUUID.mjs +109 -6
  32. package/src/core/operations/BlurImage.mjs +10 -12
  33. package/src/core/operations/ContainImage.mjs +50 -40
  34. package/src/core/operations/ConvertImageFormat.mjs +33 -39
  35. package/src/core/operations/CoverImage.mjs +39 -37
  36. package/src/core/operations/CropImage.mjs +35 -21
  37. package/src/core/operations/DisassembleARM.mjs +193 -0
  38. package/src/core/operations/DitherImage.mjs +8 -8
  39. package/src/core/operations/EscapeUnicodeCharacters.mjs +0 -17
  40. package/src/core/operations/ExtractAudioMetadata.mjs +175 -0
  41. package/src/core/operations/ExtractEmailAddresses.mjs +2 -3
  42. package/src/core/operations/ExtractLSB.mjs +17 -11
  43. package/src/core/operations/ExtractRGBA.mjs +12 -10
  44. package/src/core/operations/FlaskSessionDecode.mjs +80 -0
  45. package/src/core/operations/FlaskSessionSign.mjs +89 -0
  46. package/src/core/operations/FlaskSessionVerify.mjs +136 -0
  47. package/src/core/operations/FlipImage.mjs +14 -10
  48. package/src/core/operations/GenerateImage.mjs +39 -32
  49. package/src/core/operations/ImageBrightnessContrast.mjs +10 -10
  50. package/src/core/operations/ImageFilter.mjs +14 -13
  51. package/src/core/operations/ImageHueSaturationLightness.mjs +22 -20
  52. package/src/core/operations/ImageOpacity.mjs +6 -8
  53. package/src/core/operations/InvertImage.mjs +4 -6
  54. package/src/core/operations/Jq.mjs +12 -4
  55. package/src/core/operations/NormaliseImage.mjs +5 -7
  56. package/src/core/operations/OffsetChecker.mjs +1 -1
  57. package/src/core/operations/ParityBit.mjs +128 -0
  58. package/src/core/operations/ParseEthernetFrame.mjs +112 -0
  59. package/src/core/operations/ParseIPv4Header.mjs +23 -6
  60. package/src/core/operations/ParseQRCode.mjs +13 -13
  61. package/src/core/operations/PseudoRandomIntegerGenerator.mjs +164 -0
  62. package/src/core/operations/RC6Decrypt.mjs +119 -0
  63. package/src/core/operations/RC6Encrypt.mjs +119 -0
  64. package/src/core/operations/RandomizeColourPalette.mjs +11 -11
  65. package/src/core/operations/RegularExpression.mjs +2 -1
  66. package/src/core/operations/RenderMarkdown.mjs +35 -4
  67. package/src/core/operations/ResizeImage.mjs +30 -23
  68. package/src/core/operations/RotateImage.mjs +8 -9
  69. package/src/core/operations/SQLBeautify.mjs +21 -3
  70. package/src/core/operations/SharpenImage.mjs +94 -62
  71. package/src/core/operations/SplitColourChannels.mjs +47 -21
  72. package/src/core/operations/TextIntegerConverter.mjs +123 -0
  73. package/src/core/operations/UnescapeUnicodeCharacters.mjs +17 -0
  74. package/src/core/operations/ViewBitPlane.mjs +16 -20
  75. package/src/core/operations/index.mjs +22 -0
  76. package/src/node/index.mjs +55 -0
  77. package/src/web/HTMLIngredient.mjs +24 -43
  78. package/src/web/HTMLOperation.mjs +8 -2
  79. package/src/web/Manager.mjs +1 -0
  80. package/src/web/html/index.html +6 -6
  81. package/src/web/static/fonts/bmfonts/Roboto72White.fnt +491 -485
  82. package/src/web/static/fonts/bmfonts/RobotoBlack72White.fnt +494 -488
  83. package/src/web/static/fonts/bmfonts/RobotoMono72White.fnt +110 -103
  84. package/src/web/static/fonts/bmfonts/RobotoSlab72White.fnt +498 -492
  85. package/src/web/stylesheets/layout/_banner.css +30 -0
  86. package/src/web/stylesheets/layout/_modals.css +5 -0
  87. package/src/web/stylesheets/utils/_overrides.css +7 -0
  88. package/src/web/waiters/ControlsWaiter.mjs +82 -0
  89. package/src/web/waiters/InputWaiter.mjs +12 -6
  90. package/src/web/waiters/OperationsWaiter.mjs +30 -13
  91. package/src/web/waiters/RecipeWaiter.mjs +2 -2
  92. package/tests/browser/02_ops.js +23 -3
  93. package/tests/node/index.mjs +1 -0
  94. package/tests/node/tests/lib/BigIntUtils.mjs +150 -0
  95. package/tests/node/tests/operations.mjs +11 -10
  96. package/tests/operations/index.mjs +13 -0
  97. package/tests/operations/tests/A1Z26CipherDecode.mjs +33 -0
  98. package/tests/operations/tests/AnalyseUUID.mjs +66 -0
  99. package/tests/operations/tests/DisassembleARM.mjs +377 -0
  100. package/tests/operations/tests/ExtractAudioMetadata.mjs +287 -0
  101. package/tests/operations/tests/ExtractEmailAddresses.mjs +38 -12
  102. package/tests/operations/tests/Fernet.mjs +18 -3
  103. package/tests/operations/tests/FlaskSession.mjs +246 -0
  104. package/tests/operations/tests/GenerateQRCode.mjs +67 -0
  105. package/tests/operations/tests/JWTSign.mjs +83 -8
  106. package/tests/operations/tests/Jq.mjs +32 -0
  107. package/tests/operations/tests/Modhex.mjs +20 -0
  108. package/tests/operations/tests/ParityBit.mjs +147 -0
  109. package/tests/operations/tests/ParseEthernetFrame.mjs +45 -0
  110. package/tests/operations/tests/RC6.mjs +487 -0
  111. package/tests/operations/tests/RegularExpression.mjs +75 -0
  112. package/tests/operations/tests/RenderMarkdown.mjs +110 -0
  113. package/tests/operations/tests/SQLBeautify.mjs +54 -0
  114. package/tests/operations/tests/TextIntegerConverter.mjs +199 -0
  115. package/tests/samples/Audio.mjs +73 -0
  116. package/tests/samples/Images.mjs +0 -12
  117. package/webpack.config.js +10 -7
  118. package/src/core/lib/ImageManipulation.mjs +0 -251
@@ -0,0 +1,164 @@
1
+ /**
2
+ * @author cktgh [chankaitung@gmail.com]
3
+ * @copyright Crown Copyright 2026
4
+ * @license Apache-2.0
5
+ */
6
+
7
+ import Operation from "../Operation.mjs";
8
+ import OperationError from "../errors/OperationError.mjs";
9
+ import forge from "node-forge";
10
+ import Utils, { isWorkerEnvironment } from "../Utils.mjs";
11
+ import { DELIM_OPTIONS } from "../lib/Delim.mjs";
12
+
13
+ /**
14
+ * Pseudo-Random Integer Generator operation
15
+ */
16
+ class PseudoRandomIntegerGenerator extends Operation {
17
+
18
+ // in theory 2**53 is the max range, but we use Number.MAX_SAFE_INTEGER (2**53 - 1) as it is more consistent.
19
+ static MAX_RANGE = Number.MAX_SAFE_INTEGER;
20
+ // arbitrary choice
21
+ static BUFFER_SIZE = 1024;
22
+
23
+ /**
24
+ * PseudoRandomIntegerGenerator constructor
25
+ */
26
+ constructor() {
27
+ super();
28
+
29
+ this.name = "Pseudo-Random Integer Generator";
30
+ this.module = "Ciphers";
31
+ this.description = "A cryptographically-secure pseudo-random number generator (PRNG).<br><br>Generates random integers within a specified range using the browser's built-in <code>crypto.getRandomValues()</code> method if available.<br><br>The supported range of integers is from <code>-(2^53 - 1)</code> to <code>(2^53 - 1)</code>.";
32
+ this.infoURL = "https://wikipedia.org/wiki/Pseudorandom_number_generator";
33
+ this.inputType = "string";
34
+ this.outputType = "string";
35
+ this.args = [
36
+ {
37
+ "name": "Number of Integers",
38
+ "type": "number",
39
+ "value": 1,
40
+ "min": 1
41
+ },
42
+ {
43
+ "name": "Min Value",
44
+ "type": "number",
45
+ "value": 0,
46
+ "min": Number.MIN_SAFE_INTEGER,
47
+ "max": Number.MAX_SAFE_INTEGER
48
+ },
49
+ {
50
+ "name": "Max Value",
51
+ "type": "number",
52
+ "value": 99,
53
+ "min": Number.MIN_SAFE_INTEGER,
54
+ "max": Number.MAX_SAFE_INTEGER
55
+ },
56
+ {
57
+ "name": "Delimiter",
58
+ "type": "option",
59
+ "value": DELIM_OPTIONS
60
+ },
61
+ {
62
+ "name": "Output",
63
+ "type": "option",
64
+ "value": ["Raw", "Hex", "Decimal"]
65
+ }
66
+ ];
67
+
68
+ // not using BigUint64Array to avoid BigInt handling overhead
69
+ this.randomBuffer = new Uint32Array(PseudoRandomIntegerGenerator.BUFFER_SIZE);
70
+ this.randomBufferOffset = PseudoRandomIntegerGenerator.BUFFER_SIZE;
71
+ }
72
+
73
+ /**
74
+ * @param {string} input
75
+ * @param {Object[]} args
76
+ * @returns {string}
77
+ */
78
+ run(input, args) {
79
+ const [numInts, minInt, maxInt, delimiter, outputType] = args;
80
+
81
+ if (minInt === null || maxInt === null) return "";
82
+
83
+ const min = Math.ceil(minInt);
84
+ const max = Math.floor(maxInt);
85
+ const delim = Utils.charRep(delimiter || "Space");
86
+
87
+ if (!Number.isSafeInteger(min) || !Number.isSafeInteger(max)) {
88
+ throw new OperationError("Min and Max must be between `-(2^53 - 1)` and `2^53 - 1`.");
89
+ }
90
+ if (min > max) {
91
+ throw new OperationError("Min cannot be larger than Max.");
92
+ }
93
+ const range = max - min + 1; // inclusive range
94
+ if (range > PseudoRandomIntegerGenerator.MAX_RANGE) {
95
+ throw new OperationError("Range between Min and Max cannot be larger than `2^53`");
96
+ }
97
+
98
+ // as large as possible while divisible by range
99
+ const rejectionThreshold = PseudoRandomIntegerGenerator.MAX_RANGE - (PseudoRandomIntegerGenerator.MAX_RANGE % range);
100
+ const output = [];
101
+ for (let i = 0; i < numInts; i++) {
102
+ const result = this._generateRandomValue(rejectionThreshold);
103
+ const intValue = min + (result % range);
104
+
105
+ switch (outputType) {
106
+ case "Hex":
107
+ output.push(intValue.toString(16));
108
+ break;
109
+ case "Decimal":
110
+ output.push(intValue.toString(10));
111
+ break;
112
+ case "Raw":
113
+ default:
114
+ output.push(Utils.chr(intValue));
115
+ }
116
+ }
117
+
118
+ if (outputType === "Raw") {
119
+ return output.join("");
120
+ }
121
+ return output.join(delim);
122
+ }
123
+
124
+ /**
125
+ * Generate a random value, result will be less than the rejection threshold (exclusive).
126
+ *
127
+ * @param {number} rejectionThreshold
128
+ * @returns {number}
129
+ */
130
+ _generateRandomValue(rejectionThreshold) {
131
+ let result;
132
+ do {
133
+ if (this.randomBufferOffset + 2 > this.randomBuffer.length) {
134
+ this._resetRandomBuffer();
135
+ }
136
+ // stitching a 53 bit number; not using BigUint64Array to avoid BigInt handling overhead
137
+ result = (this.randomBuffer[this.randomBufferOffset++] & 0x1f_ffff) * 0x1_0000_0000 +
138
+ this.randomBuffer[this.randomBufferOffset++];
139
+ } while (result >= rejectionThreshold);
140
+
141
+ return result;
142
+ }
143
+
144
+ /**
145
+ * Fill random buffer with new random values and rseet the offset.
146
+ */
147
+ _resetRandomBuffer() {
148
+ if (isWorkerEnvironment() && self.crypto) {
149
+ self.crypto.getRandomValues(this.randomBuffer);
150
+ } else {
151
+ const bytes = forge.random.getBytesSync(this.randomBuffer.length * 4);
152
+ for (let j = 0; j < this.randomBuffer.length; j++) {
153
+ this.randomBuffer[j] = (bytes.charCodeAt(j * 4) << 24) |
154
+ (bytes.charCodeAt(j * 4 + 1) << 16) |
155
+ (bytes.charCodeAt(j * 4 + 2) << 8) |
156
+ bytes.charCodeAt(j * 4 + 3);
157
+ }
158
+ }
159
+ this.randomBufferOffset = 0;
160
+ }
161
+
162
+ }
163
+
164
+ export default PseudoRandomIntegerGenerator;
@@ -0,0 +1,119 @@
1
+ /**
2
+ * @author Medjedtxm
3
+ * @copyright Crown Copyright 2026
4
+ * @license Apache-2.0
5
+ */
6
+
7
+ import Operation from "../Operation.mjs";
8
+ import Utils from "../Utils.mjs";
9
+ import OperationError from "../errors/OperationError.mjs";
10
+ import { toHex } from "../lib/Hex.mjs";
11
+ import { decryptRC6, getBlockSize, getDefaultRounds } from "../lib/RC6.mjs";
12
+
13
+ /**
14
+ * RC6 Decrypt operation
15
+ */
16
+ class RC6Decrypt extends Operation {
17
+
18
+ /**
19
+ * RC6Decrypt constructor
20
+ */
21
+ constructor() {
22
+ super();
23
+
24
+ this.name = "RC6 Decrypt";
25
+ this.module = "Ciphers";
26
+ this.description = "RC6 is a symmetric key block cipher derived from RC5. It was designed by Ron Rivest, Matt Robshaw, Ray Sidney, and Yiqun Lisa Yin to meet the requirements of the AES competition, and was one of the five finalists.<br><br>RC6 is parameterised as RC6-w/r/b where w is word size in bits (any multiple of 8 from 8-256), r is the number of rounds (1-255), and b is the key length in bytes. The standard AES submission uses w=32, r=20. Common word sizes: 8, 16, 32 (standard), 64, 128.<br><br><b>IV:</b> The Initialisation Vector should be 4*w/8 bytes (e.g. 16 bytes for w=32). If not entered, it will default to null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, the PKCS#7 padding scheme is used.";
27
+ this.infoURL = "https://wikipedia.org/wiki/RC6";
28
+ this.inputType = "string";
29
+ this.outputType = "string";
30
+ this.args = [
31
+ {
32
+ "name": "Key",
33
+ "type": "toggleString",
34
+ "value": "",
35
+ "toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
36
+ },
37
+ {
38
+ "name": "IV",
39
+ "type": "toggleString",
40
+ "value": "",
41
+ "toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
42
+ },
43
+ {
44
+ "name": "Mode",
45
+ "type": "option",
46
+ "value": ["CBC", "CFB", "OFB", "CTR", "ECB"]
47
+ },
48
+ {
49
+ "name": "Input",
50
+ "type": "option",
51
+ "value": ["Hex", "Raw"]
52
+ },
53
+ {
54
+ "name": "Output",
55
+ "type": "option",
56
+ "value": ["Raw", "Hex"]
57
+ },
58
+ {
59
+ "name": "Padding",
60
+ "type": "option",
61
+ "value": ["PKCS5", "NO", "ZERO", "RANDOM", "BIT"]
62
+ },
63
+ {
64
+ "name": "Word Size",
65
+ "type": "number",
66
+ "value": 32,
67
+ "min": 8,
68
+ "max": 256,
69
+ "step": 8
70
+ },
71
+ {
72
+ "name": "Rounds",
73
+ "type": "number",
74
+ "value": 20,
75
+ "min": 1,
76
+ "max": 255
77
+ }
78
+ ];
79
+ }
80
+
81
+ /**
82
+ * @param {string} input
83
+ * @param {Object[]} args
84
+ * @returns {string}
85
+ */
86
+ run(input, args) {
87
+ const key = Utils.convertToByteArray(args[0].string, args[0].option),
88
+ iv = Utils.convertToByteArray(args[1].string, args[1].option),
89
+ [,, mode, inputType, outputType, padding, wordSize, rounds] = args;
90
+
91
+ // Validate word size
92
+ if (!Number.isInteger(wordSize) || wordSize < 8 || wordSize > 256 || wordSize % 8 !== 0)
93
+ throw new OperationError(`Invalid word size: ${wordSize}. Must be a multiple of 8 between 8 and 256.`);
94
+
95
+ const blockSize = getBlockSize(wordSize);
96
+ const defaultRounds = getDefaultRounds(wordSize);
97
+
98
+ if (iv.length !== blockSize && iv.length !== 0 && mode !== "ECB")
99
+ throw new OperationError(`Invalid IV length: ${iv.length} bytes
100
+
101
+ RC6-${wordSize} uses an IV length of ${blockSize} bytes (${blockSize * 8} bits).
102
+ Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
103
+
104
+ if (!Number.isInteger(rounds) || rounds < 1 || rounds > 255)
105
+ throw new OperationError(`Invalid number of rounds: ${rounds}
106
+
107
+ Rounds must be an integer between 1 and 255. Standard for w=${wordSize} is ${defaultRounds}.`);
108
+
109
+ // Default IV to null bytes if empty (like AES)
110
+ const actualIv = iv.length === 0 ? new Array(blockSize).fill(0) : iv;
111
+
112
+ input = Utils.convertToByteArray(input, inputType);
113
+ const output = decryptRC6(input, key, actualIv, mode, padding, rounds, wordSize);
114
+ return outputType === "Hex" ? toHex(output, "") : Utils.byteArrayToUtf8(output);
115
+ }
116
+
117
+ }
118
+
119
+ export default RC6Decrypt;
@@ -0,0 +1,119 @@
1
+ /**
2
+ * @author Medjedtxm
3
+ * @copyright Crown Copyright 2026
4
+ * @license Apache-2.0
5
+ */
6
+
7
+ import Operation from "../Operation.mjs";
8
+ import Utils from "../Utils.mjs";
9
+ import OperationError from "../errors/OperationError.mjs";
10
+ import { toHex } from "../lib/Hex.mjs";
11
+ import { encryptRC6, getBlockSize, getDefaultRounds } from "../lib/RC6.mjs";
12
+
13
+ /**
14
+ * RC6 Encrypt operation
15
+ */
16
+ class RC6Encrypt extends Operation {
17
+
18
+ /**
19
+ * RC6Encrypt constructor
20
+ */
21
+ constructor() {
22
+ super();
23
+
24
+ this.name = "RC6 Encrypt";
25
+ this.module = "Ciphers";
26
+ this.description = "RC6 is a symmetric key block cipher derived from RC5. It was designed by Ron Rivest, Matt Robshaw, Ray Sidney, and Yiqun Lisa Yin to meet the requirements of the AES competition, and was one of the five finalists.<br><br>RC6 is parameterised as RC6-w/r/b where w is word size in bits (any multiple of 8 from 8-256), r is the number of rounds (1-255), and b is the key length in bytes. The standard AES submission uses w=32, r=20. Common word sizes: 8, 16, 32 (standard), 64, 128.<br><br><b>IV:</b> The Initialisation Vector should be 4*w/8 bytes (e.g. 16 bytes for w=32). If not entered, it will default to null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, the PKCS#7 padding scheme is used.";
27
+ this.infoURL = "https://wikipedia.org/wiki/RC6";
28
+ this.inputType = "string";
29
+ this.outputType = "string";
30
+ this.args = [
31
+ {
32
+ "name": "Key",
33
+ "type": "toggleString",
34
+ "value": "",
35
+ "toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
36
+ },
37
+ {
38
+ "name": "IV",
39
+ "type": "toggleString",
40
+ "value": "",
41
+ "toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
42
+ },
43
+ {
44
+ "name": "Mode",
45
+ "type": "option",
46
+ "value": ["CBC", "CFB", "OFB", "CTR", "ECB"]
47
+ },
48
+ {
49
+ "name": "Input",
50
+ "type": "option",
51
+ "value": ["Raw", "Hex"]
52
+ },
53
+ {
54
+ "name": "Output",
55
+ "type": "option",
56
+ "value": ["Hex", "Raw"]
57
+ },
58
+ {
59
+ "name": "Padding",
60
+ "type": "option",
61
+ "value": ["PKCS5", "NO", "ZERO", "RANDOM", "BIT"]
62
+ },
63
+ {
64
+ "name": "Word Size",
65
+ "type": "number",
66
+ "value": 32,
67
+ "min": 8,
68
+ "max": 256,
69
+ "step": 8
70
+ },
71
+ {
72
+ "name": "Rounds",
73
+ "type": "number",
74
+ "value": 20,
75
+ "min": 1,
76
+ "max": 255
77
+ }
78
+ ];
79
+ }
80
+
81
+ /**
82
+ * @param {string} input
83
+ * @param {Object[]} args
84
+ * @returns {string}
85
+ */
86
+ run(input, args) {
87
+ const key = Utils.convertToByteArray(args[0].string, args[0].option),
88
+ iv = Utils.convertToByteArray(args[1].string, args[1].option),
89
+ [,, mode, inputType, outputType, padding, wordSize, rounds] = args;
90
+
91
+ // Validate word size
92
+ if (!Number.isInteger(wordSize) || wordSize < 8 || wordSize > 256 || wordSize % 8 !== 0)
93
+ throw new OperationError(`Invalid word size: ${wordSize}. Must be a multiple of 8 between 8 and 256.`);
94
+
95
+ const blockSize = getBlockSize(wordSize);
96
+ const defaultRounds = getDefaultRounds(wordSize);
97
+
98
+ if (iv.length !== blockSize && iv.length !== 0 && mode !== "ECB")
99
+ throw new OperationError(`Invalid IV length: ${iv.length} bytes
100
+
101
+ RC6-${wordSize} uses an IV length of ${blockSize} bytes (${blockSize * 8} bits).
102
+ Make sure you have specified the type correctly (e.g. Hex vs UTF8).`);
103
+
104
+ if (!Number.isInteger(rounds) || rounds < 1 || rounds > 255)
105
+ throw new OperationError(`Invalid number of rounds: ${rounds}
106
+
107
+ Rounds must be an integer between 1 and 255. Standard for w=${wordSize} is ${defaultRounds}.`);
108
+
109
+ // Default IV to null bytes if empty (like AES)
110
+ const actualIv = iv.length === 0 ? new Array(blockSize).fill(0) : iv;
111
+
112
+ input = Utils.convertToByteArray(input, inputType);
113
+ const output = encryptRC6(input, key, actualIv, mode, padding, rounds, wordSize);
114
+ return outputType === "Hex" ? toHex(output, "") : Utils.byteArrayToUtf8(output);
115
+ }
116
+
117
+ }
118
+
119
+ export default RC6Encrypt;
@@ -10,13 +10,12 @@ import Utils from "../Utils.mjs";
10
10
  import { isImage } from "../lib/FileType.mjs";
11
11
  import { runHash } from "../lib/Hash.mjs";
12
12
  import { toBase64 } from "../lib/Base64.mjs";
13
- import Jimp from "jimp/es/index.js";
13
+ import { Jimp } from "jimp";
14
14
 
15
15
  /**
16
16
  * Randomize Colour Palette operation
17
17
  */
18
18
  class RandomizeColourPalette extends Operation {
19
-
20
19
  /**
21
20
  * RandomizeColourPalette constructor
22
21
  */
@@ -25,7 +24,8 @@ class RandomizeColourPalette extends Operation {
25
24
 
26
25
  this.name = "Randomize Colour Palette";
27
26
  this.module = "Image";
28
- this.description = "Randomizes each colour in an image's colour palette. This can often reveal text or symbols that were previously a very similar colour to their surroundings, a technique sometimes used in Steganography.";
27
+ this.description =
28
+ "Randomizes each colour in an image's colour palette. This can often reveal text or symbols that were previously a very similar colour to their surroundings, a technique sometimes used in Steganography.";
29
29
  this.infoURL = "https://wikipedia.org/wiki/Indexed_color";
30
30
  this.inputType = "ArrayBuffer";
31
31
  this.outputType = "ArrayBuffer";
@@ -34,8 +34,8 @@ class RandomizeColourPalette extends Operation {
34
34
  {
35
35
  name: "Seed",
36
36
  type: "string",
37
- value: ""
38
- }
37
+ value: "",
38
+ },
39
39
  ];
40
40
  }
41
41
 
@@ -45,23 +45,24 @@ class RandomizeColourPalette extends Operation {
45
45
  * @returns {ArrayBuffer}
46
46
  */
47
47
  async run(input, args) {
48
- if (!isImage(input)) throw new OperationError("Please enter a valid image file.");
48
+ if (!isImage(input))
49
+ throw new OperationError("Please enter a valid image file.");
49
50
 
50
- const seed = args[0] || (Math.random().toString().substr(2)),
51
+ const seed = args[0] || Math.random().toString().substr(2),
51
52
  parsedImage = await Jimp.read(input),
52
53
  width = parsedImage.bitmap.width,
53
54
  height = parsedImage.bitmap.height;
54
55
 
55
56
  let rgbString, rgbHash, rgbHex;
56
57
 
57
- parsedImage.scan(0, 0, width, height, function(x, y, idx) {
58
- rgbString = this.bitmap.data.slice(idx, idx+3).join(".");
58
+ parsedImage.scan(0, 0, width, height, function (x, y, idx) {
59
+ rgbString = this.bitmap.data.slice(idx, idx + 3).join(".");
59
60
  rgbHash = runHash("md5", Utils.strToArrayBuffer(seed + rgbString));
60
61
  rgbHex = rgbHash.substr(0, 6) + "ff";
61
62
  parsedImage.setPixelColor(parseInt(rgbHex, 16), x, y);
62
63
  });
63
64
 
64
- const imageBuffer = await parsedImage.getBufferAsync(Jimp.AUTO);
65
+ const imageBuffer = await parsedImage.getBuffer(parsedImage.mime);
65
66
 
66
67
  return new Uint8Array(imageBuffer).buffer;
67
68
  }
@@ -77,7 +78,6 @@ class RandomizeColourPalette extends Operation {
77
78
 
78
79
  return `<img src="data:${type};base64,${toBase64(data)}">`;
79
80
  }
80
-
81
81
  }
82
82
 
83
83
  export default RandomizeColourPalette;
@@ -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;