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.
- package/CHANGELOG.md +182 -0
- package/CONTRIBUTING.md +40 -0
- package/Dockerfile +2 -0
- package/Gruntfile.js +2 -28
- package/README.md +1 -1
- package/babel.config.js +0 -6
- package/package.json +64 -63
- package/src/core/Chef.mjs +8 -1
- package/src/core/Ingredient.mjs +5 -2
- package/src/core/Operation.mjs +6 -1
- package/src/core/Recipe.mjs +10 -5
- package/src/core/config/Categories.json +20 -4
- package/src/core/config/OperationConfig.json +550 -26
- package/src/core/config/modules/Ciphers.mjs +6 -0
- package/src/core/config/modules/Crypto.mjs +6 -0
- package/src/core/config/modules/Default.mjs +8 -0
- package/src/core/config/modules/Shellcode.mjs +2 -0
- package/src/core/config/scripts/fixCryptoApiImports.mjs +54 -0
- package/src/core/config/scripts/fixSnackBarMarkup.mjs +28 -0
- package/src/core/lib/AudioBytes.mjs +103 -0
- package/src/core/lib/AudioMetaSchema.mjs +82 -0
- package/src/core/lib/AudioParsers.mjs +630 -0
- package/src/core/lib/BigIntUtils.mjs +73 -0
- package/src/core/lib/Extract.mjs +5 -0
- package/src/core/lib/Modhex.mjs +2 -0
- package/src/core/lib/ParityBit.mjs +50 -0
- package/src/core/lib/QRCode.mjs +30 -10
- package/src/core/lib/RC6.mjs +625 -0
- package/src/core/operations/A1Z26CipherDecode.mjs +1 -1
- package/src/core/operations/AddTextToImage.mjs +116 -64
- package/src/core/operations/AnalyseUUID.mjs +109 -6
- package/src/core/operations/BlurImage.mjs +10 -12
- package/src/core/operations/ContainImage.mjs +50 -40
- package/src/core/operations/ConvertImageFormat.mjs +33 -39
- package/src/core/operations/CoverImage.mjs +39 -37
- package/src/core/operations/CropImage.mjs +35 -21
- package/src/core/operations/DisassembleARM.mjs +193 -0
- package/src/core/operations/DitherImage.mjs +8 -8
- package/src/core/operations/EscapeUnicodeCharacters.mjs +0 -17
- package/src/core/operations/ExtractAudioMetadata.mjs +175 -0
- package/src/core/operations/ExtractEmailAddresses.mjs +2 -3
- package/src/core/operations/ExtractLSB.mjs +17 -11
- package/src/core/operations/ExtractRGBA.mjs +12 -10
- package/src/core/operations/FlaskSessionDecode.mjs +80 -0
- package/src/core/operations/FlaskSessionSign.mjs +89 -0
- package/src/core/operations/FlaskSessionVerify.mjs +136 -0
- package/src/core/operations/FlipImage.mjs +14 -10
- package/src/core/operations/GenerateImage.mjs +39 -32
- package/src/core/operations/ImageBrightnessContrast.mjs +10 -10
- package/src/core/operations/ImageFilter.mjs +14 -13
- package/src/core/operations/ImageHueSaturationLightness.mjs +22 -20
- package/src/core/operations/ImageOpacity.mjs +6 -8
- package/src/core/operations/InvertImage.mjs +4 -6
- package/src/core/operations/Jq.mjs +12 -4
- package/src/core/operations/NormaliseImage.mjs +5 -7
- package/src/core/operations/OffsetChecker.mjs +1 -1
- package/src/core/operations/ParityBit.mjs +128 -0
- package/src/core/operations/ParseEthernetFrame.mjs +112 -0
- package/src/core/operations/ParseIPv4Header.mjs +23 -6
- package/src/core/operations/ParseQRCode.mjs +13 -13
- package/src/core/operations/PseudoRandomIntegerGenerator.mjs +164 -0
- package/src/core/operations/RC6Decrypt.mjs +119 -0
- package/src/core/operations/RC6Encrypt.mjs +119 -0
- package/src/core/operations/RandomizeColourPalette.mjs +11 -11
- package/src/core/operations/RegularExpression.mjs +2 -1
- package/src/core/operations/RenderMarkdown.mjs +35 -4
- package/src/core/operations/ResizeImage.mjs +30 -23
- package/src/core/operations/RotateImage.mjs +8 -9
- package/src/core/operations/SQLBeautify.mjs +21 -3
- package/src/core/operations/SharpenImage.mjs +94 -62
- package/src/core/operations/SplitColourChannels.mjs +47 -21
- package/src/core/operations/TextIntegerConverter.mjs +123 -0
- package/src/core/operations/UnescapeUnicodeCharacters.mjs +17 -0
- package/src/core/operations/ViewBitPlane.mjs +16 -20
- package/src/core/operations/index.mjs +22 -0
- package/src/node/index.mjs +55 -0
- package/src/web/HTMLIngredient.mjs +24 -43
- package/src/web/HTMLOperation.mjs +8 -2
- package/src/web/Manager.mjs +1 -0
- package/src/web/html/index.html +6 -6
- package/src/web/static/fonts/bmfonts/Roboto72White.fnt +491 -485
- package/src/web/static/fonts/bmfonts/RobotoBlack72White.fnt +494 -488
- package/src/web/static/fonts/bmfonts/RobotoMono72White.fnt +110 -103
- package/src/web/static/fonts/bmfonts/RobotoSlab72White.fnt +498 -492
- package/src/web/stylesheets/layout/_banner.css +30 -0
- package/src/web/stylesheets/layout/_modals.css +5 -0
- package/src/web/stylesheets/utils/_overrides.css +7 -0
- package/src/web/waiters/ControlsWaiter.mjs +82 -0
- package/src/web/waiters/InputWaiter.mjs +12 -6
- package/src/web/waiters/OperationsWaiter.mjs +30 -13
- package/src/web/waiters/RecipeWaiter.mjs +2 -2
- package/tests/browser/02_ops.js +23 -3
- package/tests/node/index.mjs +1 -0
- package/tests/node/tests/lib/BigIntUtils.mjs +150 -0
- package/tests/node/tests/operations.mjs +11 -10
- package/tests/operations/index.mjs +13 -0
- package/tests/operations/tests/A1Z26CipherDecode.mjs +33 -0
- package/tests/operations/tests/AnalyseUUID.mjs +66 -0
- package/tests/operations/tests/DisassembleARM.mjs +377 -0
- package/tests/operations/tests/ExtractAudioMetadata.mjs +287 -0
- package/tests/operations/tests/ExtractEmailAddresses.mjs +38 -12
- package/tests/operations/tests/Fernet.mjs +18 -3
- package/tests/operations/tests/FlaskSession.mjs +246 -0
- package/tests/operations/tests/GenerateQRCode.mjs +67 -0
- package/tests/operations/tests/JWTSign.mjs +83 -8
- package/tests/operations/tests/Jq.mjs +32 -0
- package/tests/operations/tests/Modhex.mjs +20 -0
- package/tests/operations/tests/ParityBit.mjs +147 -0
- package/tests/operations/tests/ParseEthernetFrame.mjs +45 -0
- package/tests/operations/tests/RC6.mjs +487 -0
- package/tests/operations/tests/RegularExpression.mjs +75 -0
- package/tests/operations/tests/RenderMarkdown.mjs +110 -0
- package/tests/operations/tests/SQLBeautify.mjs +54 -0
- package/tests/operations/tests/TextIntegerConverter.mjs +199 -0
- package/tests/samples/Audio.mjs +73 -0
- package/tests/samples/Images.mjs +0 -12
- package/webpack.config.js +10 -7
- package/src/core/lib/ImageManipulation.mjs +0 -251
|
@@ -9,13 +9,19 @@ import OperationError from "../errors/OperationError.mjs";
|
|
|
9
9
|
import { isImage } from "../lib/FileType.mjs";
|
|
10
10
|
import { toBase64 } from "../lib/Base64.mjs";
|
|
11
11
|
import { isWorkerEnvironment } from "../Utils.mjs";
|
|
12
|
-
import
|
|
12
|
+
import {
|
|
13
|
+
Jimp,
|
|
14
|
+
JimpMime,
|
|
15
|
+
ResizeStrategy,
|
|
16
|
+
measureText,
|
|
17
|
+
measureTextHeight,
|
|
18
|
+
loadFont,
|
|
19
|
+
} from "jimp";
|
|
13
20
|
|
|
14
21
|
/**
|
|
15
22
|
* Add Text To Image operation
|
|
16
23
|
*/
|
|
17
24
|
class AddTextToImage extends Operation {
|
|
18
|
-
|
|
19
25
|
/**
|
|
20
26
|
* AddTextToImage constructor
|
|
21
27
|
*/
|
|
@@ -24,7 +30,8 @@ class AddTextToImage extends Operation {
|
|
|
24
30
|
|
|
25
31
|
this.name = "Add Text To Image";
|
|
26
32
|
this.module = "Image";
|
|
27
|
-
this.description =
|
|
33
|
+
this.description =
|
|
34
|
+
"Adds text onto an image.<br><br>Text can be horizontally or vertically aligned, or the position can be manually specified.<br>Variants of the Roboto font face are available in any size or colour.";
|
|
28
35
|
this.infoURL = "";
|
|
29
36
|
this.inputType = "ArrayBuffer";
|
|
30
37
|
this.outputType = "ArrayBuffer";
|
|
@@ -33,72 +40,67 @@ class AddTextToImage extends Operation {
|
|
|
33
40
|
{
|
|
34
41
|
name: "Text",
|
|
35
42
|
type: "string",
|
|
36
|
-
value: ""
|
|
43
|
+
value: "",
|
|
37
44
|
},
|
|
38
45
|
{
|
|
39
46
|
name: "Horizontal align",
|
|
40
47
|
type: "option",
|
|
41
|
-
value: ["None", "Left", "Center", "Right"]
|
|
48
|
+
value: ["None", "Left", "Center", "Right"],
|
|
42
49
|
},
|
|
43
50
|
{
|
|
44
51
|
name: "Vertical align",
|
|
45
52
|
type: "option",
|
|
46
|
-
value: ["None", "Top", "Middle", "Bottom"]
|
|
53
|
+
value: ["None", "Top", "Middle", "Bottom"],
|
|
47
54
|
},
|
|
48
55
|
{
|
|
49
56
|
name: "X position",
|
|
50
57
|
type: "number",
|
|
51
|
-
value: 0
|
|
58
|
+
value: 0,
|
|
52
59
|
},
|
|
53
60
|
{
|
|
54
61
|
name: "Y position",
|
|
55
62
|
type: "number",
|
|
56
|
-
value: 0
|
|
63
|
+
value: 0,
|
|
57
64
|
},
|
|
58
65
|
{
|
|
59
66
|
name: "Size",
|
|
60
67
|
type: "number",
|
|
61
68
|
value: 32,
|
|
62
|
-
min: 8
|
|
69
|
+
min: 8,
|
|
63
70
|
},
|
|
64
71
|
{
|
|
65
72
|
name: "Font face",
|
|
66
73
|
type: "option",
|
|
67
|
-
value: [
|
|
68
|
-
"Roboto",
|
|
69
|
-
"Roboto Black",
|
|
70
|
-
"Roboto Mono",
|
|
71
|
-
"Roboto Slab"
|
|
72
|
-
]
|
|
74
|
+
value: ["Roboto", "Roboto Black", "Roboto Mono", "Roboto Slab"],
|
|
73
75
|
},
|
|
74
76
|
{
|
|
75
77
|
name: "Red",
|
|
76
78
|
type: "number",
|
|
77
79
|
value: 255,
|
|
78
80
|
min: 0,
|
|
79
|
-
max: 255
|
|
81
|
+
max: 255,
|
|
80
82
|
},
|
|
81
83
|
{
|
|
82
84
|
name: "Green",
|
|
83
85
|
type: "number",
|
|
84
86
|
value: 255,
|
|
85
87
|
min: 0,
|
|
86
|
-
max: 255
|
|
88
|
+
max: 255,
|
|
87
89
|
},
|
|
88
90
|
{
|
|
89
91
|
name: "Blue",
|
|
90
92
|
type: "number",
|
|
91
93
|
value: 255,
|
|
92
94
|
min: 0,
|
|
93
|
-
max: 255
|
|
95
|
+
max: 255,
|
|
94
96
|
},
|
|
95
97
|
{
|
|
96
98
|
name: "Alpha",
|
|
97
99
|
type: "number",
|
|
98
100
|
value: 255,
|
|
99
101
|
min: 0,
|
|
100
|
-
max: 255
|
|
101
|
-
}
|
|
102
|
+
max: 255,
|
|
103
|
+
},
|
|
102
104
|
];
|
|
103
105
|
}
|
|
104
106
|
|
|
@@ -131,41 +133,60 @@ class AddTextToImage extends Operation {
|
|
|
131
133
|
} catch (err) {
|
|
132
134
|
throw new OperationError(`Error loading image. (${err})`);
|
|
133
135
|
}
|
|
134
|
-
try {
|
|
135
|
-
if (isWorkerEnvironment())
|
|
136
|
-
self.sendStatusMessage("Adding text to image...");
|
|
137
136
|
|
|
138
|
-
|
|
137
|
+
if (isWorkerEnvironment())
|
|
138
|
+
self.sendStatusMessage("Adding text to image...");
|
|
139
|
+
|
|
140
|
+
const fontsMap = {};
|
|
141
|
+
try {
|
|
139
142
|
const fonts = [
|
|
140
|
-
import(
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
import(
|
|
143
|
+
import(
|
|
144
|
+
/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/Roboto72White.fnt"
|
|
145
|
+
),
|
|
146
|
+
import(
|
|
147
|
+
/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoBlack72White.fnt"
|
|
148
|
+
),
|
|
149
|
+
import(
|
|
150
|
+
/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoMono72White.fnt"
|
|
151
|
+
),
|
|
152
|
+
import(
|
|
153
|
+
/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoSlab72White.fnt"
|
|
154
|
+
),
|
|
144
155
|
];
|
|
145
156
|
|
|
146
|
-
await Promise.all(fonts)
|
|
147
|
-
.
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
});
|
|
153
|
-
|
|
154
|
-
|
|
157
|
+
await Promise.all(fonts).then((fonts) => {
|
|
158
|
+
fontsMap.Roboto = fonts[0];
|
|
159
|
+
fontsMap["Roboto Black"] = fonts[1];
|
|
160
|
+
fontsMap["Roboto Mono"] = fonts[2];
|
|
161
|
+
fontsMap["Roboto Slab"] = fonts[3];
|
|
162
|
+
});
|
|
155
163
|
// Make Webpack load the png font images
|
|
156
164
|
await Promise.all([
|
|
157
|
-
import(
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
import(
|
|
165
|
+
import(
|
|
166
|
+
/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/Roboto72White.png"
|
|
167
|
+
),
|
|
168
|
+
import(
|
|
169
|
+
/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoSlab72White.png"
|
|
170
|
+
),
|
|
171
|
+
import(
|
|
172
|
+
/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoMono72White.png"
|
|
173
|
+
),
|
|
174
|
+
import(
|
|
175
|
+
/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoBlack72White.png"
|
|
176
|
+
),
|
|
161
177
|
]);
|
|
178
|
+
} catch (err) {
|
|
179
|
+
throw new OperationError(`Error preparing fonts. (${err})`);
|
|
180
|
+
}
|
|
162
181
|
|
|
182
|
+
let jimpFont;
|
|
183
|
+
try {
|
|
163
184
|
const font = fontsMap[fontFace];
|
|
164
185
|
|
|
165
186
|
// LoadFont needs an absolute url, so append the font name to self.docURL
|
|
166
|
-
|
|
187
|
+
jimpFont = await loadFont(self.docURL + "/" + font.default);
|
|
167
188
|
|
|
168
|
-
jimpFont.pages.forEach(function(page) {
|
|
189
|
+
jimpFont.pages.forEach(function (page) {
|
|
169
190
|
if (page.bitmap) {
|
|
170
191
|
// Adjust the RGB values of the image pages to change the font colour.
|
|
171
192
|
const pageWidth = page.bitmap.width;
|
|
@@ -175,32 +196,56 @@ class AddTextToImage extends Operation {
|
|
|
175
196
|
const idx = (iy * pageWidth + ix) << 2;
|
|
176
197
|
|
|
177
198
|
const newRed = page.bitmap.data[idx] - (255 - red);
|
|
178
|
-
const newGreen =
|
|
179
|
-
|
|
180
|
-
const
|
|
199
|
+
const newGreen =
|
|
200
|
+
page.bitmap.data[idx + 1] - (255 - green);
|
|
201
|
+
const newBlue =
|
|
202
|
+
page.bitmap.data[idx + 2] - (255 - blue);
|
|
203
|
+
const newAlpha =
|
|
204
|
+
page.bitmap.data[idx + 3] - (255 - alpha);
|
|
181
205
|
|
|
182
206
|
// Make sure the bitmap values don't go below 0 as that makes jimp very unhappy
|
|
183
|
-
page.bitmap.data[idx] =
|
|
184
|
-
page.bitmap.data[idx + 1] =
|
|
185
|
-
|
|
186
|
-
page.bitmap.data[idx +
|
|
207
|
+
page.bitmap.data[idx] = newRed > 0 ? newRed : 0;
|
|
208
|
+
page.bitmap.data[idx + 1] =
|
|
209
|
+
newGreen > 0 ? newGreen : 0;
|
|
210
|
+
page.bitmap.data[idx + 2] =
|
|
211
|
+
newBlue > 0 ? newBlue : 0;
|
|
212
|
+
page.bitmap.data[idx + 3] =
|
|
213
|
+
newAlpha > 0 ? newAlpha : 0;
|
|
187
214
|
}
|
|
188
215
|
}
|
|
189
216
|
}
|
|
190
217
|
});
|
|
218
|
+
} catch (err) {
|
|
219
|
+
throw new OperationError(`Error loading font. (${err})`);
|
|
220
|
+
}
|
|
191
221
|
|
|
222
|
+
try {
|
|
192
223
|
// Create a temporary image to hold the rendered text
|
|
193
|
-
const textImage = new Jimp(
|
|
194
|
-
|
|
224
|
+
const textImage = new Jimp({
|
|
225
|
+
width: measureText(jimpFont, text),
|
|
226
|
+
height: measureTextHeight(jimpFont, text),
|
|
227
|
+
});
|
|
228
|
+
textImage.print({
|
|
229
|
+
font: jimpFont,
|
|
230
|
+
x: 0,
|
|
231
|
+
y: 0,
|
|
232
|
+
text,
|
|
233
|
+
});
|
|
195
234
|
|
|
196
235
|
// Scale the rendered text image to the correct size
|
|
197
236
|
const scaleFactor = size / 72;
|
|
198
237
|
if (size !== 1) {
|
|
199
238
|
// Use bicubic for decreasing size
|
|
200
239
|
if (size > 1) {
|
|
201
|
-
textImage.scale(
|
|
240
|
+
textImage.scale({
|
|
241
|
+
f: scaleFactor,
|
|
242
|
+
mode: ResizeStrategy.BICUBIC,
|
|
243
|
+
});
|
|
202
244
|
} else {
|
|
203
|
-
textImage.scale(
|
|
245
|
+
textImage.scale({
|
|
246
|
+
f: scaleFactor,
|
|
247
|
+
mode: ResizeStrategy.BILINEAR,
|
|
248
|
+
});
|
|
204
249
|
}
|
|
205
250
|
}
|
|
206
251
|
|
|
@@ -210,10 +255,10 @@ class AddTextToImage extends Operation {
|
|
|
210
255
|
xPos = 0;
|
|
211
256
|
break;
|
|
212
257
|
case "Center":
|
|
213
|
-
xPos =
|
|
258
|
+
xPos = image.width / 2 - textImage.width / 2;
|
|
214
259
|
break;
|
|
215
260
|
case "Right":
|
|
216
|
-
xPos = image.
|
|
261
|
+
xPos = image.width - textImage.width;
|
|
217
262
|
break;
|
|
218
263
|
}
|
|
219
264
|
|
|
@@ -222,25 +267,33 @@ class AddTextToImage extends Operation {
|
|
|
222
267
|
yPos = 0;
|
|
223
268
|
break;
|
|
224
269
|
case "Middle":
|
|
225
|
-
yPos =
|
|
270
|
+
yPos = image.height / 2 - textImage.height / 2;
|
|
226
271
|
break;
|
|
227
272
|
case "Bottom":
|
|
228
|
-
yPos = image.
|
|
273
|
+
yPos = image.height - textImage.height;
|
|
229
274
|
break;
|
|
230
275
|
}
|
|
231
276
|
|
|
232
277
|
// Blit the rendered text image onto the original source image
|
|
233
|
-
image.blit(
|
|
278
|
+
image.blit({
|
|
279
|
+
src: textImage,
|
|
280
|
+
x: xPos,
|
|
281
|
+
y: yPos,
|
|
282
|
+
});
|
|
283
|
+
} catch (err) {
|
|
284
|
+
throw new OperationError(`Error adding text to image. (${err})`);
|
|
285
|
+
}
|
|
234
286
|
|
|
287
|
+
try {
|
|
235
288
|
let imageBuffer;
|
|
236
|
-
if (image.
|
|
237
|
-
imageBuffer = await image.
|
|
289
|
+
if (image.mime === "image/gif") {
|
|
290
|
+
imageBuffer = await image.getBuffer(JimpMime.png);
|
|
238
291
|
} else {
|
|
239
|
-
imageBuffer = await image.
|
|
292
|
+
imageBuffer = await image.getBuffer(image.mime);
|
|
240
293
|
}
|
|
241
294
|
return imageBuffer.buffer;
|
|
242
295
|
} catch (err) {
|
|
243
|
-
throw new OperationError(`Error
|
|
296
|
+
throw new OperationError(`Error exporting image. (${err})`);
|
|
244
297
|
}
|
|
245
298
|
}
|
|
246
299
|
|
|
@@ -261,7 +314,6 @@ class AddTextToImage extends Operation {
|
|
|
261
314
|
|
|
262
315
|
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
|
263
316
|
}
|
|
264
|
-
|
|
265
317
|
}
|
|
266
318
|
|
|
267
319
|
export default AddTextToImage;
|
|
@@ -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 = "
|
|
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
|
-
|
|
40
|
-
|
|
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
|
+
}
|
|
@@ -9,14 +9,12 @@ import OperationError from "../errors/OperationError.mjs";
|
|
|
9
9
|
import { isWorkerEnvironment } from "../Utils.mjs";
|
|
10
10
|
import { isImage } from "../lib/FileType.mjs";
|
|
11
11
|
import { toBase64 } from "../lib/Base64.mjs";
|
|
12
|
-
import {
|
|
13
|
-
import Jimp from "jimp/es/index.js";
|
|
12
|
+
import { Jimp, JimpMime } from "jimp";
|
|
14
13
|
|
|
15
14
|
/**
|
|
16
15
|
* Blur Image operation
|
|
17
16
|
*/
|
|
18
17
|
class BlurImage extends Operation {
|
|
19
|
-
|
|
20
18
|
/**
|
|
21
19
|
* BlurImage constructor
|
|
22
20
|
*/
|
|
@@ -25,7 +23,8 @@ class BlurImage extends Operation {
|
|
|
25
23
|
|
|
26
24
|
this.name = "Blur Image";
|
|
27
25
|
this.module = "Image";
|
|
28
|
-
this.description =
|
|
26
|
+
this.description =
|
|
27
|
+
"Applies a blur effect to the image.<br><br>Gaussian blur is much slower than fast blur, but produces better results.";
|
|
29
28
|
this.infoURL = "https://wikipedia.org/wiki/Gaussian_blur";
|
|
30
29
|
this.inputType = "ArrayBuffer";
|
|
31
30
|
this.outputType = "ArrayBuffer";
|
|
@@ -35,13 +34,13 @@ class BlurImage extends Operation {
|
|
|
35
34
|
name: "Amount",
|
|
36
35
|
type: "number",
|
|
37
36
|
value: 5,
|
|
38
|
-
min: 1
|
|
37
|
+
min: 1,
|
|
39
38
|
},
|
|
40
39
|
{
|
|
41
40
|
name: "Type",
|
|
42
41
|
type: "option",
|
|
43
|
-
value: ["Fast", "Gaussian"]
|
|
44
|
-
}
|
|
42
|
+
value: ["Fast", "Gaussian"],
|
|
43
|
+
},
|
|
45
44
|
];
|
|
46
45
|
}
|
|
47
46
|
|
|
@@ -73,15 +72,15 @@ class BlurImage extends Operation {
|
|
|
73
72
|
case "Gaussian":
|
|
74
73
|
if (isWorkerEnvironment())
|
|
75
74
|
self.sendStatusMessage("Gaussian blurring image...");
|
|
76
|
-
image
|
|
75
|
+
image.gaussian(blurAmount);
|
|
77
76
|
break;
|
|
78
77
|
}
|
|
79
78
|
|
|
80
79
|
let imageBuffer;
|
|
81
|
-
if (image.
|
|
82
|
-
imageBuffer = await image.
|
|
80
|
+
if (image.mime === "image/gif") {
|
|
81
|
+
imageBuffer = await image.getBuffer(JimpMime.png);
|
|
83
82
|
} else {
|
|
84
|
-
imageBuffer = await image.
|
|
83
|
+
imageBuffer = await image.getBuffer(image.mime);
|
|
85
84
|
}
|
|
86
85
|
return imageBuffer.buffer;
|
|
87
86
|
} catch (err) {
|
|
@@ -106,7 +105,6 @@ class BlurImage extends Operation {
|
|
|
106
105
|
|
|
107
106
|
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
|
108
107
|
}
|
|
109
|
-
|
|
110
108
|
}
|
|
111
109
|
|
|
112
110
|
export default BlurImage;
|