cyberchef 11.2.0 → 11.3.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/AGENTS.md +75 -0
- package/CHANGELOG.md +147 -1
- package/Dockerfile +2 -2
- package/Gruntfile.js +1 -0
- package/package.json +22 -21
- package/src/core/Dish.mjs +1 -5
- package/src/core/Ingredient.mjs +92 -0
- package/src/core/Operation.mjs +19 -0
- package/src/core/Recipe.mjs +4 -0
- package/src/core/Utils.mjs +48 -0
- package/src/core/config/Categories.json +22 -6
- package/src/core/config/OperationConfig.json +4771 -1226
- package/src/core/config/modules/Ciphers.mjs +20 -0
- package/src/core/config/modules/Crypto.mjs +10 -0
- package/src/core/config/modules/Default.mjs +8 -0
- package/src/core/config/modules/File.mjs +16 -0
- package/src/core/config/modules/OpModules.mjs +2 -0
- package/src/core/config/scripts/generateHTMLEntities.mjs +139 -0
- package/src/core/config/scripts/htmlEntityOverrides.mjs +86 -0
- package/src/core/lib/Arithmetic.mjs +21 -5
- package/src/core/lib/BigIntUtils.mjs +0 -1
- package/src/core/lib/COBS.mjs +86 -0
- package/src/core/lib/Decimal.mjs +5 -5
- package/src/core/lib/HTMLEntities.mjs +2068 -0
- package/src/core/lib/Present.mjs +422 -0
- package/src/core/lib/TEA.mjs +494 -0
- package/src/core/lib/TLVParser.mjs +16 -7
- package/src/core/lib/Twofish.mjs +608 -0
- package/src/core/operations/AsconDecrypt.mjs +112 -0
- package/src/core/operations/AsconEncrypt.mjs +108 -0
- package/src/core/operations/AsconHash.mjs +49 -0
- package/src/core/operations/AsconMAC.mjs +68 -0
- package/src/core/operations/AutomatedValidationTestOp.mjs +84 -0
- package/src/core/operations/AvroToJSON.mjs +1 -1
- package/src/core/operations/BLAKE3.mjs +5 -1
- package/src/core/operations/BcryptCompare.mjs +11 -5
- package/src/core/operations/BitShiftLeft.mjs +4 -1
- package/src/core/operations/Bzip2Compress.mjs +1 -1
- package/src/core/operations/DechunkHTTPResponse.mjs +4 -1
- package/src/core/operations/ExtendedGCD.mjs +101 -0
- package/src/core/operations/FromBase.mjs +2 -1
- package/src/core/operations/FromCOBS.mjs +38 -0
- package/src/core/operations/FromDecimal.mjs +6 -1
- package/src/core/operations/FromHTMLEntity.mjs +2 -1458
- package/src/core/operations/GenerateHOTP.mjs +21 -6
- package/src/core/operations/GenerateImage.mjs +22 -10
- package/src/core/operations/GeneratePrime.mjs +154 -0
- package/src/core/operations/GenerateTOTP.mjs +24 -7
- package/src/core/operations/Gzip.mjs +1 -3
- package/src/core/operations/Jsonata.mjs +12 -0
- package/src/core/operations/MIMEDecoding.mjs +1 -1
- package/src/core/operations/MOD.mjs +62 -0
- package/src/core/operations/ModularInverse.mjs +107 -0
- package/src/core/operations/PRESENTDecrypt.mjs +94 -0
- package/src/core/operations/PRESENTEncrypt.mjs +94 -0
- package/src/core/operations/ParseURI.mjs +18 -5
- package/src/core/operations/PseudoRandomNumberGenerator.mjs +2 -1
- package/src/core/operations/RandomPrime.mjs +154 -0
- package/src/core/operations/RenderPDF.mjs +100 -0
- package/src/core/operations/SM4Encrypt.mjs +1 -1
- package/src/core/operations/SetDifference.mjs +8 -1
- package/src/core/operations/SetIntersection.mjs +8 -1
- package/src/core/operations/ShowOnMap.mjs +14 -2
- package/src/core/operations/TEADecrypt.mjs +98 -0
- package/src/core/operations/TEAEncrypt.mjs +98 -0
- package/src/core/operations/ToBase.mjs +4 -4
- package/src/core/operations/ToBase32.mjs +20 -4
- package/src/core/operations/ToBinary.mjs +4 -1
- package/src/core/operations/ToCOBS.mjs +38 -0
- package/src/core/operations/ToHTMLEntity.mjs +7 -1430
- package/src/core/operations/TwofishDecrypt.mjs +94 -0
- package/src/core/operations/TwofishEncrypt.mjs +94 -0
- package/src/core/operations/URLEncode.mjs +22 -18
- package/src/core/operations/UnescapeUnicodeCharacters.mjs +2 -1
- package/src/core/operations/ViewBitPlane.mjs +9 -3
- package/src/core/operations/Wrap.mjs +5 -0
- package/src/core/operations/XORBruteForce.mjs +4 -1
- package/src/core/operations/XORChecksum.mjs +2 -2
- package/src/core/operations/XTEADecrypt.mjs +110 -0
- package/src/core/operations/XTEAEncrypt.mjs +110 -0
- package/src/core/operations/index.mjs +42 -0
- package/src/core/vendor/ascon.mjs +162 -0
- package/src/core/vendor/htmlEntities/entity.json +2233 -0
- package/src/core/vendor/htmlEntities/entity.txt +14 -0
- package/src/node/api.mjs +4 -1
- package/src/node/index.mjs +105 -0
- package/src/web/HTMLOperation.mjs +2 -1
- package/src/web/stylesheets/layout/_io.css +8 -0
- package/tests/browser/00_nightwatch.js +26 -0
- package/tests/browser/02_ops.js +20 -4
- package/tests/node/index.mjs +1 -0
- package/tests/node/tests/Dish.mjs +19 -0
- package/tests/node/tests/NodeDish.mjs +36 -0
- package/tests/node/tests/ToHTMLEntity.mjs +82 -0
- package/tests/node/tests/Utils.mjs +77 -0
- package/tests/node/tests/nodeApi.mjs +33 -1
- package/tests/node/tests/operations.mjs +26 -1
- package/tests/operations/index.mjs +17 -0
- package/tests/operations/tests/Arithmetic.mjs +33 -0
- package/tests/operations/tests/Ascon.mjs +501 -0
- package/tests/operations/tests/AutomatedValidation.mjs +154 -0
- package/tests/operations/tests/BLAKE3.mjs +39 -1
- package/tests/operations/tests/Base32.mjs +22 -0
- package/tests/operations/tests/COBS.mjs +476 -0
- package/tests/operations/tests/CharEnc.mjs +2 -2
- package/tests/operations/tests/DechunkHTTPResponse.mjs +66 -0
- package/tests/operations/tests/ExtendedGCD.mjs +78 -0
- package/tests/operations/tests/FromBase.mjs +66 -0
- package/tests/operations/tests/FromDecimal.mjs +55 -0
- package/tests/operations/tests/GenerateLoremIpsum.mjs +2 -2
- package/tests/operations/tests/Gzip.mjs +60 -0
- package/tests/operations/tests/HTMLEntity.mjs +126 -0
- package/tests/operations/tests/Hash.mjs +44 -0
- package/tests/operations/tests/Hexdump.mjs +1 -1
- package/tests/operations/tests/Image.mjs +26 -0
- package/tests/operations/tests/Jsonata.mjs +23 -0
- package/tests/operations/tests/MIMEDecoding.mjs +33 -0
- package/tests/operations/tests/MOD.mjs +208 -0
- package/tests/operations/tests/Median.mjs +33 -0
- package/tests/operations/tests/ModularInverse.mjs +78 -0
- package/tests/operations/tests/OTP.mjs +167 -2
- package/tests/operations/tests/PRESENT.mjs +465 -0
- package/tests/operations/tests/ParseTLV.mjs +41 -0
- package/tests/operations/tests/RenderPDF.mjs +55 -0
- package/tests/operations/tests/SM2.mjs +1 -1
- package/tests/operations/tests/SetDifference.mjs +22 -0
- package/tests/operations/tests/SetIntersection.mjs +23 -1
- package/tests/operations/tests/ShowOnMap.mjs +61 -0
- package/tests/operations/tests/TEA.mjs +566 -0
- package/tests/operations/tests/Twofish.mjs +486 -0
- package/tests/operations/tests/URLEncodeDecode.mjs +26 -0
- package/tests/operations/tests/UnescapeUnicodeCharacters.mjs +88 -0
- package/tests/operations/tests/Wrap.mjs +44 -0
- package/webpack.config.js +3 -3
package/tests/node/index.mjs
CHANGED
|
@@ -24,6 +24,7 @@ import "./tests/Dish.mjs";
|
|
|
24
24
|
import "./tests/NodeDish.mjs";
|
|
25
25
|
import "./tests/Utils.mjs";
|
|
26
26
|
import "./tests/Categories.mjs";
|
|
27
|
+
import "./tests/ToHTMLEntity.mjs";
|
|
27
28
|
import "./tests/lib/BigIntUtils.mjs";
|
|
28
29
|
import "./tests/lib/ChartsProtocolPrototypePollution.mjs";
|
|
29
30
|
|
|
@@ -9,4 +9,23 @@ TestRegister.addApiTests([
|
|
|
9
9
|
assert(dish.presentAs);
|
|
10
10
|
}),
|
|
11
11
|
|
|
12
|
+
it("Disk - should not error on serialized BigNumber (0)", () => {
|
|
13
|
+
const dish = new Dish({ s: 1, e: 0, c: [0] }, Dish.BIG_NUMBER);
|
|
14
|
+
assert.strictEqual(dish.value.toString(), "0");
|
|
15
|
+
}),
|
|
16
|
+
|
|
17
|
+
it("Dish - should not error on serialized BigNumber (1)", () => {
|
|
18
|
+
const dish = new Dish({ c: [1], e: 0, s: 1 }, Dish.BIG_NUMBER);
|
|
19
|
+
assert.strictEqual(dish.value.toString(), "1");
|
|
20
|
+
}),
|
|
21
|
+
|
|
22
|
+
it("Dish - should not error on serialized BigNumber (-100)", () => {
|
|
23
|
+
const dish = new Dish({ s: -1, e: 2, c: [100] }, Dish.BIG_NUMBER);
|
|
24
|
+
assert.strictEqual(dish.value.toString(), "-100");
|
|
25
|
+
}),
|
|
26
|
+
|
|
27
|
+
it("Dish - should not error on serialized BigNumber (NaN)", () => {
|
|
28
|
+
const dish = new Dish({ s: null, e: null, c: null }, Dish.BIG_NUMBER);
|
|
29
|
+
assert.strictEqual(dish.value.toString(), "NaN");
|
|
30
|
+
}),
|
|
12
31
|
]);
|
|
@@ -65,6 +65,42 @@ TestRegister.addApiTests([
|
|
|
65
65
|
assert.strictEqual(result.toString(), "493e8136b759370a415ef2cf2f7a69690441ff86592aba082bc2e2e0");
|
|
66
66
|
}),
|
|
67
67
|
|
|
68
|
+
it("Composable Dish: toBase32 should support non-BMP Unicode alphabets", () => {
|
|
69
|
+
const alphabet = "🀇🀈🀉🀊🀋🀌🀍🀎🀏🀙🀚🀛🀜🀝🀞🀟🀠🀡🀐🀑🀒🀓🀔🀕🀖🀗🀘🀀🀁🀂🀃🀅";
|
|
70
|
+
|
|
71
|
+
const result = new Dish("hello")
|
|
72
|
+
.apply(toBase32, {alphabet})
|
|
73
|
+
.toString();
|
|
74
|
+
|
|
75
|
+
// Should not contain replacement characters
|
|
76
|
+
assert.equal(result.includes("�"), false);
|
|
77
|
+
|
|
78
|
+
// Should contain only symbols from the alphabet
|
|
79
|
+
for (const ch of Array.from(result)) {
|
|
80
|
+
assert.ok(Array.from(alphabet).includes(ch));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// "hello" => 8 Base32 symbols
|
|
84
|
+
assert.equal(Array.from(result).length, 8);
|
|
85
|
+
}),
|
|
86
|
+
|
|
87
|
+
it("Composable Dish: toBase32 should omit padding for 32-character Unicode alphabets", () => {
|
|
88
|
+
const alphabet = "🀇🀈🀉🀊🀋🀌🀍🀎🀏🀙🀚🀛🀜🀝🀞🀟🀠🀡🀐🀑🀒🀓🀔🀕🀖🀗🀘🀀🀁🀂🀃🀅";
|
|
89
|
+
|
|
90
|
+
const result = new Dish("hell")
|
|
91
|
+
.apply(toBase32, {alphabet})
|
|
92
|
+
.toString();
|
|
93
|
+
|
|
94
|
+
// Should not leak undefined from array indexing
|
|
95
|
+
assert.equal(result.includes("undefined"), false);
|
|
96
|
+
|
|
97
|
+
// Should not contain replacement characters
|
|
98
|
+
assert.equal(result.includes("�"), false);
|
|
99
|
+
|
|
100
|
+
// Unpadded Base32 output for 4-byte input should be 7 symbols
|
|
101
|
+
assert.equal(Array.from(result).length, 7);
|
|
102
|
+
}),
|
|
103
|
+
|
|
68
104
|
it("Dish translation: ArrayBuffer to ArrayBuffer", () => {
|
|
69
105
|
const dish = new Dish(new ArrayBuffer(10), 4);
|
|
70
106
|
dish.get("array buffer");
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import TestRegister from "../../lib/TestRegister.mjs";
|
|
2
|
+
import ToHTMLEntity from "../../../src/core/operations/ToHTMLEntity.mjs";
|
|
3
|
+
import FromHTMLEntity from "../../../src/core/operations/FromHTMLEntity.mjs";
|
|
4
|
+
import { HTML_ENTITY_LOOKUP, HTML_ENTITY_REVERSE_LOOKUP } from "../../../src/core/lib/HTMLEntities.mjs";
|
|
5
|
+
import it from "../assertionHandler.mjs";
|
|
6
|
+
import assert from "assert";
|
|
7
|
+
import { readFileSync } from "fs";
|
|
8
|
+
import { fileURLToPath } from "url";
|
|
9
|
+
import path from "path";
|
|
10
|
+
|
|
11
|
+
// Vendored WHATWG named character reference set (https://html.spec.whatwg.org/entities.json).
|
|
12
|
+
const SPEC = JSON.parse(readFileSync(path.join(
|
|
13
|
+
path.dirname(fileURLToPath(import.meta.url)),
|
|
14
|
+
"../../../src/core/vendor/htmlEntities/entity.json"), "utf8"));
|
|
15
|
+
const specByName = {};
|
|
16
|
+
for (const [key, val] of Object.entries(SPEC))
|
|
17
|
+
if (key.endsWith(";")) specByName[key.slice(1, -1)] = val.codepoints;
|
|
18
|
+
|
|
19
|
+
TestRegister.addApiTests([
|
|
20
|
+
it("To HTML Entity: every named entity in the table is well-formed", () => {
|
|
21
|
+
// "Convert all characters" emits an entity for every code point, so a
|
|
22
|
+
// correct table yields an unbroken stream of entity tokens. A malformed
|
|
23
|
+
// value such as "≱;" or "ε," leaves stray characters between
|
|
24
|
+
// tokens, which the walk below flags and reports with surrounding context.
|
|
25
|
+
let input = "";
|
|
26
|
+
for (let cp = 0; cp <= 0xFFFF; cp++) {
|
|
27
|
+
if (cp >= 0xD800 && cp <= 0xDFFF) continue; // skip surrogate range
|
|
28
|
+
input += String.fromCodePoint(cp);
|
|
29
|
+
}
|
|
30
|
+
const output = new ToHTMLEntity().run(input, [true, "Named entities"]);
|
|
31
|
+
|
|
32
|
+
const tokenRe = /&#[0-9]+;|&#x[0-9a-fA-F]+;|&[A-Za-z][A-Za-z0-9]*;/y;
|
|
33
|
+
const malformed = [];
|
|
34
|
+
let pos = 0;
|
|
35
|
+
while (pos < output.length) {
|
|
36
|
+
tokenRe.lastIndex = pos;
|
|
37
|
+
if (tokenRe.exec(output)) {
|
|
38
|
+
pos = tokenRe.lastIndex;
|
|
39
|
+
} else {
|
|
40
|
+
malformed.push(output.slice(Math.max(0, pos - 12), pos + 12));
|
|
41
|
+
pos++;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
assert.deepStrictEqual(malformed, [], `Malformed entity value(s) near: ${JSON.stringify(malformed)}`);
|
|
45
|
+
}),
|
|
46
|
+
|
|
47
|
+
it("HTML Entity: named encoding round-trips through From HTML Entity", () => {
|
|
48
|
+
// Because both operations share one lookup table, encoding a character to
|
|
49
|
+
// a named entity and decoding it must return the original character for
|
|
50
|
+
// every BMP code point: FromHTMLEntity(ToHTMLEntity(x)) === x.
|
|
51
|
+
const toOp = new ToHTMLEntity(),
|
|
52
|
+
fromOp = new FromHTMLEntity();
|
|
53
|
+
const mismatches = [];
|
|
54
|
+
for (let cp = 0; cp <= 0xFFFF; cp++) {
|
|
55
|
+
if (cp >= 0xD800 && cp <= 0xDFFF) continue; // skip surrogate range
|
|
56
|
+
const char = String.fromCodePoint(cp);
|
|
57
|
+
const encoded = toOp.run(char, [true, "Named entities"]);
|
|
58
|
+
const decoded = fromOp.run(encoded, []);
|
|
59
|
+
if (decoded !== char)
|
|
60
|
+
mismatches.push(`U+${cp.toString(16).toUpperCase().padStart(4, "0")} -> ${encoded} -> U+${decoded.codePointAt(0).toString(16).toUpperCase()}`);
|
|
61
|
+
}
|
|
62
|
+
assert.deepStrictEqual(mismatches, [], `Round-trip failed for: ${JSON.stringify(mismatches.slice(0, 20))}`);
|
|
63
|
+
}),
|
|
64
|
+
|
|
65
|
+
it("HTML Entity: every table entry is conformant with the WHATWG spec", () => {
|
|
66
|
+
// Both lookup tables must agree with entities.json: every encode name is a
|
|
67
|
+
// real spec name mapping to exactly that code point, and every decode name
|
|
68
|
+
// maps to the spec code point.
|
|
69
|
+
const violations = [];
|
|
70
|
+
for (const [cp, name] of Object.entries(HTML_ENTITY_LOOKUP)) {
|
|
71
|
+
const spec = specByName[name];
|
|
72
|
+
if (!spec || spec.length !== 1 || spec[0] !== Number(cp))
|
|
73
|
+
violations.push(`encode ${cp} -> &${name}; (spec: ${spec ? JSON.stringify(spec) : "none"})`);
|
|
74
|
+
}
|
|
75
|
+
for (const [name, cp] of Object.entries(HTML_ENTITY_REVERSE_LOOKUP)) {
|
|
76
|
+
const spec = specByName[name];
|
|
77
|
+
if (!spec || spec.length !== 1 || spec[0] !== cp)
|
|
78
|
+
violations.push(`decode &${name}; -> ${cp} (spec: ${spec ? JSON.stringify(spec) : "none"})`);
|
|
79
|
+
}
|
|
80
|
+
assert.deepStrictEqual(violations, [], `Spec violations: ${JSON.stringify(violations.slice(0, 20))}`);
|
|
81
|
+
}),
|
|
82
|
+
]);
|
|
@@ -26,4 +26,81 @@ TestRegister.addApiTests([
|
|
|
26
26
|
"\x7e...",
|
|
27
27
|
);
|
|
28
28
|
}),
|
|
29
|
+
|
|
30
|
+
it("Utils: should parse normal pretty recipes", () => {
|
|
31
|
+
assert.deepStrictEqual(
|
|
32
|
+
Utils.parseRecipeConfig("From_Base64('A-Za-z0-9+/=',true)To_Hex('Space')"),
|
|
33
|
+
[
|
|
34
|
+
{
|
|
35
|
+
op: "From Base64",
|
|
36
|
+
args: ["A-Za-z0-9+/=", true],
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
op: "To Hex",
|
|
40
|
+
args: ["Space"],
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
);
|
|
44
|
+
}),
|
|
45
|
+
|
|
46
|
+
it("Utils: should parse pretty recipe options", () => {
|
|
47
|
+
assert.deepStrictEqual(
|
|
48
|
+
Utils.parseRecipeConfig("A(/disabled/breakpoint)"),
|
|
49
|
+
[
|
|
50
|
+
{
|
|
51
|
+
op: "A",
|
|
52
|
+
args: [],
|
|
53
|
+
disabled: true,
|
|
54
|
+
breakpoint: true,
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
);
|
|
58
|
+
}),
|
|
59
|
+
|
|
60
|
+
it("Utils: should parse escaped quotes and backslashes in pretty recipes", () => {
|
|
61
|
+
assert.deepStrictEqual(
|
|
62
|
+
Utils.parseRecipeConfig("A('\\'\\\\')"),
|
|
63
|
+
[
|
|
64
|
+
{
|
|
65
|
+
op: "A",
|
|
66
|
+
args: ["'\\"],
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
);
|
|
70
|
+
}),
|
|
71
|
+
|
|
72
|
+
it("Utils: should parse large valid quoted pretty recipe arguments", () => {
|
|
73
|
+
const value = "x".repeat(10000);
|
|
74
|
+
|
|
75
|
+
assert.deepStrictEqual(
|
|
76
|
+
Utils.parseRecipeConfig(`A('${value}')`),
|
|
77
|
+
[
|
|
78
|
+
{
|
|
79
|
+
op: "A",
|
|
80
|
+
args: [value],
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
);
|
|
84
|
+
}),
|
|
85
|
+
|
|
86
|
+
it("Utils: should reject malformed pretty recipes with unmatched quotes", () => {
|
|
87
|
+
assert.throws(
|
|
88
|
+
() => Utils.parseRecipeConfig("A(" + "'".repeat(10000)),
|
|
89
|
+
/Invalid recipe/,
|
|
90
|
+
);
|
|
91
|
+
}),
|
|
92
|
+
|
|
93
|
+
it("Utils: should reject malformed pretty recipes with malformed parentheses", () => {
|
|
94
|
+
assert.throws(
|
|
95
|
+
() => Utils.parseRecipeConfig("A("),
|
|
96
|
+
/Invalid recipe/,
|
|
97
|
+
);
|
|
98
|
+
}),
|
|
99
|
+
|
|
100
|
+
it("Utils: should reject malformed pretty recipes with malformed escapes", () => {
|
|
101
|
+
assert.throws(
|
|
102
|
+
() => Utils.parseRecipeConfig("A('" + "\\".repeat(10000)),
|
|
103
|
+
/Invalid recipe/,
|
|
104
|
+
);
|
|
105
|
+
}),
|
|
29
106
|
]);
|
|
@@ -109,6 +109,38 @@ TestRegister.addApiTests([
|
|
|
109
109
|
assert.equal(3 + result, 35);
|
|
110
110
|
}),
|
|
111
111
|
|
|
112
|
+
it("toBase32: should support non-BMP Unicode alphabets", () => {
|
|
113
|
+
const alphabet = "🀇🀈🀉🀊🀋🀌🀍🀎🀏🀙🀚🀛🀜🀝🀞🀟🀠🀡🀐🀑🀒🀓🀔🀕🀖🀗🀘🀀🀁🀂🀃🀅";
|
|
114
|
+
|
|
115
|
+
const result = chef.toBase32("hello", {alphabet}).toString();
|
|
116
|
+
|
|
117
|
+
// Should not contain replacement characters
|
|
118
|
+
assert.equal(result.includes("�"), false);
|
|
119
|
+
|
|
120
|
+
// Should contain only symbols from the alphabet
|
|
121
|
+
for (const ch of Array.from(result)) {
|
|
122
|
+
assert.ok(Array.from(alphabet).includes(ch));
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// "hello" => 8 Base32 symbols
|
|
126
|
+
assert.equal(Array.from(result).length, 8);
|
|
127
|
+
}),
|
|
128
|
+
|
|
129
|
+
it("toBase32: should omit padding for 32-character Unicode alphabets", () => {
|
|
130
|
+
const alphabet = "🀇🀈🀉🀊🀋🀌🀍🀎🀏🀙🀚🀛🀜🀝🀞🀟🀠🀡🀐🀑🀒🀓🀔🀕🀖🀗🀘🀀🀁🀂🀃🀅";
|
|
131
|
+
|
|
132
|
+
const result = chef.toBase32("hell", {alphabet}).toString();
|
|
133
|
+
|
|
134
|
+
// Should not leak undefined from array indexing
|
|
135
|
+
assert.equal(result.includes("undefined"), false);
|
|
136
|
+
|
|
137
|
+
// Should not contain replacement characters
|
|
138
|
+
assert.equal(result.includes("�"), false);
|
|
139
|
+
|
|
140
|
+
// Unpadded Base32 output for 4-byte input should be 7 symbols
|
|
141
|
+
assert.equal(Array.from(result).length, 7);
|
|
142
|
+
}),
|
|
143
|
+
|
|
112
144
|
it("chef.help: should exist", () => {
|
|
113
145
|
assert(chef.help);
|
|
114
146
|
}),
|
|
@@ -136,7 +168,7 @@ TestRegister.addApiTests([
|
|
|
136
168
|
|
|
137
169
|
it("chef.help: returns multiple results", () => {
|
|
138
170
|
const result = chef.help("base 64");
|
|
139
|
-
assert.strictEqual(result.length,
|
|
171
|
+
assert.strictEqual(result.length, 14);
|
|
140
172
|
}),
|
|
141
173
|
|
|
142
174
|
it("chef.help: looks in description for matches too", () => {
|
|
@@ -264,6 +264,18 @@ Full hash: $2a$10$ODeP1.6fMsb.ENk2ngPUCO7qTGVPyHA9TqDVcyupyed8FjsiF65L6`;
|
|
|
264
264
|
assert.strictEqual(result.toString(), "Fit as a Fiddle");
|
|
265
265
|
}),
|
|
266
266
|
|
|
267
|
+
it("Bzip2 Compress: round-trips through the Node API", async () => {
|
|
268
|
+
const compressed = await chef.bzip2Compress("The quick brown fox.");
|
|
269
|
+
const result = await chef.bzip2Decompress(compressed);
|
|
270
|
+
assert.strictEqual(result.toString(), "The quick brown fox.");
|
|
271
|
+
}),
|
|
272
|
+
|
|
273
|
+
it("Avro to JSON: decodes an object container file through the Node API", async () => {
|
|
274
|
+
const avro = chef.fromHex("4f626a0104166176726f2e736368656d6196017b2274797065223a227265636f7264222c226e616d65223a22736d616c6c222c226669656c6473223a5b7b226e616d65223a226e616d65222c2274797065223a22737472696e67227d5d7d146176726f2e636f646563086e756c6c004e0247632e3702e5b75cdab9a62f1541020e0c6d796e616d654e0247632e3702e5b75cdab9a62f1541");
|
|
275
|
+
const result = await chef.avroToJSON(avro);
|
|
276
|
+
assert.strictEqual(result.toString(), "{\n \"name\": \"myname\"\n}");
|
|
277
|
+
}),
|
|
278
|
+
|
|
267
279
|
it("cartesianProduct: binary string", () => {
|
|
268
280
|
const result = cartesianProduct("1:2\\n\\n3:4", {
|
|
269
281
|
itemDelimiter: ":",
|
|
@@ -605,8 +617,9 @@ Top Drawer`, {
|
|
|
605
617
|
|
|
606
618
|
it("Generate HOTP", () => {
|
|
607
619
|
const result = chef.generateHOTP("JBSWY3DPEHPK3PXP", {
|
|
620
|
+
name: "Account",
|
|
608
621
|
});
|
|
609
|
-
const expected = `URI: otpauth://hotp
|
|
622
|
+
const expected = `URI: otpauth://hotp/Account?secret=JBSWY3DPEHPK3PXP&algorithm=SHA1&digits=6&counter=0
|
|
610
623
|
|
|
611
624
|
Password: 282760`;
|
|
612
625
|
assert.strictEqual(result.toString(), expected);
|
|
@@ -728,6 +741,18 @@ Arguments:
|
|
|
728
741
|
assert.strictEqual(result.toString(), expected);
|
|
729
742
|
}),
|
|
730
743
|
|
|
744
|
+
it("Parse URI with constructor and __proto__ arguments", () => {
|
|
745
|
+
const result = chef.parseURI("https://example.com/?constructor=ok&__proto__=hello");
|
|
746
|
+
const expected = `Protocol: https:
|
|
747
|
+
Hostname: example.com
|
|
748
|
+
Path name: /
|
|
749
|
+
Arguments:
|
|
750
|
+
\tconstructor = ok
|
|
751
|
+
\t__proto__ = hello
|
|
752
|
+
`;
|
|
753
|
+
assert.strictEqual(result.toString(), expected);
|
|
754
|
+
}),
|
|
755
|
+
|
|
731
756
|
it("Parse user agent", () => {
|
|
732
757
|
const result = chef.parseUserAgent("Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0 ");
|
|
733
758
|
const expected = `Browser
|
|
@@ -20,6 +20,9 @@ import "./tests/A1Z26CipherDecode.mjs";
|
|
|
20
20
|
import "./tests/AESKeyWrap.mjs";
|
|
21
21
|
import "./tests/AlternatingCaps.mjs";
|
|
22
22
|
import "./tests/AnalyseUUID.mjs";
|
|
23
|
+
import "./tests/Arithmetic.mjs";
|
|
24
|
+
import "./tests/Ascon.mjs";
|
|
25
|
+
import "./tests/AutomatedValidation.mjs";
|
|
23
26
|
import "./tests/AvroToJSON.mjs";
|
|
24
27
|
import "./tests/BCD.mjs";
|
|
25
28
|
import "./tests/BLAKE2b.mjs";
|
|
@@ -41,6 +44,7 @@ import "./tests/ByteRepr.mjs";
|
|
|
41
44
|
import "./tests/CBORDecode.mjs";
|
|
42
45
|
import "./tests/CBOREncode.mjs";
|
|
43
46
|
import "./tests/CMAC.mjs";
|
|
47
|
+
import "./tests/COBS.mjs";
|
|
44
48
|
import "./tests/CRCChecksum.mjs";
|
|
45
49
|
import "./tests/CSV.mjs";
|
|
46
50
|
import "./tests/CaesarBoxCipher.mjs";
|
|
@@ -64,6 +68,7 @@ import "./tests/ConvertLeetSpeak.mjs";
|
|
|
64
68
|
import "./tests/ConvertToNATOAlphabet.mjs";
|
|
65
69
|
import "./tests/Crypt.mjs";
|
|
66
70
|
import "./tests/DateTime.mjs";
|
|
71
|
+
import "./tests/DechunkHTTPResponse.mjs";
|
|
67
72
|
import "./tests/DefangIP.mjs";
|
|
68
73
|
import "./tests/DisassembleARM.mjs";
|
|
69
74
|
import "./tests/DropNthBytes.mjs";
|
|
@@ -71,6 +76,7 @@ import "./tests/ECDSA.mjs";
|
|
|
71
76
|
import "./tests/ELFInfo.mjs";
|
|
72
77
|
import "./tests/Enigma.mjs";
|
|
73
78
|
import "./tests/EscapeSmartCharacters.mjs";
|
|
79
|
+
import "./tests/ExtendedGCD.mjs";
|
|
74
80
|
import "./tests/ExtractAudioMetadata.mjs";
|
|
75
81
|
import "./tests/ExtractEmailAddresses.mjs";
|
|
76
82
|
import "./tests/ExtractHashes.mjs";
|
|
@@ -81,6 +87,7 @@ import "./tests/FlaskSession.mjs";
|
|
|
81
87
|
import "./tests/FletcherChecksum.mjs";
|
|
82
88
|
import "./tests/Float.mjs";
|
|
83
89
|
import "./tests/Fork.mjs";
|
|
90
|
+
import "./tests/FromBase.mjs";
|
|
84
91
|
import "./tests/FromDecimal.mjs";
|
|
85
92
|
import "./tests/GOST.mjs";
|
|
86
93
|
import "./tests/GenerateAllChecksums.mjs";
|
|
@@ -93,6 +100,7 @@ import "./tests/Gunzip.mjs";
|
|
|
93
100
|
import "./tests/Gzip.mjs";
|
|
94
101
|
import "./tests/HASSH.mjs";
|
|
95
102
|
import "./tests/HKDF.mjs";
|
|
103
|
+
import "./tests/HTMLEntity.mjs";
|
|
96
104
|
import "./tests/Hash.mjs";
|
|
97
105
|
import "./tests/HaversineDistance.mjs";
|
|
98
106
|
import "./tests/Hex.mjs";
|
|
@@ -121,10 +129,13 @@ import "./tests/LevenshteinDistance.mjs";
|
|
|
121
129
|
import "./tests/Lorenz.mjs";
|
|
122
130
|
import "./tests/LuhnChecksum.mjs";
|
|
123
131
|
import "./tests/MIMEDecoding.mjs";
|
|
132
|
+
import "./tests/MOD.mjs";
|
|
124
133
|
import "./tests/MS.mjs";
|
|
125
134
|
import "./tests/Magic.mjs";
|
|
126
135
|
import "./tests/Media.mjs";
|
|
136
|
+
import "./tests/Median.mjs";
|
|
127
137
|
import "./tests/Modhex.mjs";
|
|
138
|
+
import "./tests/ModularInverse.mjs";
|
|
128
139
|
import "./tests/MorseCode.mjs";
|
|
129
140
|
import "./tests/MultipleBombe.mjs";
|
|
130
141
|
import "./tests/MurmurHash3.mjs";
|
|
@@ -136,6 +147,7 @@ import "./tests/PEMtoHex.mjs";
|
|
|
136
147
|
import "./tests/PGP.mjs";
|
|
137
148
|
import "./tests/PHP.mjs";
|
|
138
149
|
import "./tests/PHPSerialize.mjs";
|
|
150
|
+
import "./tests/PRESENT.mjs";
|
|
139
151
|
import "./tests/ParityBit.mjs";
|
|
140
152
|
import "./tests/ParseCSR.mjs";
|
|
141
153
|
import "./tests/ParseEthernetFrame.mjs";
|
|
@@ -163,6 +175,7 @@ import "./tests/Register.mjs";
|
|
|
163
175
|
import "./tests/RegularExpression.mjs";
|
|
164
176
|
import "./tests/RemoveANSIEscapeCodes.mjs";
|
|
165
177
|
import "./tests/RenderMarkdown.mjs";
|
|
178
|
+
import "./tests/RenderPDF.mjs";
|
|
166
179
|
import "./tests/RisonEncodeDecode.mjs";
|
|
167
180
|
import "./tests/Rotate.mjs";
|
|
168
181
|
import "./tests/SIGABA.mjs";
|
|
@@ -174,6 +187,7 @@ import "./tests/SeqUtils.mjs";
|
|
|
174
187
|
import "./tests/SetDifference.mjs";
|
|
175
188
|
import "./tests/SetIntersection.mjs";
|
|
176
189
|
import "./tests/SetUnion.mjs";
|
|
190
|
+
import "./tests/ShowOnMap.mjs";
|
|
177
191
|
import "./tests/Shuffle.mjs";
|
|
178
192
|
// Cannot test operations that use the File type yet
|
|
179
193
|
// import "./tests/SplitColourChannels.mjs";
|
|
@@ -184,15 +198,18 @@ import "./tests/StripUDPHeader.mjs";
|
|
|
184
198
|
import "./tests/Subsection.mjs";
|
|
185
199
|
import "./tests/SwapCase.mjs";
|
|
186
200
|
import "./tests/SymmetricDifference.mjs";
|
|
201
|
+
import "./tests/TEA.mjs";
|
|
187
202
|
import "./tests/TakeNthBytes.mjs";
|
|
188
203
|
import "./tests/Template.mjs";
|
|
189
204
|
import "./tests/TextEncodingBruteForce.mjs";
|
|
190
205
|
import "./tests/TextIntegerConverter.mjs";
|
|
191
206
|
import "./tests/ToFromInsensitiveRegex.mjs";
|
|
192
207
|
import "./tests/TranslateDateTimeFormat.mjs";
|
|
208
|
+
import "./tests/Twofish.mjs";
|
|
193
209
|
import "./tests/Typex.mjs";
|
|
194
210
|
import "./tests/URLEncodeDecode.mjs";
|
|
195
211
|
import "./tests/UnescapeString.mjs";
|
|
212
|
+
import "./tests/UnescapeUnicodeCharacters.mjs";
|
|
196
213
|
import "./tests/Unicode.mjs";
|
|
197
214
|
import "./tests/Wrap.mjs";
|
|
198
215
|
import "./tests/XORChecksum.mjs";
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for arithmetical operations
|
|
3
|
+
*
|
|
4
|
+
* @copyright Crown Copyright 2026
|
|
5
|
+
* @license Apache-2.0
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import TestRegister from "../../lib/TestRegister.mjs";
|
|
9
|
+
|
|
10
|
+
TestRegister.addTests([
|
|
11
|
+
{
|
|
12
|
+
name: "Subtract",
|
|
13
|
+
input: "321,123,test",
|
|
14
|
+
expectedOutput: "198",
|
|
15
|
+
recipeConfig: [
|
|
16
|
+
{
|
|
17
|
+
"op": "Subtract",
|
|
18
|
+
"args": ["Comma"]
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
},
|
|
22
|
+
{
|
|
23
|
+
name: "Subtract - no valid input",
|
|
24
|
+
input: "test",
|
|
25
|
+
expectedOutput: "NaN",
|
|
26
|
+
recipeConfig: [
|
|
27
|
+
{
|
|
28
|
+
"op": "Subtract",
|
|
29
|
+
"args": ["Comma"]
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
]);
|