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.
- package/.devcontainer/devcontainer.json +1 -1
- package/.nvmrc +1 -1
- package/CHANGELOG.md +79 -0
- package/CONTRIBUTING.md +4 -1
- package/Dockerfile +2 -2
- package/Gruntfile.js +3 -17
- package/README.md +3 -3
- package/babel.config.js +4 -1
- package/package.json +31 -27
- package/src/core/ChefWorker.js +1 -1
- package/src/core/Recipe.mjs +1 -1
- package/src/core/config/Categories.json +2 -1
- package/src/core/config/OperationConfig.json +54 -3
- package/src/core/config/modules/Default.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/Extract.mjs +5 -0
- package/src/core/lib/Magic.mjs +1 -1
- package/src/core/lib/ParityBit.mjs +50 -0
- package/src/core/operations/AnalyseUUID.mjs +109 -6
- package/src/core/operations/ExtractEmailAddresses.mjs +2 -3
- package/src/core/operations/FromPunycode.mjs +1 -1
- package/src/core/operations/ParityBit.mjs +128 -0
- package/src/core/operations/RegularExpression.mjs +2 -1
- package/src/core/operations/RenderMarkdown.mjs +35 -4
- package/src/core/operations/ShowBase64Offsets.mjs +28 -28
- package/src/core/operations/ToPunycode.mjs +1 -1
- package/src/core/operations/index.mjs +2 -0
- package/src/node/NodeRecipe.mjs +8 -7
- package/src/node/api.mjs +4 -4
- package/src/node/index.mjs +5 -0
- package/src/web/HTMLOperation.mjs +8 -2
- package/src/web/html/index.html +1 -1
- package/src/web/index.js +2 -2
- package/src/web/static/sitemap.mjs +1 -1
- package/src/web/waiters/OperationsWaiter.mjs +30 -13
- package/tests/lib/wasmFetchPolyfill.mjs +31 -0
- package/tests/node/consumers/cjs-consumer.js +2 -2
- package/tests/node/consumers/esm-consumer.mjs +2 -2
- package/tests/node/tests/Categories.mjs +2 -2
- package/tests/node/tests/nodeApi.mjs +55 -58
- package/tests/node/tests/operations.mjs +2 -3
- package/tests/operations/index.mjs +6 -0
- package/tests/operations/tests/AnalyseUUID.mjs +66 -0
- package/tests/operations/tests/Base64.mjs +11 -0
- package/tests/operations/tests/ExtractEmailAddresses.mjs +38 -12
- package/tests/operations/tests/Fernet.mjs +18 -3
- package/tests/operations/tests/ParityBit.mjs +147 -0
- package/tests/operations/tests/RegularExpression.mjs +75 -0
- package/tests/operations/tests/RenderMarkdown.mjs +110 -0
|
@@ -43,17 +43,23 @@ class HTMLOperation {
|
|
|
43
43
|
/**
|
|
44
44
|
* Renders the operation in HTML as a stub operation with no ingredients.
|
|
45
45
|
*
|
|
46
|
+
* @param {boolean} removeIcon - show icon for removing operation
|
|
47
|
+
* @param {string} elementId - element ID for aria usage
|
|
46
48
|
* @returns {string}
|
|
47
49
|
*/
|
|
48
|
-
toStubHtml(removeIcon) {
|
|
50
|
+
toStubHtml(removeIcon = false, elementId = null) {
|
|
49
51
|
let html = "<li class='operation'";
|
|
50
52
|
|
|
53
|
+
if (elementId) {
|
|
54
|
+
html += ` id='${elementId}'`;
|
|
55
|
+
}
|
|
56
|
+
|
|
51
57
|
if (this.description) {
|
|
52
58
|
const infoLink = this.infoURL ? `<hr>${titleFromWikiLink(this.infoURL)}` : "";
|
|
53
59
|
|
|
54
60
|
html += ` data-container='body' data-toggle='popover' data-placement='right'
|
|
55
61
|
data-content="${this.description}${infoLink}" data-html='true' data-trigger='hover'
|
|
56
|
-
data-boundary='viewport'`;
|
|
62
|
+
data-boundary='viewport' role='button'`;
|
|
57
63
|
}
|
|
58
64
|
|
|
59
65
|
html += ">" + this.name;
|
package/src/web/html/index.html
CHANGED
|
@@ -173,7 +173,7 @@
|
|
|
173
173
|
Operations
|
|
174
174
|
<span class="op-count"></span>
|
|
175
175
|
</div>
|
|
176
|
-
<input id="search" type="search" class="form-control" placeholder="Search..." autocomplete="off" tabindex="0" data-help-title="Searching for operations" data-help="<p>Use the search box to find useful operations.</p><p>Both operation names and descriptions are queried using a fuzzy matching algorithm.</p>">
|
|
176
|
+
<input id="search" type="search" class="form-control" placeholder="Search..." autocomplete="off" tabindex="0" data-help-title="Searching for operations" data-help="<p>Use the search box to find useful operations.</p><p>Both operation names and descriptions are queried using a fuzzy matching algorithm.</p>" aria-owns="search-results">
|
|
177
177
|
<ul id="search-results" class="op-list"></ul>
|
|
178
178
|
<div id="categories" class="panel-group no-select"></div>
|
|
179
179
|
</div>
|
package/src/web/index.js
CHANGED
|
@@ -17,8 +17,8 @@ import * as CanvasComponents from "../core/lib/CanvasComponents.mjs";
|
|
|
17
17
|
|
|
18
18
|
// CyberChef
|
|
19
19
|
import App from "./App.mjs";
|
|
20
|
-
import Categories from "../core/config/Categories.json"
|
|
21
|
-
import OperationConfig from "../core/config/OperationConfig.json"
|
|
20
|
+
import Categories from "../core/config/Categories.json" with { type: "json" };
|
|
21
|
+
import OperationConfig from "../core/config/OperationConfig.json" with { type: "json" };
|
|
22
22
|
|
|
23
23
|
|
|
24
24
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import sm from "sitemap";
|
|
2
|
-
import OperationConfig from "../../core/config/OperationConfig.json"
|
|
2
|
+
import OperationConfig from "../../core/config/OperationConfig.json" with { type: "json" };
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Generates an XML sitemap for all CyberChef operations and a number of recipes.
|
|
@@ -28,17 +28,16 @@ class OperationsWaiter {
|
|
|
28
28
|
this.removeIntent = false;
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
|
|
32
31
|
/**
|
|
33
32
|
* Handler for search events.
|
|
34
33
|
* Finds operations which match the given search term and displays them under the search box.
|
|
35
34
|
*
|
|
36
|
-
* @param {
|
|
35
|
+
* @param {KeyboardEvent | ClipboardEvent | Event} e
|
|
37
36
|
*/
|
|
38
37
|
searchOperations(e) {
|
|
39
38
|
let ops, selected;
|
|
40
39
|
|
|
41
|
-
if (e.type === "search" || e.keyCode === 13) { // Search or Return
|
|
40
|
+
if ((e.type === "search" && e.target.value !== "") || e.keyCode === 13) { // Search (non-empty) or Return
|
|
42
41
|
e.preventDefault();
|
|
43
42
|
ops = document.querySelectorAll("#search-results li");
|
|
44
43
|
if (ops.length) {
|
|
@@ -49,27 +48,43 @@ class OperationsWaiter {
|
|
|
49
48
|
}
|
|
50
49
|
}
|
|
51
50
|
|
|
51
|
+
/**
|
|
52
|
+
* Sets up the operation element with the correct attributes when selected
|
|
53
|
+
* @param {HTMLElement} element
|
|
54
|
+
*/
|
|
55
|
+
const _selectOperation = (element) => {
|
|
56
|
+
element.classList.add("selected-op");
|
|
57
|
+
element.scrollIntoView({block: "nearest"});
|
|
58
|
+
$(element).popover("show");
|
|
59
|
+
e.target.setAttribute("aria-activedescendant", element.id);
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Sets up the operation element with the correct attributes when deselected
|
|
64
|
+
* @param {HTMLElement} element
|
|
65
|
+
*/
|
|
66
|
+
const _deselectOperation = (element) => {
|
|
67
|
+
element.classList.remove("selected-op");
|
|
68
|
+
$(element).popover("hide");
|
|
69
|
+
};
|
|
70
|
+
|
|
52
71
|
if (e.keyCode === 40) { // Down
|
|
53
72
|
e.preventDefault();
|
|
54
73
|
ops = document.querySelectorAll("#search-results li");
|
|
55
74
|
if (ops.length) {
|
|
56
75
|
selected = this.getSelectedOp(ops);
|
|
57
|
-
if (selected > -1)
|
|
58
|
-
ops[selected].classList.remove("selected-op");
|
|
59
|
-
}
|
|
76
|
+
if (selected > -1) _deselectOperation(ops[selected]);
|
|
60
77
|
if (selected === ops.length-1) selected = -1;
|
|
61
|
-
ops[selected+1]
|
|
78
|
+
_selectOperation(ops[selected+1]);
|
|
62
79
|
}
|
|
63
80
|
} else if (e.keyCode === 38) { // Up
|
|
64
81
|
e.preventDefault();
|
|
65
82
|
ops = document.querySelectorAll("#search-results li");
|
|
66
83
|
if (ops.length) {
|
|
67
84
|
selected = this.getSelectedOp(ops);
|
|
68
|
-
if (selected > -1)
|
|
69
|
-
ops[selected].classList.remove("selected-op");
|
|
70
|
-
}
|
|
85
|
+
if (selected > -1) _deselectOperation(ops[selected]);
|
|
71
86
|
if (selected === 0) selected = ops.length;
|
|
72
|
-
ops[selected-1]
|
|
87
|
+
_selectOperation(ops[selected-1]);
|
|
73
88
|
}
|
|
74
89
|
} else {
|
|
75
90
|
const searchResultsEl = document.getElementById("search-results");
|
|
@@ -83,11 +98,13 @@ class OperationsWaiter {
|
|
|
83
98
|
searchResultsEl.removeChild(searchResultsEl.firstChild);
|
|
84
99
|
}
|
|
85
100
|
|
|
101
|
+
document.querySelector("#search").removeAttribute("aria-activedescendant");
|
|
102
|
+
|
|
86
103
|
$("#categories .show").collapse("hide");
|
|
87
104
|
if (str) {
|
|
88
105
|
const matchedOps = this.filterOperations(str, true);
|
|
89
106
|
const matchedOpsHtml = matchedOps
|
|
90
|
-
.map(
|
|
107
|
+
.map((operation, idx) => operation.toStubHtml(false, `search-result-${idx}`))
|
|
91
108
|
.join("");
|
|
92
109
|
|
|
93
110
|
searchResultsEl.innerHTML = matchedOpsHtml;
|
|
@@ -103,7 +120,7 @@ class OperationsWaiter {
|
|
|
103
120
|
* @param {string} searchStr
|
|
104
121
|
* @param {boolean} highlight - Whether or not to highlight the matching string in the operation
|
|
105
122
|
* name and description
|
|
106
|
-
* @returns {
|
|
123
|
+
* @returns {HTMLOperation[]}
|
|
107
124
|
*/
|
|
108
125
|
filterOperations(inStr, highlight) {
|
|
109
126
|
const matchedOps = [];
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Polyfill for Node.js 22+ where globalThis.fetch is built-in but rejects
|
|
3
|
+
* bare filesystem paths. WASM libraries like argon2-browser call fetch() with
|
|
4
|
+
* an absolute path (e.g. "/path/to/argon2.wasm") expecting a browser-style
|
|
5
|
+
* fallback, but Node.js 22's fetch throws synchronously for non-URL strings.
|
|
6
|
+
*
|
|
7
|
+
* This wrapper intercepts such calls and serves the file via Node's fs module,
|
|
8
|
+
* returning a synthetic Response so the WASM module loads correctly.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { readFile } from "fs/promises";
|
|
12
|
+
|
|
13
|
+
if (globalThis.fetch) {
|
|
14
|
+
const originalFetch = globalThis.fetch;
|
|
15
|
+
globalThis.fetch = async function patchedFetch(url, options) {
|
|
16
|
+
const urlStr = typeof url === "string" ?
|
|
17
|
+
url :
|
|
18
|
+
url instanceof URL ?
|
|
19
|
+
url.href :
|
|
20
|
+
String(url);
|
|
21
|
+
// Intercept bare filesystem paths (absolute POSIX or Windows)
|
|
22
|
+
if (urlStr.startsWith("/") || /^[A-Za-z]:[/\\]/.test(urlStr)) {
|
|
23
|
+
const buffer = await readFile(urlStr);
|
|
24
|
+
return new Response(buffer, {
|
|
25
|
+
status: 200,
|
|
26
|
+
headers: { "Content-Type": "application/wasm" },
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
return originalFetch(url, options);
|
|
30
|
+
};
|
|
31
|
+
}
|
|
@@ -9,7 +9,7 @@ import assert from "assert";
|
|
|
9
9
|
import chef from "cyberchef";
|
|
10
10
|
import { bake, toHex, reverse, unique, multiply } from "cyberchef";
|
|
11
11
|
|
|
12
|
-
const a = bake("Testing, 1 2 3", [
|
|
12
|
+
const a = await bake("Testing, 1 2 3", [
|
|
13
13
|
toHex,
|
|
14
14
|
reverse,
|
|
15
15
|
{
|
|
@@ -28,7 +28,7 @@ const a = bake("Testing, 1 2 3", [
|
|
|
28
28
|
|
|
29
29
|
assert.equal(a.value, "630957449041920");
|
|
30
30
|
|
|
31
|
-
const b = chef.bake("Testing, 1 2 3", [
|
|
31
|
+
const b = await chef.bake("Testing, 1 2 3", [
|
|
32
32
|
chef.toHex,
|
|
33
33
|
chef.reverse,
|
|
34
34
|
{
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import TestRegister from "../../lib/TestRegister.mjs";
|
|
2
|
-
import Categories from "../../../src/core/config/Categories.json"
|
|
3
|
-
import OperationConfig from "../../../src/core/config/OperationConfig.json"
|
|
2
|
+
import Categories from "../../../src/core/config/Categories.json" with { type: "json" };
|
|
3
|
+
import OperationConfig from "../../../src/core/config/OperationConfig.json" with { type: "json" };
|
|
4
4
|
import it from "../assertionHandler.mjs";
|
|
5
5
|
import assert from "assert";
|
|
6
6
|
|
|
@@ -170,77 +170,77 @@ TestRegister.addApiTests([
|
|
|
170
170
|
assert(chef.bake);
|
|
171
171
|
}),
|
|
172
172
|
|
|
173
|
-
it("chef.bake: should return NodeDish", () => {
|
|
174
|
-
const result = chef.bake("input", "to base 64");
|
|
173
|
+
it("chef.bake: should return NodeDish", async () => {
|
|
174
|
+
const result = await chef.bake("input", "to base 64");
|
|
175
175
|
assert(result instanceof NodeDish);
|
|
176
176
|
}),
|
|
177
177
|
|
|
178
|
-
it("chef.bake: should take an input and an op name and perform it", () => {
|
|
179
|
-
const result = chef.bake("some input", "to base 32");
|
|
178
|
+
it("chef.bake: should take an input and an op name and perform it", async () => {
|
|
179
|
+
const result = await chef.bake("some input", "to base 32");
|
|
180
180
|
assert.strictEqual(result.toString(), "ONXW2ZJANFXHA5LU");
|
|
181
181
|
}),
|
|
182
182
|
|
|
183
|
-
it("chef.bake: should complain if recipe isnt a valid object", () => {
|
|
184
|
-
assert.
|
|
183
|
+
it("chef.bake: should complain if recipe isnt a valid object", async () => {
|
|
184
|
+
await assert.rejects(() => chef.bake("some input", 3264), {
|
|
185
185
|
name: "TypeError",
|
|
186
186
|
message: "Recipe can only contain function names or functions"
|
|
187
187
|
});
|
|
188
188
|
}),
|
|
189
189
|
|
|
190
|
-
it("chef.bake: Should complain if string op is invalid", () => {
|
|
191
|
-
assert.
|
|
190
|
+
it("chef.bake: Should complain if string op is invalid", async () => {
|
|
191
|
+
await assert.rejects(() => chef.bake("some input", "not a valid operation"), {
|
|
192
192
|
name: "TypeError",
|
|
193
193
|
message: "Couldn't find an operation with name 'not a valid operation'."
|
|
194
194
|
});
|
|
195
195
|
}),
|
|
196
196
|
|
|
197
|
-
it("chef.bake: Should take an input and an operation and perform it", () => {
|
|
198
|
-
const result = chef.bake("https://google.com/search?q=help", chef.parseURI);
|
|
197
|
+
it("chef.bake: Should take an input and an operation and perform it", async () => {
|
|
198
|
+
const result = await chef.bake("https://google.com/search?q=help", chef.parseURI);
|
|
199
199
|
assert.strictEqual(result.toString(), "Protocol:\thttps:\nHostname:\tgoogle.com\nPath name:\t/search\nArguments:\n\tq = help\n");
|
|
200
200
|
}),
|
|
201
201
|
|
|
202
|
-
it("chef.bake: Should complain if an invalid operation is inputted", () => {
|
|
203
|
-
assert.
|
|
202
|
+
it("chef.bake: Should complain if an invalid operation is inputted", async () => {
|
|
203
|
+
await assert.rejects(() => chef.bake("https://google.com/search?q=help", () => {}), {
|
|
204
204
|
name: "TypeError",
|
|
205
205
|
message: "Inputted function not a Chef operation."
|
|
206
206
|
});
|
|
207
207
|
}),
|
|
208
208
|
|
|
209
|
-
it("chef.bake: accepts an array of operation names and performs them all in order", () => {
|
|
210
|
-
const result = chef.bake("https://google.com/search?q=that's a complicated question", ["URL encode", "URL decode", "Parse URI"]);
|
|
209
|
+
it("chef.bake: accepts an array of operation names and performs them all in order", async () => {
|
|
210
|
+
const result = await chef.bake("https://google.com/search?q=that's a complicated question", ["URL encode", "URL decode", "Parse URI"]);
|
|
211
211
|
assert.strictEqual(result.toString(), "Protocol:\thttps:\nHostname:\tgoogle.com\nPath name:\t/search\nArguments:\n\tq = that's a complicated question\n");
|
|
212
212
|
}),
|
|
213
213
|
|
|
214
|
-
it("chef.bake: forgiving with operation names", () =>{
|
|
215
|
-
const result = chef.bake("https://google.com/search?q=that's a complicated question", ["urlencode", "url decode", "parseURI"]);
|
|
214
|
+
it("chef.bake: forgiving with operation names", async () =>{
|
|
215
|
+
const result = await chef.bake("https://google.com/search?q=that's a complicated question", ["urlencode", "url decode", "parseURI"]);
|
|
216
216
|
assert.strictEqual(result.toString(), "Protocol:\thttps:\nHostname:\tgoogle.com\nPath name:\t/search\nArguments:\n\tq = that's a complicated question\n");
|
|
217
217
|
}),
|
|
218
218
|
|
|
219
|
-
it("chef.bake: forgiving with operation names", () =>{
|
|
220
|
-
const result = chef.bake("hello", ["to base 64"]);
|
|
219
|
+
it("chef.bake: forgiving with operation names", async () =>{
|
|
220
|
+
const result = await chef.bake("hello", ["to base 64"]);
|
|
221
221
|
assert.strictEqual(result.toString(), "aGVsbG8=");
|
|
222
222
|
}),
|
|
223
223
|
|
|
224
|
-
it("chef.bake: if recipe is empty array, return input as dish", () => {
|
|
225
|
-
const result = chef.bake("some input", []);
|
|
224
|
+
it("chef.bake: if recipe is empty array, return input as dish", async () => {
|
|
225
|
+
const result = await chef.bake("some input", []);
|
|
226
226
|
assert.strictEqual(result.toString(), "some input");
|
|
227
227
|
assert(result instanceof NodeDish, "Result is not instance of NodeDish");
|
|
228
228
|
}),
|
|
229
229
|
|
|
230
|
-
it("chef.bake: accepts an array of operations as recipe", () => {
|
|
231
|
-
const result = chef.bake("https://google.com/search?q=that's a complicated question", [chef.URLEncode, chef.URLDecode, chef.parseURI]);
|
|
230
|
+
it("chef.bake: accepts an array of operations as recipe", async () => {
|
|
231
|
+
const result = await chef.bake("https://google.com/search?q=that's a complicated question", [chef.URLEncode, chef.URLDecode, chef.parseURI]);
|
|
232
232
|
assert.strictEqual(result.toString(), "Protocol:\thttps:\nHostname:\tgoogle.com\nPath name:\t/search\nArguments:\n\tq = that's a complicated question\n");
|
|
233
233
|
}),
|
|
234
234
|
|
|
235
|
-
it("should complain if an invalid operation is inputted as part of array", () => {
|
|
236
|
-
assert.
|
|
235
|
+
it("should complain if an invalid operation is inputted as part of array", async () => {
|
|
236
|
+
await assert.rejects(() => chef.bake("something", [() => {}]), {
|
|
237
237
|
name: "TypeError",
|
|
238
238
|
message: "Inputted function not a Chef operation."
|
|
239
239
|
});
|
|
240
240
|
}),
|
|
241
241
|
|
|
242
|
-
it("chef.bake: should take single JSON object describing op and args OBJ", () => {
|
|
243
|
-
const result = chef.bake("some input", {
|
|
242
|
+
it("chef.bake: should take single JSON object describing op and args OBJ", async () => {
|
|
243
|
+
const result = await chef.bake("some input", {
|
|
244
244
|
op: chef.toHex,
|
|
245
245
|
args: {
|
|
246
246
|
Delimiter: "Colon"
|
|
@@ -249,23 +249,23 @@ TestRegister.addApiTests([
|
|
|
249
249
|
assert.strictEqual(result.toString(), "73:6f:6d:65:20:69:6e:70:75:74");
|
|
250
250
|
}),
|
|
251
251
|
|
|
252
|
-
it("chef.bake: should take single JSON object desribing op with optional args", () => {
|
|
253
|
-
const result = chef.bake("some input", {
|
|
252
|
+
it("chef.bake: should take single JSON object desribing op with optional args", async () => {
|
|
253
|
+
const result = await chef.bake("some input", {
|
|
254
254
|
op: chef.toHex,
|
|
255
255
|
});
|
|
256
256
|
assert.strictEqual(result.toString(), "73 6f 6d 65 20 69 6e 70 75 74");
|
|
257
257
|
}),
|
|
258
258
|
|
|
259
|
-
it("chef.bake: should take single JSON object describing op and args ARRAY", () => {
|
|
260
|
-
const result = chef.bake("some input", {
|
|
259
|
+
it("chef.bake: should take single JSON object describing op and args ARRAY", async () => {
|
|
260
|
+
const result = await chef.bake("some input", {
|
|
261
261
|
op: chef.toHex,
|
|
262
262
|
args: ["Colon"]
|
|
263
263
|
});
|
|
264
264
|
assert.strictEqual(result.toString(), "73:6f:6d:65:20:69:6e:70:75:74");
|
|
265
265
|
}),
|
|
266
266
|
|
|
267
|
-
it("chef.bake: should error if op in JSON is not chef op", () => {
|
|
268
|
-
assert.
|
|
267
|
+
it("chef.bake: should error if op in JSON is not chef op", async () => {
|
|
268
|
+
await assert.rejects(() => chef.bake("some input", {
|
|
269
269
|
op: () => {},
|
|
270
270
|
args: ["Colon"],
|
|
271
271
|
}), {
|
|
@@ -274,8 +274,8 @@ TestRegister.addApiTests([
|
|
|
274
274
|
});
|
|
275
275
|
}),
|
|
276
276
|
|
|
277
|
-
it("chef.bake: should take multiple ops in JSON object form, some ops by string", () => {
|
|
278
|
-
const result = chef.bake("some input", [
|
|
277
|
+
it("chef.bake: should take multiple ops in JSON object form, some ops by string", async () => {
|
|
278
|
+
const result = await chef.bake("some input", [
|
|
279
279
|
{
|
|
280
280
|
op: chef.toHex,
|
|
281
281
|
args: ["Colon"]
|
|
@@ -290,8 +290,8 @@ TestRegister.addApiTests([
|
|
|
290
290
|
assert.strictEqual(result.toString(), "67;63;72;66;146;72;66;144;72;66;65;72;62;60;72;66;71;72;66;145;72;67;60;72;67;65;72;67;64");
|
|
291
291
|
}),
|
|
292
292
|
|
|
293
|
-
it("chef.bake: should take multiple ops in JSON object form, some without args", () => {
|
|
294
|
-
const result = chef.bake("some input", [
|
|
293
|
+
it("chef.bake: should take multiple ops in JSON object form, some without args", async () => {
|
|
294
|
+
const result = await chef.bake("some input", [
|
|
295
295
|
{
|
|
296
296
|
op: chef.toHex,
|
|
297
297
|
},
|
|
@@ -305,8 +305,8 @@ TestRegister.addApiTests([
|
|
|
305
305
|
assert.strictEqual(result.toString(), "67;63;40;66;146;40;66;144;40;66;65;40;62;60;40;66;71;40;66;145;40;67;60;40;67;65;40;67;64");
|
|
306
306
|
}),
|
|
307
307
|
|
|
308
|
-
it("chef.bake: should handle op with multiple args", () => {
|
|
309
|
-
const result = chef.bake("some input", {
|
|
308
|
+
it("chef.bake: should handle op with multiple args", async () => {
|
|
309
|
+
const result = await chef.bake("some input", {
|
|
310
310
|
op: "to morse code",
|
|
311
311
|
args: {
|
|
312
312
|
formatOptions: "Dash/Dot",
|
|
@@ -317,13 +317,13 @@ TestRegister.addApiTests([
|
|
|
317
317
|
assert.strictEqual(result.toString(), "DotDotDot\\DashDashDash\\DashDash\\Dot,DotDot\\DashDot\\DotDashDashDot\\DotDotDash\\Dash");
|
|
318
318
|
}),
|
|
319
319
|
|
|
320
|
-
it("chef.bake: should take compact JSON format from Chef Website as recipe", () => {
|
|
321
|
-
const result = chef.bake("some input", [{"op": "To Morse Code", "args": ["Dash/Dot", "Backslash", "Comma"]}, {"op": "Hex to PEM", "args": ["SOMETHING"]}, {"op": "To Snake case", "args": [false]}]);
|
|
320
|
+
it("chef.bake: should take compact JSON format from Chef Website as recipe", async () => {
|
|
321
|
+
const result = await chef.bake("some input", [{"op": "To Morse Code", "args": ["Dash/Dot", "Backslash", "Comma"]}, {"op": "Hex to PEM", "args": ["SOMETHING"]}, {"op": "To Snake case", "args": [false]}]);
|
|
322
322
|
assert.strictEqual(result.toString(), "begin_something_anananaaaaak_da_aaak_da_aaaaananaaaaaaan_da_aaaaaaanan_da_aaak_end_something");
|
|
323
323
|
}),
|
|
324
324
|
|
|
325
|
-
it("chef.bake: should accept Clean JSON format from Chef website as recipe", () => {
|
|
326
|
-
const result = chef.bake("some input", [
|
|
325
|
+
it("chef.bake: should accept Clean JSON format from Chef website as recipe", async () => {
|
|
326
|
+
const result = await chef.bake("some input", [
|
|
327
327
|
{ "op": "To Morse Code",
|
|
328
328
|
"args": ["Dash/Dot", "Backslash", "Comma"] },
|
|
329
329
|
{ "op": "Hex to PEM",
|
|
@@ -334,8 +334,8 @@ TestRegister.addApiTests([
|
|
|
334
334
|
assert.strictEqual(result.toString(), "begin_something_anananaaaaak_da_aaak_da_aaaaananaaaaaaan_da_aaaaaaanan_da_aaak_end_something");
|
|
335
335
|
}),
|
|
336
336
|
|
|
337
|
-
it("chef.bake: should accept Clean JSON format from Chef website - args optional", () => {
|
|
338
|
-
const result = chef.bake("some input", [
|
|
337
|
+
it("chef.bake: should accept Clean JSON format from Chef website - args optional", async () => {
|
|
338
|
+
const result = await chef.bake("some input", [
|
|
339
339
|
{ "op": "To Morse Code" },
|
|
340
340
|
{ "op": "Hex to PEM",
|
|
341
341
|
"args": ["SOMETHING"] },
|
|
@@ -345,31 +345,28 @@ TestRegister.addApiTests([
|
|
|
345
345
|
assert.strictEqual(result.toString(), "begin_something_aaaaaaaaaaaaaa_end_something");
|
|
346
346
|
}),
|
|
347
347
|
|
|
348
|
-
it("chef.bake: should accept operation names from Chef Website which contain forward slash", () => {
|
|
349
|
-
const result = chef.bake("I'll have the test salmon", [
|
|
348
|
+
it("chef.bake: should accept operation names from Chef Website which contain forward slash", async () => {
|
|
349
|
+
const result = await chef.bake("I'll have the test salmon", [
|
|
350
350
|
{ "op": "Find / Replace",
|
|
351
351
|
"args": [{ "option": "Regex", "string": "test" }, "good", true, false, true, false]}
|
|
352
352
|
]);
|
|
353
353
|
assert.strictEqual(result.toString(), "I'll have the good salmon");
|
|
354
354
|
}),
|
|
355
355
|
|
|
356
|
-
it("chef.bake: should accept operation names from Chef Website which contain a hyphen", () => {
|
|
357
|
-
const result = chef.bake("I'll have the test salmon", [
|
|
356
|
+
it("chef.bake: should accept operation names from Chef Website which contain a hyphen", async () => {
|
|
357
|
+
const result = await chef.bake("I'll have the test salmon", [
|
|
358
358
|
{ "op": "Adler-32 Checksum",
|
|
359
359
|
"args": [] }
|
|
360
360
|
]);
|
|
361
361
|
assert.strictEqual(result.toString(), "6e4208f8");
|
|
362
362
|
}),
|
|
363
363
|
|
|
364
|
-
it("chef.bake: should accept operation names from Chef Website which contain a period", () => {
|
|
365
|
-
const result = chef.bake("30 13 02 01 05 16 0e 41 6e 79 62 6f 64 79 20 74 68 65 72 65 3f", [
|
|
364
|
+
it("chef.bake: should accept operation names from Chef Website which contain a period", async () => {
|
|
365
|
+
const result = await chef.bake("30 13 02 01 05 16 0e 41 6e 79 62 6f 64 79 20 74 68 65 72 65 3f", [
|
|
366
366
|
{ "op": "Parse ASN.1 hex string",
|
|
367
367
|
"args": [0, 32] }
|
|
368
368
|
]);
|
|
369
|
-
assert.strictEqual(result.toString(), `SEQUENCE
|
|
370
|
-
INTEGER 05
|
|
371
|
-
IA5String 'Anybody there?'
|
|
372
|
-
`);
|
|
369
|
+
assert.strictEqual(result.toString(), `SEQUENCE\n INTEGER 05\n IA5String 'Anybody there?'\n`);
|
|
373
370
|
}),
|
|
374
371
|
|
|
375
372
|
it("Excluded operations: throw a sensible error when you try and call one", () => {
|
|
@@ -381,16 +378,16 @@ TestRegister.addApiTests([
|
|
|
381
378
|
}
|
|
382
379
|
}),
|
|
383
380
|
|
|
384
|
-
it("chef.bake: cannot accept flowControl operations in recipe", () => {
|
|
385
|
-
assert.
|
|
381
|
+
it("chef.bake: cannot accept flowControl operations in recipe", async () => {
|
|
382
|
+
await assert.rejects(() => chef.bake("some input", "magic"), {
|
|
386
383
|
name: "TypeError",
|
|
387
384
|
message: "flowControl operations like Magic are not currently allowed in recipes for chef.bake in the Node API"
|
|
388
385
|
});
|
|
389
|
-
assert.
|
|
386
|
+
await assert.rejects(() => chef.bake("some input", magic), {
|
|
390
387
|
name: "TypeError",
|
|
391
388
|
message: "flowControl operations like Magic are not currently allowed in recipes for chef.bake in the Node API"
|
|
392
389
|
});
|
|
393
|
-
assert.
|
|
390
|
+
await assert.rejects(() => chef.bake("some input", ["to base 64", "magic"]), {
|
|
394
391
|
name: "TypeError",
|
|
395
392
|
message: "flowControl operations like Magic are not currently allowed in recipes for chef.bake in the Node API"
|
|
396
393
|
});
|
|
@@ -589,8 +589,7 @@ Password: 282760`;
|
|
|
589
589
|
...[1, 3, 4, 5, 6, 7].map(version => it(`Analyze UUID v${version}`, () => {
|
|
590
590
|
const uuid = chef.generateUUID("", { "version": `v${version}` }).toString();
|
|
591
591
|
const result = chef.analyseUUID(uuid).toString();
|
|
592
|
-
|
|
593
|
-
assert.strictEqual(result, expected);
|
|
592
|
+
assert.ok(result.startsWith(`Version:\n${version}\n`), `Expected output to start with "Version:\\n${version}\\n", got: ${result}`);
|
|
594
593
|
})),
|
|
595
594
|
|
|
596
595
|
it("Generate UUID using defaults", () => {
|
|
@@ -598,7 +597,7 @@ Password: 282760`;
|
|
|
598
597
|
assert.ok(uuid);
|
|
599
598
|
|
|
600
599
|
const analysis = chef.analyseUUID(uuid).toString();
|
|
601
|
-
assert.
|
|
600
|
+
assert.ok(analysis.startsWith("Version:\n4\n"), `Expected output to start with "Version:\\n4\\n", got: ${analysis}`);
|
|
602
601
|
}),
|
|
603
602
|
|
|
604
603
|
it("Gzip, Gunzip", () => {
|
|
@@ -11,11 +11,13 @@
|
|
|
11
11
|
* @license Apache-2.0
|
|
12
12
|
*/
|
|
13
13
|
|
|
14
|
+
import "../lib/wasmFetchPolyfill.mjs";
|
|
14
15
|
import { setLongTestFailure, logTestReport } from "../lib/utils.mjs";
|
|
15
16
|
|
|
16
17
|
import TestRegister from "../lib/TestRegister.mjs";
|
|
17
18
|
import "./tests/A1Z26CipherDecode.mjs";
|
|
18
19
|
import "./tests/AESKeyWrap.mjs";
|
|
20
|
+
import "./tests/AnalyseUUID.mjs";
|
|
19
21
|
import "./tests/AlternatingCaps.mjs";
|
|
20
22
|
import "./tests/AvroToJSON.mjs";
|
|
21
23
|
import "./tests/BaconCipher.mjs";
|
|
@@ -71,6 +73,7 @@ import "./tests/ExtractAudioMetadata.mjs";
|
|
|
71
73
|
import "./tests/ExtractEmailAddresses.mjs";
|
|
72
74
|
import "./tests/ExtractHashes.mjs";
|
|
73
75
|
import "./tests/ExtractIPAddresses.mjs";
|
|
76
|
+
import "./tests/Fernet.mjs";
|
|
74
77
|
import "./tests/Float.mjs";
|
|
75
78
|
import "./tests/FileTree.mjs";
|
|
76
79
|
import "./tests/FletcherChecksum.mjs";
|
|
@@ -134,6 +137,7 @@ import "./tests/ParseUDP.mjs";
|
|
|
134
137
|
import "./tests/PEMtoHex.mjs";
|
|
135
138
|
import "./tests/PGP.mjs";
|
|
136
139
|
import "./tests/PHP.mjs";
|
|
140
|
+
import "./tests/ParityBit.mjs";
|
|
137
141
|
import "./tests/PHPSerialize.mjs";
|
|
138
142
|
import "./tests/PowerSet.mjs";
|
|
139
143
|
import "./tests/Protobuf.mjs";
|
|
@@ -143,6 +147,8 @@ import "./tests/Rabbit.mjs";
|
|
|
143
147
|
import "./tests/RAKE.mjs";
|
|
144
148
|
import "./tests/Regex.mjs";
|
|
145
149
|
import "./tests/Register.mjs";
|
|
150
|
+
import "./tests/RegularExpression.mjs";
|
|
151
|
+
import "./tests/RenderMarkdown.mjs";
|
|
146
152
|
import "./tests/RisonEncodeDecode.mjs";
|
|
147
153
|
import "./tests/Rotate.mjs";
|
|
148
154
|
import "./tests/RSA.mjs";
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Analyse UUID tests
|
|
3
|
+
*
|
|
4
|
+
* @author ko80240 [csk.dev@proton.me]
|
|
5
|
+
* @copyright Crown Copyright 2023
|
|
6
|
+
* @license Apache-2.0
|
|
7
|
+
*/
|
|
8
|
+
import TestRegister from "../../lib/TestRegister.mjs";
|
|
9
|
+
|
|
10
|
+
TestRegister.addTests([
|
|
11
|
+
{
|
|
12
|
+
"name": "Analyse UUID: v1 UUID extracts timestamp, clock, and node",
|
|
13
|
+
"input": "cefa1760-28ee-11f1-9f95-1fb76af3e239",
|
|
14
|
+
"expectedOutput": "Version:\n1\n\nTimestamp:\n1774514156502\n\nTimestamp (ISO):\n2026-03-26T08:35:56.502Z\n\nNode:\n1F:B7:6A:F3:E2:39\n\nClock:\n8085\n\nUUID Integer:\n275119515460318071558429785403790975545",
|
|
15
|
+
"recipeConfig": [
|
|
16
|
+
{
|
|
17
|
+
"op": "Analyse UUID",
|
|
18
|
+
"args": [true]
|
|
19
|
+
}
|
|
20
|
+
]
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
"name": "Analyse UUID: v7 UUID extracts timestamp, randA, and randB",
|
|
24
|
+
"input": "019d294a-af64-7728-9524-26da08f50708",
|
|
25
|
+
"expectedOutput": "Version:\n7\n\nTimestamp:\n1774514253668\n\nTimestamp (ISO):\n2026-03-26T08:37:33.668Z\n\nRand A:\n1832\n\nRand B:\n952426DA08F50708\n\nUUID Integer:\n2145256098533991595556290452700595976",
|
|
26
|
+
"recipeConfig": [
|
|
27
|
+
{
|
|
28
|
+
"op": "Analyse UUID",
|
|
29
|
+
"args": [true]
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"name": "Analyse UUID: v4 UUID should show no metadata - not possible",
|
|
35
|
+
"input": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
|
|
36
|
+
"expectedOutput": "Version:\n4\n\nNo metadata available. Only versions 1, 6, 7 are supported.\n\nUUID Integer:\n324969006592305634633390616021200786553",
|
|
37
|
+
"recipeConfig": [
|
|
38
|
+
{
|
|
39
|
+
"op": "Analyse UUID",
|
|
40
|
+
"args": [true]
|
|
41
|
+
}
|
|
42
|
+
]
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
"name": "Analyse UUID: if the 'Include Metadata' option is false it should return not metadata",
|
|
46
|
+
"input": "cefa1760-28ee-11f1-9f95-1fb76af3e239",
|
|
47
|
+
"expectedOutput": "Version:\n1\n\nUUID Integer:\n275119515460318071558429785403790975545",
|
|
48
|
+
"recipeConfig": [
|
|
49
|
+
{
|
|
50
|
+
"op": "Analyse UUID",
|
|
51
|
+
"args": [false]
|
|
52
|
+
}
|
|
53
|
+
]
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
"name": "Analyse UUID: invalid UUID should return error message",
|
|
57
|
+
"input": "not-a-uuid",
|
|
58
|
+
"expectedOutput": "Invalid UUID",
|
|
59
|
+
"recipeConfig": [
|
|
60
|
+
{
|
|
61
|
+
"op": "Analyse UUID",
|
|
62
|
+
"args": [true]
|
|
63
|
+
}
|
|
64
|
+
]
|
|
65
|
+
}
|
|
66
|
+
]);
|
|
@@ -116,4 +116,15 @@ TestRegister.addTests([
|
|
|
116
116
|
},
|
|
117
117
|
],
|
|
118
118
|
},
|
|
119
|
+
{
|
|
120
|
+
name: "Show Base64 offsets: escapes static output",
|
|
121
|
+
input: "\x00\x10\x83\x10\x51\x87",
|
|
122
|
+
expectedOutput: "<script>\n<AQmsBRk66\n<ia1AEIM6",
|
|
123
|
+
recipeConfig: [
|
|
124
|
+
{
|
|
125
|
+
op: "Show Base64 offsets",
|
|
126
|
+
args: ["<script>ale(1)/.ABCDEFGHIJKLMNOPQRSTUVWXYZbdfghjkmnoquvwxyz023456", false, "Raw"],
|
|
127
|
+
},
|
|
128
|
+
],
|
|
129
|
+
},
|
|
119
130
|
]);
|