From 1ef4afc82d1cb96cf9e56707f362c12e2f7dc9e0 Mon Sep 17 00:00:00 2001 From: p-leriche <7701190+p-leriche@users.noreply.github.com> Date: Wed, 4 Mar 2026 09:44:28 +0000 Subject: [PATCH 01/20] Add BigInt utility functions for number theory operations (#2205) Co-authored-by: GCHQDeveloper581 <63102987+GCHQDeveloper581@users.noreply.github.com> (initial tests) --- src/core/config/Categories.json | 3 + src/core/lib/BigIntUtils.mjs | 73 +++++++++++++ tests/node/index.mjs | 1 + tests/node/tests/lib/BigIntUtils.mjs | 150 +++++++++++++++++++++++++++ 4 files changed, 227 insertions(+) create mode 100644 src/core/lib/BigIntUtils.mjs create mode 100644 tests/node/tests/lib/BigIntUtils.mjs diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index aac00ca1..07b2caeb 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -222,6 +222,9 @@ "Subtract", "Multiply", "Divide", + "Modular Exponentiation", + "Modular Inverse", + "Extended GCD", "Mean", "Median", "Standard Deviation", diff --git a/src/core/lib/BigIntUtils.mjs b/src/core/lib/BigIntUtils.mjs new file mode 100644 index 00000000..5ddd8786 --- /dev/null +++ b/src/core/lib/BigIntUtils.mjs @@ -0,0 +1,73 @@ +/** + * @author p-leriche [philip.leriche@cantab.net] + * @copyright Crown Copyright 2025 + * @license Apache-2.0 + */ + +import OperationError from "../errors/OperationError.mjs"; + +/** + * Number theory utilities used by cryptographic operations. + * + * Currently provides: + * - parseBigInt + * - Extended Euclidean Algorithm + * - Modular Exponentiation + * + * Additional algorithms may be added as required. + */ + +/** + * parseBigInt helper operation + */ +export function parseBigInt(value, param) { + const v = (value ?? "").trim(); + if (/^0x[0-9a-f]+$/i.test(v)) return BigInt(v); + if (/^[+-]?[0-9]+$/.test(v)) return BigInt(v); + throw new OperationError(param + " must be decimal or hex (0x...)"); +} + +/** + * Extended Euclidean Algorithm + * + * Returns [g, x, y] such that: + * a*x + b*y = g = gcd(a, b) + * + * (Uses an iterative algorithm to avoid possible stack overflow) + */ +export function egcd(a, b) { + let oldR = a, r = b; + let oldS = 1n, s = 0n; + let oldT = 0n, t = 1n; + + while (r !== 0n) { + const quotient = oldR / r; + + [oldR, r] = [r, oldR - quotient * r]; + [oldS, s] = [s, oldS - quotient * s]; + [oldT, t] = [t, oldT - quotient * t]; + } + + // oldR is the gcd + // oldS and oldT are the Bézout coefficients + return [oldR, oldS, oldT]; +} + +/** + * Modular exponentiation + */ +export function modPow(base, exponent, modulus) { + let result = 1n; + base %= modulus; + + while (exponent > 0n) { + if (exponent & 1n) { + result = (result * base) % modulus; + } + base = (base * base) % modulus; + exponent >>= 1n; + } + + return result; +} + diff --git a/tests/node/index.mjs b/tests/node/index.mjs index f6abba40..f872f8f4 100644 --- a/tests/node/index.mjs +++ b/tests/node/index.mjs @@ -23,6 +23,7 @@ import "./tests/Dish.mjs"; import "./tests/NodeDish.mjs"; import "./tests/Utils.mjs"; import "./tests/Categories.mjs"; +import "./tests/lib/BigIntUtils.mjs"; const testStatus = { allTestsPassing: true, diff --git a/tests/node/tests/lib/BigIntUtils.mjs b/tests/node/tests/lib/BigIntUtils.mjs new file mode 100644 index 00000000..d75a4893 --- /dev/null +++ b/tests/node/tests/lib/BigIntUtils.mjs @@ -0,0 +1,150 @@ +import TestRegister from "../../../lib/TestRegister.mjs"; +import { parseBigInt, egcd, modPow } from "../../../../src/core/lib/BigIntUtils.mjs"; +import it from "../../assertionHandler.mjs"; +import assert from "assert"; + +TestRegister.addApiTests([ + // ===== parseBigInt tests ===== + it("BigIntUtils: parseBigInt - decimal number", () => { + const value = parseBigInt("1", "test value"); + assert.deepStrictEqual(value, BigInt("1")); + }), + + it("BigIntUtils: parseBigInt - large decimal", () => { + const value = parseBigInt("123456789012345678901234567890", "test value"); + assert.deepStrictEqual(value, BigInt("123456789012345678901234567890")); + }), + + it("BigIntUtils: parseBigInt - hexadecimal lowercase", () => { + const value = parseBigInt("0xff", "test value"); + assert.deepStrictEqual(value, BigInt("255")); + }), + + it("BigIntUtils: parseBigInt - hexadecimal uppercase", () => { + const value = parseBigInt("0xFF", "test value"); + assert.deepStrictEqual(value, BigInt("255")); + }), + + it("BigIntUtils: parseBigInt - large hexadecimal", () => { + const value = parseBigInt("0x123456789ABCDEF", "test value"); + assert.deepStrictEqual(value, BigInt("0x123456789ABCDEF")); + }), + + it("BigIntUtils: parseBigInt - whitespace trimming", () => { + const value = parseBigInt(" 42 ", "test value"); + assert.deepStrictEqual(value, BigInt("42")); + }), + + it("BigIntUtils: parseBigInt - invalid input (text)", () => { + assert.throws(() => parseBigInt("test", "test value"), { + name: "Error", + message: "test value must be decimal or hex (0x...)" + }); + }), + + it("BigIntUtils: parseBigInt - invalid input (hex without prefix)", () => { + assert.throws(() => parseBigInt("FF", "test value"), { + name: "Error", + message: "test value must be decimal or hex (0x...)" + }); + }), + + it("BigIntUtils: parseBigInt - invalid input (mixed)", () => { + assert.throws(() => parseBigInt("12abc", "test value"), { + name: "Error", + message: "test value must be decimal or hex (0x...)" + }); + }), + + // ===== egcd tests ===== + it("BigIntUtils: egcd - basic coprime", () => { + const a = BigInt("36"); + const b = BigInt("48"); + const gcd = BigInt("12"); + const bezout1 = BigInt("-1"); + const bezout2 = BigInt("1"); + assert.deepStrictEqual(egcd(a, b), [gcd, bezout1, bezout2]); + }), + + it("BigIntUtils: egcd - coprime numbers", () => { + const [g, x, y] = egcd(BigInt("3"), BigInt("11")); + assert.strictEqual(g, BigInt("1")); + // Verify Bézout identity: a*x + b*y = gcd + assert.strictEqual(BigInt("3") * x + BigInt("11") * y, g); + }), + + it("BigIntUtils: egcd - non-coprime numbers", () => { + const [g, x, y] = egcd(BigInt("240"), BigInt("46")); + assert.strictEqual(g, BigInt("2")); + // Verify Bézout identity + assert.strictEqual(BigInt("240") * x + BigInt("46") * y, g); + }), + + it("BigIntUtils: egcd - with zero", () => { + const [g, x, y] = egcd(BigInt("17"), BigInt("0")); + assert.strictEqual(g, BigInt("17")); + assert.strictEqual(x, BigInt("1")); + assert.strictEqual(y, BigInt("0")); + }), + + it("BigIntUtils: egcd - identical numbers", () => { + const [g, x, y] = egcd(BigInt("42"), BigInt("42")); + assert.strictEqual(g, BigInt("42")); + // Verify Bézout identity + assert.strictEqual(BigInt("42") * x + BigInt("42") * y, g); + }), + + it("BigIntUtils: egcd - large numbers", () => { + const a = BigInt("123456789012345678901234567890"); + const b = BigInt("987654321098765432109876543210"); + const [g, x, y] = egcd(a, b); + // Verify Bézout identity + assert.strictEqual(a * x + b * y, g); + }), + + // ===== modPow tests ===== + it("BigIntUtils: modPow - basic", () => { + // 2^10 mod 1000 = 1024 mod 1000 = 24 + const result = modPow(BigInt("2"), BigInt("10"), BigInt("1000")); + assert.strictEqual(result, BigInt("24")); + }), + + it("BigIntUtils: modPow - RSA-like example", () => { + // Common RSA public exponent + const base = BigInt("123456789"); + const exp = BigInt("65537"); + const mod = BigInt("999999999999"); + const result = modPow(base, exp, mod); + // Result should be less than modulus + assert(result < mod); + assert(result >= BigInt("0")); + }), + + it("BigIntUtils: modPow - exponent zero", () => { + // Any number^0 = 1 + const result = modPow(BigInt("999"), BigInt("0"), BigInt("100")); + assert.strictEqual(result, BigInt("1")); + }), + + it("BigIntUtils: modPow - base zero", () => { + // 0^n = 0 + const result = modPow(BigInt("0"), BigInt("5"), BigInt("100")); + assert.strictEqual(result, BigInt("0")); + }), + + it("BigIntUtils: modPow - large exponent", () => { + // Test with very large exponent (efficient algorithm should handle this) + const result = modPow(BigInt("3"), BigInt("1000000"), BigInt("1000000007")); + assert(result >= BigInt("0")); + assert(result < BigInt("1000000007")); + }), + + it("BigIntUtils: modPow - modular inverse verification", () => { + // If a*x . 1 (mod m), then modPow(a, 1, m) * x . 1 (mod m) + const a = BigInt("3"); + const m = BigInt("11"); + const x = BigInt("4"); // inverse of 3 mod 11 + const result = modPow(a, BigInt("1"), m) * x % m; + assert.strictEqual(result, BigInt("1")); + }), +]); From c1b849bdb28383b65b1bb6997b665e706e2eaad7 Mon Sep 17 00:00:00 2001 From: Thomas Date: Wed, 4 Mar 2026 22:42:48 +0800 Subject: [PATCH 02/20] feat: add random integer generation operation (#2151) --- src/core/config/Categories.json | 1 + .../PseudoRandomIntegerGenerator.mjs | 164 ++++++++++++++++++ 2 files changed, 165 insertions(+) create mode 100644 src/core/operations/PseudoRandomIntegerGenerator.mjs diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 07b2caeb..6d6b2f39 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -554,6 +554,7 @@ "P-list Viewer", "Disassemble x86", "Pseudo-Random Number Generator", + "Pseudo-Random Integer Generator", "Generate De Bruijn Sequence", "Generate UUID", "Analyse UUID", diff --git a/src/core/operations/PseudoRandomIntegerGenerator.mjs b/src/core/operations/PseudoRandomIntegerGenerator.mjs new file mode 100644 index 00000000..a2d83a92 --- /dev/null +++ b/src/core/operations/PseudoRandomIntegerGenerator.mjs @@ -0,0 +1,164 @@ +/** + * @author cktgh [chankaitung@gmail.com] + * @copyright Crown Copyright 2026 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import OperationError from "../errors/OperationError.mjs"; +import forge from "node-forge"; +import Utils, { isWorkerEnvironment } from "../Utils.mjs"; +import { DELIM_OPTIONS } from "../lib/Delim.mjs"; + +/** + * Pseudo-Random Integer Generator operation + */ +class PseudoRandomIntegerGenerator extends Operation { + + // in theory 2**53 is the max range, but we use Number.MAX_SAFE_INTEGER (2**53 - 1) as it is more consistent. + static MAX_RANGE = Number.MAX_SAFE_INTEGER; + // arbitrary choice + static BUFFER_SIZE = 1024; + + /** + * PseudoRandomIntegerGenerator constructor + */ + constructor() { + super(); + + this.name = "Pseudo-Random Integer Generator"; + this.module = "Ciphers"; + this.description = "A cryptographically-secure pseudo-random number generator (PRNG).

Generates random integers within a specified range using the browser's built-in crypto.getRandomValues() method if available.

The supported range of integers is from -(2^53 - 1) to (2^53 - 1)."; + this.infoURL = "https://wikipedia.org/wiki/Pseudorandom_number_generator"; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + "name": "Number of Integers", + "type": "number", + "value": 1, + "min": 1 + }, + { + "name": "Min Value", + "type": "number", + "value": 0, + "min": Number.MIN_SAFE_INTEGER, + "max": Number.MAX_SAFE_INTEGER + }, + { + "name": "Max Value", + "type": "number", + "value": 99, + "min": Number.MIN_SAFE_INTEGER, + "max": Number.MAX_SAFE_INTEGER + }, + { + "name": "Delimiter", + "type": "option", + "value": DELIM_OPTIONS + }, + { + "name": "Output", + "type": "option", + "value": ["Raw", "Hex", "Decimal"] + } + ]; + + // not using BigUint64Array to avoid BigInt handling overhead + this.randomBuffer = new Uint32Array(PseudoRandomIntegerGenerator.BUFFER_SIZE); + this.randomBufferOffset = PseudoRandomIntegerGenerator.BUFFER_SIZE; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const [numInts, minInt, maxInt, delimiter, outputType] = args; + + if (minInt === null || maxInt === null) return ""; + + const min = Math.ceil(minInt); + const max = Math.floor(maxInt); + const delim = Utils.charRep(delimiter || "Space"); + + if (!Number.isSafeInteger(min) || !Number.isSafeInteger(max)) { + throw new OperationError("Min and Max must be between `-(2^53 - 1)` and `2^53 - 1`."); + } + if (min > max) { + throw new OperationError("Min cannot be larger than Max."); + } + const range = max - min + 1; // inclusive range + if (range > PseudoRandomIntegerGenerator.MAX_RANGE) { + throw new OperationError("Range between Min and Max cannot be larger than `2^53`"); + } + + // as large as possible while divisible by range + const rejectionThreshold = PseudoRandomIntegerGenerator.MAX_RANGE - (PseudoRandomIntegerGenerator.MAX_RANGE % range); + const output = []; + for (let i = 0; i < numInts; i++) { + const result = this._generateRandomValue(rejectionThreshold); + const intValue = min + (result % range); + + switch (outputType) { + case "Hex": + output.push(intValue.toString(16)); + break; + case "Decimal": + output.push(intValue.toString(10)); + break; + case "Raw": + default: + output.push(Utils.chr(intValue)); + } + } + + if (outputType === "Raw") { + return output.join(""); + } + return output.join(delim); + } + + /** + * Generate a random value, result will be less than the rejection threshold (exclusive). + * + * @param {number} rejectionThreshold + * @returns {number} + */ + _generateRandomValue(rejectionThreshold) { + let result; + do { + if (this.randomBufferOffset + 2 > this.randomBuffer.length) { + this._resetRandomBuffer(); + } + // stitching a 53 bit number; not using BigUint64Array to avoid BigInt handling overhead + result = (this.randomBuffer[this.randomBufferOffset++] & 0x1f_ffff) * 0x1_0000_0000 + + this.randomBuffer[this.randomBufferOffset++]; + } while (result >= rejectionThreshold); + + return result; + } + + /** + * Fill random buffer with new random values and rseet the offset. + */ + _resetRandomBuffer() { + if (isWorkerEnvironment() && self.crypto) { + self.crypto.getRandomValues(this.randomBuffer); + } else { + const bytes = forge.random.getBytesSync(this.randomBuffer.length * 4); + for (let j = 0; j < this.randomBuffer.length; j++) { + this.randomBuffer[j] = (bytes.charCodeAt(j * 4) << 24) | + (bytes.charCodeAt(j * 4 + 1) << 16) | + (bytes.charCodeAt(j * 4 + 2) << 8) | + bytes.charCodeAt(j * 4 + 3); + } + } + this.randomBufferOffset = 0; + } + +} + +export default PseudoRandomIntegerGenerator; From 2b162d494f88eaadb5e3f7d84f8ae18e02aca4ab Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 Mar 2026 15:09:48 +0000 Subject: [PATCH 03/20] Bump basic-ftp from 5.0.5 to 5.2.0 (#2218) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 145a1296..f4d18f70 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5285,9 +5285,9 @@ "license": "MIT" }, "node_modules/basic-ftp": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", - "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.2.0.tgz", + "integrity": "sha512-VoMINM2rqJwJgfdHq6RiUudKt2BV+FY5ZFezP/ypmwayk68+NzzAQy4XXLlqsGD4MCzq3DrmNFD/uUmBJuGoXw==", "dev": true, "license": "MIT", "engines": { From cd7dafdf53f96db9ba6cf0c1fbea3cbf5f3dd93d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 4 Mar 2026 19:58:25 +0000 Subject: [PATCH 04/20] Bump jsonwebtoken from 8.5.1 to 9.0.0 (#2219) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: GCHQDeveloper581 <63102987+GCHQDeveloper581@users.noreply.github.com> (updated tests to reflect stricter parameter validation in the new library version) --- package-lock.json | 70 ++++++----------------- package.json | 2 +- tests/operations/tests/JWTSign.mjs | 91 +++++++++++++++++++++++++++--- 3 files changed, 100 insertions(+), 63 deletions(-) diff --git a/package-lock.json b/package-lock.json index f4d18f70..61db7931 100644 --- a/package-lock.json +++ b/package-lock.json @@ -59,7 +59,7 @@ "json5": "^2.2.3", "jsonata": "^2.1.0", "jsonpath-plus": "^10.4.0", - "jsonwebtoken": "8.5.1", + "jsonwebtoken": "9.0.0", "jsqr": "^1.4.0", "jsrsasign": "^11.1.1", "kbpgp": "^2.1.17", @@ -12245,34 +12245,31 @@ } }, "node_modules/jsonwebtoken": { - "version": "8.5.1", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", - "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", + "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", "license": "MIT", "dependencies": { "jws": "^3.2.2", - "lodash.includes": "^4.3.0", - "lodash.isboolean": "^3.0.3", - "lodash.isinteger": "^4.0.4", - "lodash.isnumber": "^3.0.3", - "lodash.isplainobject": "^4.0.6", - "lodash.isstring": "^4.0.1", - "lodash.once": "^4.0.0", + "lodash": "^4.17.21", "ms": "^2.1.1", - "semver": "^5.6.0" + "semver": "^7.3.8" }, "engines": { - "node": ">=4", - "npm": ">=1.4.28" + "node": ">=12", + "npm": ">=6" } }, "node_modules/jsonwebtoken/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", "license": "ISC", "bin": { - "semver": "bin/semver" + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/jsqr": { @@ -12598,18 +12595,6 @@ "dev": true, "license": "MIT" }, - "node_modules/lodash.includes": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", - "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", - "license": "MIT" - }, - "node_modules/lodash.isboolean": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", - "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", - "license": "MIT" - }, "node_modules/lodash.isfinite": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/lodash.isfinite/-/lodash.isfinite-3.3.2.tgz", @@ -12617,28 +12602,11 @@ "dev": true, "license": "MIT" }, - "node_modules/lodash.isinteger": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", - "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", - "license": "MIT" - }, - "node_modules/lodash.isnumber": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", - "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", - "license": "MIT" - }, "node_modules/lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "license": "MIT" - }, - "node_modules/lodash.isstring": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", - "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "dev": true, "license": "MIT" }, "node_modules/lodash.merge": { @@ -12648,12 +12616,6 @@ "dev": true, "license": "MIT" }, - "node_modules/lodash.once": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", - "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", - "license": "MIT" - }, "node_modules/lodash.union": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", diff --git a/package.json b/package.json index 5864cdd8..1e87c230 100644 --- a/package.json +++ b/package.json @@ -142,7 +142,7 @@ "json5": "^2.2.3", "jsonata": "^2.1.0", "jsonpath-plus": "^10.4.0", - "jsonwebtoken": "8.5.1", + "jsonwebtoken": "9.0.0", "jsqr": "^1.4.0", "jsrsasign": "^11.1.1", "kbpgp": "^2.1.17", diff --git a/tests/operations/tests/JWTSign.mjs b/tests/operations/tests/JWTSign.mjs index a7752138..9954174b 100644 --- a/tests/operations/tests/JWTSign.mjs +++ b/tests/operations/tests/JWTSign.mjs @@ -15,7 +15,7 @@ const inputObject = JSON.stringify({ }, null, 4); const hsKey = "secret_cat"; -const rsKey = `-----BEGIN RSA PRIVATE KEY----- +const rsKey1024 = `-----BEGIN RSA PRIVATE KEY----- MIICWwIBAAKBgQDdlatRjRjogo3WojgGHFHYLugdUWAY9iR3fy4arWNA1KoS8kVw 33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQsHUfQrSDv+MuSUMAe8jzKE4qW +jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5Do2kQ+X5xK9cipRgEKwIDAQAB @@ -30,11 +30,52 @@ fSSjAkLRi54PKJ8TFUeOP15h9sQzydI8zJU+upvDEKZsZc/UhT/SySDOxQ4G/523 Y0sz/OZtSWcol/UMgQJALesy++GdvoIDLfJX5GBQpuFgFenRiRDabxrE9MNUZ2aP FaFp+DyAe+b4nDwuJaW2LURbr8AEZga7oQj0uYxcYw== -----END RSA PRIVATE KEY-----`; -const esKey = `-----BEGIN PRIVATE KEY----- +const rsKey2048 = `-----BEGIN RSA PRIVATE KEY----- +MIIEogIBAAKCAQEAk0VOoksAblwP82DALTG6xGC86Hfho3nChbcPGWyqn+ScfHBF +cg3SeKyy6aWCyLcKfNwE5cPYzuYvVBsZyIrdfFOuV90D/aRYbuw6UkKR3cmmy9qE +qvu05dogvc0BcmkwbC37Q8JnsZBRcosoLGgTFxcK+LXdsG7DukajpsGesxQjOLb2 +1jnx+ypzx74xvj7grqlXkxeDKr22q7QkO3A1ApoOuJRAU+SjEEZmqdXzRery2RWx +hkWbCXuQw4PnW5Lh3Wwabnu7XKVIa6wJa1pqL2IAxmlZ0bvGTfjtO5ggNfgJk5V4 +bGSOXnsplpG71AWMrK2q6NqHjFIE1szEycUKrwIDAQABAoIBAAivyt6Zy/G2g8kC +852hfvcRubLV92eRdAmNGFqTOqaUcS00i3QZyp4MRGqxtOV/88y/nEOtP1RHkZJw +HXTjHq4JsDvwhnQR8JbCX6z1zkLQdS01u3jrwJTaPpooxdATfPlfO6CYjqM+SapB +o7dS1ZAZb4U8vPx+MWoDEVNxvO7/xyqho1Oc4H9MwqQUiyG2WfIoqxLSrBYcambv +RmySwTIpgQZTr61EeWf/0eWpV0iEYbSnkB/VaKW+5tg4gCjPgy5v6/LQ0u/pzlYz +ayCL3xN2rp0tigXsiiWz3cM5gDsnatK4nVNRs9y3JSZpWpI236ZfZjs8Lts+WBUw +hAEoE9kCgYEAyEIGD1A7R/t5EYk5HhHDH5tGdyxejAcQL5AIz0YnTZU8Iixyc7FR +uDmAMiuKIcJY/nUlxZjSxNc3MkOfZNggQvf9ONrt+ftQ1yyTjv+019NfU4w4d0Ep +LNaiAHgaPKimBUZjYXbLgiMXj/1pBaQmgUYTK/VlO3PVdowxxzxMYlMCgYEAvEOG +GrhVaQV1nAYx86BgZ3wn90hBFXZWGaN+eXUmyrast93Ih3TCSgQDKPuN3pdv/TIe +cpQv/BxEMpW+6d5Z1NP3GbrLpaZUiUNk8fqw1S3pmD5aWZrYIUaNukAyOxnZVgjv +EWD9QTpI663gODaeZZTkDYiRNzTzGOg5HtzporUCgYBBOphEtqqImNXnq13qeHip +O+eo+8/UJpzUEUN9WGmG8NxEeVvSaWin7DrgnKQCuQ5J3Biwk0XcDgoRmks6Ctf/ +WE2oDk/DxGOhowhxZMMgJd6AFUVzOstRqpvcMULCjWB+iV3nqk1Bl3KeWTmzN7O/ +Gfc2s1kFE4btdV7lebObtwKBgE3rkLS8eLVYCh6Cvef9CAms7Im/wRhV+zrvXWh9 +4YljZEdRpy7RV5z03i33N/faLALa3JlF1jp9pIhfTD5Vxk59ULe4hZNRLYoGd+Bj +hw8kyps1q4WMvkm/fueIrIGjqD2gwvopb4iwy/+n3rbFfHfE0UL8tEXqR3eWnhW1 +D4pFAoGAccR4eMJD43hJWaUQLtsj0RoW9lFKVXj7aqkIIeupXwt7Ic2z/FhCAJi+ +V0MWpd3K6+kPl+ifdt8U4kcYfubPMfJhd7IkMcgQS+yZK1+5xWdRISvI8GpNwIHE +LUkVkCCadXNNZ7b1nmUKjse95u4IaE6hwAqjSTNb05gPmCfoEjg= +-----END RSA PRIVATE KEY-----`; +const esKeyP256 = `-----BEGIN PRIVATE KEY----- MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgevZzL1gdAFr88hb2 OF/2NxApJCzGCEDdfSp6VQO30hyhRANCAAQRWz+jn65BtOMvdyHKcvjBeBSDZH2r 1RTwjmYSi9R/zpBnuQ4EiMnCqfMPWiZqB4QdbAd0E7oH50VpuZ1P087G -----END PRIVATE KEY-----`; +const esKeyP384 = `-----BEGIN PRIVATE KEY----- +MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDDpgCvB2frnLKd7TuWe +JM1ejXXmr9y/5gskxKuuylLvpQTiDdtLtuhJnvw1/zWKWO6hZANiAAQ5Crhsi5FD +t55i53dCtdzG9OzCnbDFf/6136ZfEiakDTDeWCdUvNnB3WQEcVBr97BfSWLI9mO+ +T5yzm0RfhgvWIq/tBou+sIDeGp6NQfJwhDhf+JsdeF174gtfNMZGj/s= +-----END PRIVATE KEY-----`; +const esKeyP521 = `-----BEGIN PRIVATE KEY----- +MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIA0dBErrZ5ovKq4Xf/ +iTlRkYxuOfgBZ6+tWIfG13YwthB1XrH06YmteZGNjHHLZEeycwUt0jM4kUb+tOsJ +3ckhj1ihgYkDgYYABACYgsa8JWKH46CQagwNw14v/L+DIs1WAjJdMXZySjKlRkD9 +LtLMxkbX2H4H4Zl2KzCMJkwTSETzSKNlXvAUJqKbRwHezCp4y5XZN9MOBYdmyylZ +NOVxwwTouimNkJ0K6A8+/Im5S3PWB8Ra1D6t+bT1WHHhEePZcltSLLFlbIIyot5m +2w== +-----END PRIVATE KEY-----`; TestRegister.addTests([ { @@ -88,7 +129,24 @@ TestRegister.addTests([ recipeConfig: [ { op: "JWT Sign", - args: [esKey, "ES256", "{}"], + args: [esKeyP256, "ES256", "{}"], + }, + { + op: "JWT Decode", + args: [] + } + ], + }, + { + name: "JWT Sign: ES384 - P256 key", + input: inputObject, + expectedOutput: `Error: Have you entered the key correctly? The key should be either the secret for HMAC algorithms or the PEM-encoded private key for RSA and ECDSA. + +Error: "alg" parameter "ES384" requires curve "secp384r1".`, + recipeConfig: [ + { + op: "JWT Sign", + args: [esKeyP256, "ES384", "{}"], }, { op: "JWT Decode", @@ -103,7 +161,7 @@ TestRegister.addTests([ recipeConfig: [ { op: "JWT Sign", - args: [esKey, "ES384", "{}"], + args: [esKeyP384, "ES384", "{}"], }, { op: "JWT Decode", @@ -118,7 +176,24 @@ TestRegister.addTests([ recipeConfig: [ { op: "JWT Sign", - args: [esKey, "ES512", "{}"], + args: [esKeyP521, "ES512", "{}"], + }, + { + op: "JWT Decode", + args: [] + } + ], + }, + { + name: "JWT Sign: RS256, weak key", + input: inputObject, + expectedOutput: `Error: Have you entered the key correctly? The key should be either the secret for HMAC algorithms or the PEM-encoded private key for RSA and ECDSA. + +Error: secretOrPrivateKey has a minimum key size of 2048 bits for RS256`, + recipeConfig: [ + { + op: "JWT Sign", + args: [rsKey1024, "RS256", "{}"], }, { op: "JWT Decode", @@ -133,7 +208,7 @@ TestRegister.addTests([ recipeConfig: [ { op: "JWT Sign", - args: [rsKey, "RS256", "{}"], + args: [rsKey2048, "RS256", "{}"], }, { op: "JWT Decode", @@ -148,7 +223,7 @@ TestRegister.addTests([ recipeConfig: [ { op: "JWT Sign", - args: [rsKey, "RS384", "{}"], + args: [rsKey2048, "RS384", "{}"], }, { op: "JWT Decode", @@ -163,7 +238,7 @@ TestRegister.addTests([ recipeConfig: [ { op: "JWT Sign", - args: [esKey, "RS512", "{}"], + args: [rsKey2048, "RS512", "{}"], }, { op: "JWT Decode", From 0c6454e10cea224f48d263bd4c22fb2d83db714d Mon Sep 17 00:00:00 2001 From: William Floyd Date: Fri, 6 Mar 2026 06:04:41 -0600 Subject: [PATCH 05/20] fix: `jq-web` -> `jq-wasm`, includes `jq` version `1.8.1` (#2223) Co-authored-by: GCHQDeveloper581 <63102987+GCHQDeveloper581@users.noreply.github.com> (added tests) --- package-lock.json | 12 ++++++------ package.json | 2 +- src/core/operations/Jq.mjs | 21 ++++++++++----------- tests/browser/02_ops.js | 9 +++++++++ 4 files changed, 26 insertions(+), 18 deletions(-) diff --git a/package-lock.json b/package-lock.json index 61db7931..ab3f3bbf 100644 --- a/package-lock.json +++ b/package-lock.json @@ -52,7 +52,7 @@ "highlight.js": "^11.11.1", "ieee754": "^1.2.1", "jimp": "^1.6.0", - "jq-web": "^0.6.2", + "jq-wasm": "^1.1.0-jq-1.8.1", "jquery": "3.7.1", "js-sha3": "^0.9.3", "jsesc": "^3.1.0", @@ -12060,11 +12060,11 @@ "integrity": "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==", "license": "BSD-3-Clause" }, - "node_modules/jq-web": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/jq-web/-/jq-web-0.6.2.tgz", - "integrity": "sha512-+7XvjBYwTx4vP5PYkf6Q6orubO/v+UgMU6By1GritrmShr9QpT3UKa4ANzXWQfhdqtBnQYXsm7ZNbdIHT6tYpQ==", - "license": "ISC" + "node_modules/jq-wasm": { + "version": "1.1.0-jq-1.8.1", + "resolved": "https://registry.npmjs.org/jq-wasm/-/jq-wasm-1.1.0-jq-1.8.1.tgz", + "integrity": "sha512-lWfu34lpDFIygOYcL5TzxhZIApDR9iR5XywcVoyUAZ6jlQrj8HKHOKeCcHgUm2dE9RVdbP3eqNAKGLuj+k4seQ==", + "license": "MIT" }, "node_modules/jquery": { "version": "3.7.1", diff --git a/package.json b/package.json index 1e87c230..1602b1b6 100644 --- a/package.json +++ b/package.json @@ -135,7 +135,7 @@ "highlight.js": "^11.11.1", "ieee754": "^1.2.1", "jimp": "^1.6.0", - "jq-web": "^0.6.2", + "jq-wasm": "^1.1.0-jq-1.8.1", "jquery": "3.7.1", "js-sha3": "^0.9.3", "jsesc": "^3.1.0", diff --git a/src/core/operations/Jq.mjs b/src/core/operations/Jq.mjs index c1e02b34..4584d1a9 100644 --- a/src/core/operations/Jq.mjs +++ b/src/core/operations/Jq.mjs @@ -6,7 +6,7 @@ import Operation from "../Operation.mjs"; import OperationError from "../errors/OperationError.mjs"; -import jq from "jq-web"; +import * as jq from "jq-wasm"; /** * jq operation @@ -40,16 +40,15 @@ class Jq extends Operation { * @returns {string} */ run(input, args) { - const [query] = args; - let result; - - try { - result = jq.json(input, query); - } catch (err) { - throw new OperationError(`Invalid jq expression: ${err.message}`); - } - - return JSON.stringify(result); + return (async () => { + const [query] = args; + try { + const result = await jq.json(input, query); + return JSON.stringify(result); + } catch (err) { + throw new OperationError(`Invalid jq expression: ${err.message}`); + } + })(); } } diff --git a/tests/browser/02_ops.js b/tests/browser/02_ops.js index d0b89c3e..dde84f68 100644 --- a/tests/browser/02_ops.js +++ b/tests/browser/02_ops.js @@ -50,6 +50,14 @@ module.exports = { testOp(browser, "Analyse hash", "0123456789abcdef", /CRC-64/); testOp(browser, "Atbash Cipher", "test input", "gvhg rmkfg"); // testOp(browser, "Avro to JSON", "test input", "test_output"); + testOp(browser, + [ + "From Hex", "Avro to JSON" + ], + "4f626a0104166176726f2e736368656d6196017b2274797065223a227265636f7264222c226e616d65223a22736d616c6c222c226669656c6473223a5b7b226e616d65223a226e616d65222c2274797065223a22737472696e67227d5d7d146176726f2e636f646563086e756c6c004e0247632e3702e5b75cdab9a62f1541020e0c6d796e616d654e0247632e3702e5b75cdab9a62f1541", + '{"name":"myname"}\n', + [[], [false]] + ); testOp(browser, "BLAKE2b", "test input", "33ebdc8f38177f3f3f334eeb117a84e11f061bbca4db6b8923e5cec85103f59f415551a5d5a933fdb6305dc7bf84671c2540b463dbfa08ee1895cfaa5bd780b5", ["512", "Hex", { "option": "UTF8", "string": "pass" }]); testOp(browser, "BLAKE2s", "test input", "defe73d61dfa6e5807e4f9643e159a09ccda6be3c26dcd65f8a9bb38bfc973a7", ["256", "Hex", { "option": "UTF8", "string": "pass" }]); testOp(browser, "BSON deserialise", "\u0011\u0000\u0000\u0000\u0002a\u0000\u0005\u0000\u0000\u0000test\u0000\u0000", '{\u000A "a": "test"\u000A}'); @@ -206,6 +214,7 @@ module.exports = { testOpHtml(browser, "Index of Coincidence", "test input", "", /Index of Coincidence: 0.08333333333333333/); testOpImage(browser, "Invert Image", "files/Hitchhikers_Guide.jpeg"); // testOp(browser, "JPath expression", "test input", "test_output"); + testOp(browser, "Jq", '{"a":{"b":1}}', '{"b":1}', [".a"]); testOpHtml(browser, "JSON Beautify", "{a:1}", ".json-dict .json-literal", "1"); // testOp(browser, "JSON Minify", "test input", "test_output"); // testOp(browser, "JSON to CSV", "test input", "test_output"); From cbe1d39e06dae3ab4c24b2320df6aab35b403b1b Mon Sep 17 00:00:00 2001 From: ThePlayer372-FR <64158371+ThePlayer372-FR@users.noreply.github.com> Date: Sat, 7 Mar 2026 08:29:22 +0100 Subject: [PATCH 06/20] Add Flask Session operations (Decode, Sign, Verify) (#2208) --- src/core/config/Categories.json | 5 +- src/core/operations/FlaskSessionDecode.mjs | 80 +++++++ src/core/operations/FlaskSessionSign.mjs | 89 ++++++++ src/core/operations/FlaskSessionVerify.mjs | 136 ++++++++++++ tests/operations/tests/FlaskSession.mjs | 246 +++++++++++++++++++++ 5 files changed, 555 insertions(+), 1 deletion(-) create mode 100644 src/core/operations/FlaskSessionDecode.mjs create mode 100644 src/core/operations/FlaskSessionSign.mjs create mode 100644 src/core/operations/FlaskSessionVerify.mjs create mode 100644 tests/operations/tests/FlaskSession.mjs diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 6d6b2f39..cee966b0 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -164,7 +164,10 @@ "Typex", "Lorenz", "Colossus", - "SIGABA" + "SIGABA", + "Flask Session Decode", + "Flask Session Sign", + "Flask Session Verify" ] }, { diff --git a/src/core/operations/FlaskSessionDecode.mjs b/src/core/operations/FlaskSessionDecode.mjs new file mode 100644 index 00000000..5486357e --- /dev/null +++ b/src/core/operations/FlaskSessionDecode.mjs @@ -0,0 +1,80 @@ +/** + * @author ThePlayer372-FR [] + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import OperationError from "../errors/OperationError.mjs"; +import { fromBase64 } from "../lib/Base64.mjs"; + +/** + * Flask Session Decode operation + */ +class FlaskSessionDecode extends Operation { + /** + * FlaskSessionDecode constructor + */ + constructor() { + super(); + + this.name = "Flask Session Decode"; + this.module = "Crypto"; + this.description = "Decodes the payload of a Flask session cookie (itsdangerous) into JSON."; + this.inputType = "string"; + this.outputType = "JSON"; + this.args = [ + { + name: "View TimeStamp", + type: "boolean", + value: false + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {Object[]} + */ + run(input, args) { + input = input.trim(); + const parts = input.split("."); + if (parts.length !== 3) { + throw new OperationError("Invalid Flask token format. Expected payload.timestamp.signature"); + } + + const payloadB64 = parts[0]; + const time = parts[1]; + + const timeB64 = time.replace(/-/g, "+").replace(/_/g, "/"); + const binary = fromBase64(timeB64); + const bytes = new Uint8Array(4); + for (let i = 0; i < 4; i++) { + bytes[i] = binary.charCodeAt(i); + } + const view = new DataView(bytes.buffer); + const timestamp = view.getInt32(0, false); + + const base64 = payloadB64.replace(/-/g, "+").replace(/_/g, "/"); + const padded = base64.padEnd(Math.ceil(base64.length / 4) * 4, "="); + let payloadJson; + try { + payloadJson = fromBase64(padded); + } catch (e) { + throw new OperationError("Invalid Base64 payload"); + } + + try { + let data = JSON.parse(payloadJson); + + if (args[0]) { + data = {payload: data, timestamp: timestamp}; + } + return data; + } catch (e) { + throw new OperationError("Unable to decode JSON payload: " + e.message); + } + } +} + +export default FlaskSessionDecode; diff --git a/src/core/operations/FlaskSessionSign.mjs b/src/core/operations/FlaskSessionSign.mjs new file mode 100644 index 00000000..01ee8b1d --- /dev/null +++ b/src/core/operations/FlaskSessionSign.mjs @@ -0,0 +1,89 @@ +/** + * @author ThePlayer372-FR [] + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import CryptoApi from "crypto-api/src/crypto-api.mjs"; +import Utils from "../Utils.mjs"; +import { toBase64 } from "../lib/Base64.mjs"; +import OperationError from "../errors/OperationError.mjs"; + +/** + * Flask Session Sign operation + */ +class FlaskSessionSign extends Operation { + /** + * FlaskSessionSign constructor + */ + constructor() { + super(); + + this.name = "Flask Session Sign"; + this.module = "Crypto"; + this.description = "Signs a JSON payload to produce a Flask session cookie (itsdangerous HMAC)."; + this.inputType = "JSON"; + this.outputType = "string"; + this.args = [ + { + name: "Key", + type: "toggleString", + value: "", + toggleValues: ["Hex", "Decimal", "Binary", "Base64", "UTF8", "Latin1"] + }, + { + name: "Salt", + type: "toggleString", + value: "cookie-session", + toggleValues: ["UTF8", "Hex", "Decimal", "Binary", "Base64", "Latin1"] + }, + { + name: "Algorithm", + type: "option", + value: ["sha1", "sha256"], + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + if (!args[0].string) { + throw new OperationError("Secret key required"); + } + const key = Utils.convertToByteString(args[0].string, args[0].option); + const salt = Utils.convertToByteString(args[1].string || "cookie-session", args[1].option); + const algorithm = args[2] || "sha1"; + + const payloadB64 = toBase64(Utils.strToByteArray(JSON.stringify(input))); + const payload = payloadB64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); + + const derivedKey = CryptoApi.getHmac(key, CryptoApi.getHasher(algorithm)); + derivedKey.update(salt); + + const currentTimeStamp = Math.ceil(Date.now() / 1000); + const buffer = new ArrayBuffer(4); + const view = new DataView(buffer); + view.setInt32(0, currentTimeStamp, false); + const bytes = new Uint8Array(buffer); + let binary = ""; + bytes.forEach(b => binary += String.fromCharCode(b)); + const timeB64 = toBase64(Utils.strToByteArray(binary)); + const time = timeB64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); + + const data = Utils.convertToByteString(payload + "." + time, "utf8"); + const sign = CryptoApi.getHmac(derivedKey.finalize(), CryptoApi.getHasher(algorithm)); + sign.update(data); + + const signB64 = toBase64(sign.finalize()); + const sign64 = signB64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); + + return payload + "." + time + "." + sign64; + } +} + + +export default FlaskSessionSign; diff --git a/src/core/operations/FlaskSessionVerify.mjs b/src/core/operations/FlaskSessionVerify.mjs new file mode 100644 index 00000000..7603ba1f --- /dev/null +++ b/src/core/operations/FlaskSessionVerify.mjs @@ -0,0 +1,136 @@ +/** + * @author ThePlayer372-FR [] + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import OperationError from "../errors/OperationError.mjs"; +import CryptoApi from "crypto-api/src/crypto-api.mjs"; +import Utils from "../Utils.mjs"; +import { toBase64, fromBase64 } from "../lib/Base64.mjs"; + +/** + * Flask Session Verify operation + */ +class FlaskSessionVerify extends Operation { + /** + * FlaskSessionVerify constructor + */ + constructor() { + super(); + + this.name = "Flask Session Verify"; + this.module = "Crypto"; + this.description = "Verifies the HMAC signature of a Flask session cookie (itsdangerous) generated."; + this.inputType = "string"; + this.outputType = "JSON"; + this.args = [ + { + name: "Key", + type: "toggleString", + value: "", + toggleValues: ["Hex", "Decimal", "Binary", "Base64", "UTF8", "Latin1"] + }, + { + name: "Salt", + type: "toggleString", + value: "cookie-session", + toggleValues: ["UTF8", "Hex", "Decimal", "Binary", "Base64", "Latin1"] + }, + { + name: "Algorithm", + type: "option", + value: ["sha1", "sha256"], + }, + { + name: "View TimeStamp", + type: "boolean", + value: true + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + + if (!args[0].string) { + throw new OperationError("Secret key required"); + } + + const key = Utils.convertToByteString(args[0].string, args[0].option); + const salt = Utils.convertToByteString(args[1].string || "cookie-session", args[1].option); + const algorithm = args[2] || "sha1"; + + input = input.trim(); + + const parts = input.split("."); + + if (parts.length !== 3) { + throw new OperationError("Invalid Flask token format. Expected payload.timestamp.signature"); + } + + const data = Utils.convertToByteString(parts[0] + "." + parts[1], "utf8"); + + + const derivedKey = CryptoApi.getHmac(key, CryptoApi.getHasher(algorithm)); + derivedKey.update(salt); + + const sign = CryptoApi.getHmac(derivedKey.finalize(), CryptoApi.getHasher(algorithm)); + sign.update(data); + + const payloadB64 = parts[0]; + const base64 = payloadB64.replace(/-/g, "+").replace(/_/g, "/"); + const padded = base64.padEnd(Math.ceil(base64.length / 4) * 4, "="); + + const time = parts[1]; + + const timeB64 = time.replace(/-/g, "+").replace(/_/g, "/"); + const binary = fromBase64(timeB64); + const bytes = new Uint8Array(4); + for (let i = 0; i < 4; i++) { + bytes[i] = binary.charCodeAt(i); + } + const view = new DataView(bytes.buffer); + const timestamp = view.getInt32(0, false); + + let payloadJson; + try { + payloadJson = fromBase64(padded); + } catch (e) { + throw new OperationError("Invalid Base64 payload"); + } + + const signB64 = toBase64(sign.finalize()); + const sign64 = signB64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, ""); + + if (sign64 !== parts[2]) { + throw new OperationError("Invalid signature!"); + } + + try { + const decoded = JSON.parse(payloadJson); + if (!args[3]) { + return { + valid: true, + payload: decoded, + }; + } else { + return { + valid: true, + payload: decoded, + timestamp: timestamp + }; + } + } catch (e) { + throw new OperationError("Unable to decode JSON payload: " + e.message); + } + + } +} + + +export default FlaskSessionVerify; diff --git a/tests/operations/tests/FlaskSession.mjs b/tests/operations/tests/FlaskSession.mjs new file mode 100644 index 00000000..7becf400 --- /dev/null +++ b/tests/operations/tests/FlaskSession.mjs @@ -0,0 +1,246 @@ +/** + * Flask Session tests + * + * @author ThePlayer372-FR [] + * + * @license Apache-2.0 + */ + +import TestRegister from "../../lib/TestRegister.mjs"; + +const validTokenSha1 = "eyJyb2xlIjoic3VwZXJ1c2VyIiwidXNlciI6ImFkbWluIn0.aZ-KEw.E_x6bOhA4GU9t72pMinJUjN-O3I"; +const validTokenSha256 = "eyJyb2xlIjoic3VwZXJ1c2VyIiwidXNlciI6ImFkbWluIn0.aab3Ew.Jsx2DOx_H9anZg0YcvhsASxQ11897EFHeQfS2oja4y8"; + +const validKey = "mysecretkey"; +const wrongKey = "notTheKey"; + +const outputObject = { + user: "admin", + role: "superuser", +}; + +const outputVerify = { + valid: true, + payload: outputObject, +}; + +TestRegister.addTests([ + { + name: "Flask Session: Decode", + input: validTokenSha1, + expectedOutput: outputObject, + recipeConfig: [ + { + op: "Flask Session Decode", + args: [ + false + ], + } + ] + }, + { + name: "Flask Session: Verify Sha1", + input: validTokenSha1, + expectedOutput: outputVerify, + recipeConfig: [ + { + op: "Flask Session Verify", + args: [ + { + string: validKey, + option: "UTF8" + }, + { + string: "cookie-session", + option: "UTF8" + }, + "sha1", + false, + ], + } + ] + }, + { + name: "Flask Session: Verify Sha256", + input: validTokenSha256, + expectedOutput: outputVerify, + recipeConfig: [ + { + op: "Flask Session Verify", + args: [ + { + string: validKey, + option: "UTF8" + }, + { + string: "cookie-session", + option: "UTF8" + }, + "sha256", + false, + ], + } + ] + }, + { + name: "Flask Session: Sign Sha1", + input: outputObject, + expectedOutput: outputVerify, + recipeConfig: [ + { + op: "Flask Session Sign", + args: [ + { + string: validKey, + option: "UTF8" + }, + { + string: "cookie-session", + option: "UTF8" + }, + "sha1" + ] + }, + { + op: "Flask Session Verify", + args: [ + { + string: validKey, + option: "UTF8" + }, + { + string: "cookie-session", + option: "UTF8" + }, + "sha1", + false, + ], + } + ] + }, + { + name: "Flask Session: Sign Sha256", + input: outputObject, + expectedOutput: outputVerify, + recipeConfig: [ + { + op: "Flask Session Sign", + args: [ + { + string: validKey, + option: "UTF8" + }, + { + string: "cookie-session", + option: "UTF8" + }, + "sha256" + ] + }, + { + op: "Flask Session Verify", + args: [ + { + string: validKey, + option: "UTF8" + }, + { + string: "cookie-session", + option: "UTF8" + }, + "sha256", + false, + ], + } + ] + }, + { + name: "Flask Session: Verify Sha1 Wrong Key", + input: validTokenSha1, + expectedOutput: "Invalid signature!", + recipeConfig: [ + { + op: "Flask Session Verify", + args: [ + { + string: wrongKey, + option: "UTF8" + }, + { + string: "cookie-session", + option: "UTF8" + }, + "sha1", + false, + ], + } + ] + }, + { + name: "Flask Session: Verify Sha256 Wrong Key", + input: validTokenSha256, + expectedOutput: "Invalid signature!", + recipeConfig: [ + { + op: "Flask Session Verify", + args: [ + { + string: wrongKey, + option: "UTF8" + }, + { + string: "cookie-session", + option: "UTF8" + }, + "sha256", + false, + ], + } + ] + }, + { + name: "Flask Session: Verify Sha1 Wrong Salt", + input: validTokenSha1, + expectedOutput: "Invalid signature!", + recipeConfig: [ + { + op: "Flask Session Verify", + args: [ + { + string: validKey, + option: "UTF8" + }, + { + string: "notTheSalt", + option: "UTF8" + }, + "sha1", + false, + ], + } + ] + }, + { + name: "Flask Session: Verify Sha256 Wrong Salt", + input: validTokenSha256, + expectedOutput: "Invalid signature!", + recipeConfig: [ + { + op: "Flask Session Verify", + args: [ + { + string: validKey, + option: "UTF8" + }, + { + string: "notTheSalt", + option: "UTF8" + }, + "sha256", + false, + ], + } + ] + }, + +]); From 15d7d5507ef2ebccb8cf2e1d314ad4283162d7f4 Mon Sep 17 00:00:00 2001 From: Swonkie <3949813+Swonkie@users.noreply.github.com> Date: Sat, 7 Mar 2026 09:20:26 +0100 Subject: [PATCH 07/20] [bugfix] #1874 Add Bootstrap form style for CodeMirror editor (#2161) --- src/web/stylesheets/utils/_overrides.css | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/web/stylesheets/utils/_overrides.css b/src/web/stylesheets/utils/_overrides.css index a2f8b029..fec7d857 100755 --- a/src/web/stylesheets/utils/_overrides.css +++ b/src/web/stylesheets/utils/_overrides.css @@ -249,6 +249,13 @@ optgroup { } +/* Bootstrap form inside CodeMirror editor */ + +.cm-panel > .bmd-form-group { + padding-top: 0; +} + + /* CodeMirror */ .ͼ2 .cm-specialChar, From 81b3e9abd4f460bd0c4d527384d0b0ed514680cb Mon Sep 17 00:00:00 2001 From: Thomas M <44269971+thomasxm@users.noreply.github.com> Date: Sat, 7 Mar 2026 12:07:17 +0000 Subject: [PATCH 08/20] Feat/rc6 add RC6 Encrypt/Decrypt operations (#2163) --- src/core/config/Categories.json | 2 + src/core/lib/RC6.mjs | 625 +++++++++++++++++++++++++++++ src/core/operations/RC6Decrypt.mjs | 119 ++++++ src/core/operations/RC6Encrypt.mjs | 119 ++++++ tests/operations/index.mjs | 1 + tests/operations/tests/RC6.mjs | 487 ++++++++++++++++++++++ 6 files changed, 1353 insertions(+) create mode 100644 src/core/lib/RC6.mjs create mode 100644 src/core/operations/RC6Decrypt.mjs create mode 100644 src/core/operations/RC6Encrypt.mjs create mode 100644 tests/operations/tests/RC6.mjs diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index cee966b0..e59c6aeb 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -109,6 +109,8 @@ "Rabbit", "SM4 Encrypt", "SM4 Decrypt", + "RC6 Encrypt", + "RC6 Decrypt", "GOST Encrypt", "GOST Decrypt", "GOST Sign", diff --git a/src/core/lib/RC6.mjs b/src/core/lib/RC6.mjs new file mode 100644 index 00000000..eaa6087c --- /dev/null +++ b/src/core/lib/RC6.mjs @@ -0,0 +1,625 @@ +/** + * Complete implementation of RC6 block cipher encryption/decryption with + * configurable word size (w), rounds (r), and key length (b). + * + * RC6 was an AES finalist designed by Ron Rivest, Matt Robshaw, Ray Sidney, and Yiqun Lisa Yin. + * Reference: https://en.wikipedia.org/wiki/RC6 + * Test Vectors: https://datatracker.ietf.org/doc/html/draft-krovetz-rc6-rc5-vectors-00 + * + * The P and Q constants are derived from mathematical constants e (Euler's number) and + * φ (golden ratio) as specified in the IETF draft. Master 256-bit values are scaled to + * any word size. + * + * @author Medjedtxm + * @copyright Crown Copyright 2026 + * @license Apache-2.0 + */ + +import OperationError from "../errors/OperationError.mjs"; + +/** + * Master P constant (256-bit) from IETF draft-krovetz-rc6-rc5-vectors-00 + * Derived from Odd((e-2) * 2^256) where e = 2.71828... + */ +const P_256 = 0xb7e151628aed2a6abf7158809cf4f3c762e7160f38b4da56a784d9045190cfefn; + +/** + * Master Q constant (256-bit) from IETF draft-krovetz-rc6-rc5-vectors-00 + * Derived from Odd((φ-1) * 2^256) where φ = 1.61803... (golden ratio) + */ +const Q_256 = 0x9e3779b97f4a7c15f39cc0605cedc8341082276bf3a27251f86c6a11d0c18e95n; + +/** + * Get P constant for given word size by scaling the 256-bit master constant + * @param {number} w - Word size in bits + * @returns {bigint} - P constant for word size w + */ +function getP(w) { + return (P_256 >> BigInt(256 - w)) | 1n; // Ensure odd +} + +/** + * Get Q constant for given word size by scaling the 256-bit master constant + * @param {number} w - Word size in bits + * @returns {bigint} - Q constant for word size w + */ +function getQ(w) { + return (Q_256 >> BigInt(256 - w)) | 1n; // Ensure odd +} + +/** + * Get block size in bytes for given word size + * Block size = 4 words = 4 * (w/8) bytes + * @param {number} w - Word size in bits + * @returns {number} - Block size in bytes + */ +export function getBlockSize(w) { + return 4 * (w / 8); +} + +/** + * Get recommended number of rounds for given word size + * @param {number} w - Word size in bits + * @returns {number} - Recommended rounds + */ +export function getDefaultRounds(w) { + if (w <= 16) return 16; + if (w <= 32) return 20; + if (w <= 64) return 24; + return 28; +} + +/** + * Create mask for w-bit word + * @param {number} w - Word size in bits + * @returns {bigint} - Mask with w bits set + */ +function wordMask(w) { + return (1n << BigInt(w)) - 1n; +} + +/** + * Rotate left for arbitrary word size using BigInt + * Uses lower lg(w) bits of n for rotation amount (RC6 spec) + * @param {bigint} x - Value to rotate + * @param {bigint} n - Rotation amount + * @param {number} w - Word size in bits + * @param {bigint} lgMask - Mask for lower lg(w) bits + * @returns {bigint} - Rotated value + */ +function ROL(x, n, w, lgMask) { + const mask = wordMask(w); + // Mask to lg(w) bits, then mod w for non-power-of-2 word sizes + // For power-of-2, (n & lgMask) < w always, so mod w is no-op + const shift = (n & lgMask) % BigInt(w); + return ((x << shift) | (x >> (BigInt(w) - shift))) & mask; +} + +/** + * Rotate right for arbitrary word size using BigInt + * Uses lower lg(w) bits of n for rotation amount (RC6 spec) + * @param {bigint} x - Value to rotate + * @param {bigint} n - Rotation amount + * @param {number} w - Word size in bits + * @param {bigint} lgMask - Mask for lower lg(w) bits + * @returns {bigint} - Rotated value + */ +function ROR(x, n, w, lgMask) { + const mask = wordMask(w); + // Mask to lg(w) bits, then mod w for non-power-of-2 word sizes + // For power-of-2, (n & lgMask) < w always, so mod w is no-op + const shift = (n & lgMask) % BigInt(w); + return ((x >> shift) | (x << (BigInt(w) - shift))) & mask; +} + +/** + * Convert byte array to word array (little-endian) using BigInt + * @param {number[]} bytes - Input byte array + * @param {number} w - Word size in bits + * @returns {bigint[]} - Array of w-bit words as BigInt + */ +function bytesToWords(bytes, w) { + const bytesPerWord = w / 8; + const words = []; + for (let i = 0; i < bytes.length; i += bytesPerWord) { + let word = 0n; + for (let j = 0; j < bytesPerWord && (i + j) < bytes.length; j++) { + word |= BigInt(bytes[i + j] || 0) << BigInt(j * 8); + } + words.push(word); + } + return words; +} + +/** + * Convert word array to byte array (little-endian) using BigInt + * @param {bigint[]} words - Array of words + * @param {number} w - Word size in bits + * @returns {number[]} - Output byte array + */ +function wordsToBytes(words, w) { + const bytesPerWord = w / 8; + const bytes = []; + for (const word of words) { + for (let j = 0; j < bytesPerWord; j++) { + bytes.push(Number((word >> BigInt(j * 8)) & 0xFFn)); + } + } + return bytes; +} + +/** + * Generate round subkeys from user key + * + * @param {number[]} key - User key as byte array + * @param {number} rounds - Number of rounds + * @param {number} w - Word size in bits + * @returns {bigint[]} - Array of 2r+4 subkeys as BigInt + */ +function generateSubkeys(key, rounds, w) { + const bytesPerWord = w / 8; + const b = key.length; + const c = Math.max(Math.ceil(b / bytesPerWord), 1); + + // Convert key bytes to words, pad with zeros if needed + const paddedKey = [...key]; + while (paddedKey.length < c * bytesPerWord) { + paddedKey.push(0); + } + const L = bytesToWords(paddedKey, w); + + // Number of subkeys: 2*r + 4 + const t = 2 * rounds + 4; + + // Get P and Q for this word size + const P = getP(w); + const Q = getQ(w); + const mask = wordMask(w); + + // lg(w) mask for rotation amounts (floor of log2(w), per RC6 spec) + const lgw = Math.floor(Math.log2(w)); + const lgMask = (1n << BigInt(lgw)) - 1n; + + // Initialise S array with magic constants + const S = new Array(t); + S[0] = P; + for (let i = 1; i < t; i++) { + S[i] = (S[i - 1] + Q) & mask; + } + + // Mix key into S + let A = 0n, B = 0n; + let i = 0, j = 0; + const v = 3 * Math.max(c, t); + + for (let s = 0; s < v; s++) { + A = S[i] = ROL((S[i] + A + B) & mask, 3n, w, lgMask); + B = L[j] = ROL((L[j] + A + B) & mask, A + B, w, lgMask); + i = (i + 1) % t; + j = (j + 1) % c; + } + + return S; +} + +/** + * Encrypt a single block using RC6 + * + * @param {number[]} block - Plaintext block (4*w/8 bytes) + * @param {bigint[]} S - Subkeys array + * @param {number} rounds - Number of rounds + * @param {number} w - Word size in bits + * @returns {number[]} - Ciphertext block + */ +function encryptBlock(block, S, rounds, w) { + const mask = wordMask(w); + const lgw = BigInt(Math.floor(Math.log2(w))); + const lgMask = (1n << lgw) - 1n; + + // Convert block to 4 words (A, B, C, D) + let [A, B, C, D] = bytesToWords(block, w); + + // Pre-whitening + B = (B + S[0]) & mask; + D = (D + S[1]) & mask; + + // Main rounds + for (let i = 1; i <= rounds; i++) { + // t = ROL(B * (2B + 1), lg(w)) + const t = ROL((B * ((2n * B + 1n) & mask)) & mask, lgw, w, lgMask); + + // u = ROL(D * (2D + 1), lg(w)) + const u = ROL((D * ((2n * D + 1n) & mask)) & mask, lgw, w, lgMask); + + // A = ROL(A ^ t, u) + S[2i] + A = (ROL(A ^ t, u, w, lgMask) + S[2 * i]) & mask; + + // C = ROL(C ^ u, t) + S[2i + 1] + C = (ROL(C ^ u, t, w, lgMask) + S[2 * i + 1]) & mask; + + // Rotate registers: (A, B, C, D) = (B, C, D, A) + const temp = A; + A = B; + B = C; + C = D; + D = temp; + } + + // Post-whitening + A = (A + S[2 * rounds + 2]) & mask; + C = (C + S[2 * rounds + 3]) & mask; + + // Convert words back to bytes + return wordsToBytes([A, B, C, D], w); +} + +/** + * Decrypt a single block using RC6 + * + * @param {number[]} block - Ciphertext block (4*w/8 bytes) + * @param {bigint[]} S - Subkeys array + * @param {number} rounds - Number of rounds + * @param {number} w - Word size in bits + * @returns {number[]} - Plaintext block + */ +function decryptBlock(block, S, rounds, w) { + const mask = wordMask(w); + const lgw = BigInt(Math.floor(Math.log2(w))); + const lgMask = (1n << lgw) - 1n; + + // Convert block to 4 words (A, B, C, D) + let [A, B, C, D] = bytesToWords(block, w); + + // Reverse post-whitening + C = (C - S[2 * rounds + 3] + (1n << BigInt(w))) & mask; + A = (A - S[2 * rounds + 2] + (1n << BigInt(w))) & mask; + + // Main rounds in reverse + for (let i = rounds; i >= 1; i--) { + // Reverse rotate registers: (A, B, C, D) = (D, A, B, C) + const temp = D; + D = C; + C = B; + B = A; + A = temp; + + // u = ROL(D * (2D + 1), lg(w)) + const u = ROL((D * ((2n * D + 1n) & mask)) & mask, lgw, w, lgMask); + + // t = ROL(B * (2B + 1), lg(w)) + const t = ROL((B * ((2n * B + 1n) & mask)) & mask, lgw, w, lgMask); + + // C = ROR(C - S[2i + 1], t) ^ u + C = ROR((C - S[2 * i + 1] + (1n << BigInt(w))) & mask, t, w, lgMask) ^ u; + + // A = ROR(A - S[2i], u) ^ t + A = ROR((A - S[2 * i] + (1n << BigInt(w))) & mask, u, w, lgMask) ^ t; + } + + // Reverse pre-whitening + D = (D - S[1] + (1n << BigInt(w))) & mask; + B = (B - S[0] + (1n << BigInt(w))) & mask; + + // Convert words back to bytes + return wordsToBytes([A, B, C, D], w); +} + +/** + * XOR two blocks + * @param {number[]} a - First block + * @param {number[]} b - Second block + * @returns {number[]} - XOR result + */ +function xorBlocks(a, b) { + const result = new Array(a.length); + for (let i = 0; i < a.length; i++) { + result[i] = a[i] ^ b[i]; + } + return result; +} + +/** + * Increment counter (little-endian) + * @param {number[]} counter - Counter block + * @returns {number[]} - Incremented counter + */ +function incrementCounter(counter) { + const result = [...counter]; + for (let i = 0; i < result.length; i++) { + result[i]++; + if (result[i] <= 255) break; + result[i] = 0; + } + return result; +} + +/** + * Apply padding to message + * @param {number[]} message - Original message + * @param {string} padding - Padding type ("NO", "PKCS5", "ZERO", "RANDOM", "BIT") + * @param {number} blockSize - Block size in bytes + * @returns {number[]} - Padded message + */ +function applyPadding(message, padding, blockSize) { + const remainder = message.length % blockSize; + let nPadding = remainder === 0 ? 0 : blockSize - remainder; + + // For PKCS5, always add at least one byte (full block if already aligned) + if (padding === "PKCS5" && remainder === 0) { + nPadding = blockSize; + } + + if (nPadding === 0) return [...message]; + + const paddedMessage = [...message]; + + switch (padding) { + case "NO": + throw new OperationError(`No padding requested but input is not a ${blockSize}-byte multiple.`); + + case "PKCS5": + for (let i = 0; i < nPadding; i++) { + paddedMessage.push(nPadding); + } + break; + + case "ZERO": + for (let i = 0; i < nPadding; i++) { + paddedMessage.push(0); + } + break; + + case "RANDOM": + for (let i = 0; i < nPadding; i++) { + paddedMessage.push(Math.floor(Math.random() * 256)); + } + break; + + case "BIT": + paddedMessage.push(0x80); + for (let i = 1; i < nPadding; i++) { + paddedMessage.push(0); + } + break; + + default: + throw new OperationError(`Unknown padding type: ${padding}`); + } + + return paddedMessage; +} + +/** + * Remove padding from message + * @param {number[]} message - Padded message + * @param {string} padding - Padding type ("NO", "PKCS5", "ZERO", "RANDOM", "BIT") + * @param {number} blockSize - Block size in bytes + * @returns {number[]} - Unpadded message + */ +function removePadding(message, padding, blockSize) { + if (message.length === 0) return message; + + switch (padding) { + case "NO": + case "ZERO": + case "RANDOM": + // These padding types cannot be reliably removed + return message; + + case "PKCS5": { + const padByte = message[message.length - 1]; + if (padByte > 0 && padByte <= blockSize) { + // Verify padding + for (let i = 0; i < padByte; i++) { + if (message[message.length - 1 - i] !== padByte) { + throw new OperationError("Invalid PKCS#5 padding."); + } + } + return message.slice(0, message.length - padByte); + } + throw new OperationError("Invalid PKCS#5 padding."); + } + + case "BIT": { + // Find 0x80 byte working backwards, skipping zeros + for (let i = message.length - 1; i >= 0; i--) { + if (message[i] === 0x80) { + return message.slice(0, i); + } else if (message[i] !== 0) { + throw new OperationError("Invalid BIT padding."); + } + } + throw new OperationError("Invalid BIT padding."); + } + + default: + throw new OperationError(`Unknown padding type: ${padding}`); + } +} + +/** + * Encrypt using RC6 cipher with specified block mode + * + * @param {number[]} message - Plaintext as byte array + * @param {number[]} key - Key as byte array + * @param {number[]} iv - IV (block size bytes, not used for ECB) + * @param {string} mode - Block cipher mode ("ECB", "CBC", "CFB", "OFB", "CTR") + * @param {string} padding - Padding type ("NO", "PKCS5", "ZERO", "RANDOM", "BIT") + * @param {number} rounds - Number of rounds (default: 20) + * @param {number} w - Word size in bits (default: 32) + * @returns {number[]} - Ciphertext as byte array + */ +export function encryptRC6(message, key, iv, mode = "ECB", padding = "PKCS5", rounds = 20, w = 32) { + const blockSize = getBlockSize(w); + const messageLength = message.length; + if (messageLength === 0) return []; + + const S = generateSubkeys(key, rounds, w); + + // Apply padding for ECB/CBC modes + let paddedMessage; + if (mode === "ECB" || mode === "CBC") { + paddedMessage = applyPadding(message, padding, blockSize); + } else { + // Stream modes (CFB, OFB, CTR) don't need padding + paddedMessage = [...message]; + } + + const cipherText = []; + + switch (mode) { + case "ECB": + for (let i = 0; i < paddedMessage.length; i += blockSize) { + const block = paddedMessage.slice(i, i + blockSize); + cipherText.push(...encryptBlock(block, S, rounds, w)); + } + break; + + case "CBC": { + let ivBlock = [...iv]; + for (let i = 0; i < paddedMessage.length; i += blockSize) { + const block = paddedMessage.slice(i, i + blockSize); + const xored = xorBlocks(block, ivBlock); + ivBlock = encryptBlock(xored, S, rounds, w); + cipherText.push(...ivBlock); + } + break; + } + + case "CFB": { + let ivBlock = [...iv]; + for (let i = 0; i < paddedMessage.length; i += blockSize) { + const encrypted = encryptBlock(ivBlock, S, rounds, w); + const block = paddedMessage.slice(i, i + blockSize); + // Pad block if shorter than blockSize + while (block.length < blockSize) block.push(0); + ivBlock = xorBlocks(encrypted, block); + cipherText.push(...ivBlock); + } + return cipherText.slice(0, messageLength); + } + + case "OFB": { + let ivBlock = [...iv]; + for (let i = 0; i < paddedMessage.length; i += blockSize) { + ivBlock = encryptBlock(ivBlock, S, rounds, w); + const block = paddedMessage.slice(i, i + blockSize); + // Pad block if shorter than blockSize + while (block.length < blockSize) block.push(0); + cipherText.push(...xorBlocks(ivBlock, block)); + } + return cipherText.slice(0, messageLength); + } + + case "CTR": { + let counter = [...iv]; + for (let i = 0; i < paddedMessage.length; i += blockSize) { + const encrypted = encryptBlock(counter, S, rounds, w); + const block = paddedMessage.slice(i, i + blockSize); + // Pad block if shorter than blockSize + while (block.length < blockSize) block.push(0); + cipherText.push(...xorBlocks(encrypted, block)); + counter = incrementCounter(counter); + } + return cipherText.slice(0, messageLength); + } + + default: + throw new OperationError(`Invalid block cipher mode: ${mode}`); + } + + return cipherText; +} + +/** + * Decrypt using RC6 cipher with specified block mode + * + * @param {number[]} cipherText - Ciphertext as byte array + * @param {number[]} key - Key as byte array + * @param {number[]} iv - IV (block size bytes, not used for ECB) + * @param {string} mode - Block cipher mode ("ECB", "CBC", "CFB", "OFB", "CTR") + * @param {string} padding - Padding type ("NO", "PKCS5", "ZERO", "RANDOM", "BIT") + * @param {number} rounds - Number of rounds (default: 20) + * @param {number} w - Word size in bits (default: 32) + * @returns {number[]} - Plaintext as byte array + */ +export function decryptRC6(cipherText, key, iv, mode = "ECB", padding = "PKCS5", rounds = 20, w = 32) { + const blockSize = getBlockSize(w); + const originalLength = cipherText.length; + if (originalLength === 0) return []; + + const S = generateSubkeys(key, rounds, w); + + if (mode === "ECB" || mode === "CBC") { + if ((originalLength % blockSize) !== 0) + throw new OperationError(`Invalid ciphertext length: ${originalLength} bytes. Must be a multiple of ${blockSize}.`); + } else { + // Pad for stream modes + while ((cipherText.length % blockSize) !== 0) + cipherText.push(0); + } + + const plainText = []; + + switch (mode) { + case "ECB": + for (let i = 0; i < cipherText.length; i += blockSize) { + const block = cipherText.slice(i, i + blockSize); + plainText.push(...decryptBlock(block, S, rounds, w)); + } + break; + + case "CBC": { + let ivBlock = [...iv]; + for (let i = 0; i < cipherText.length; i += blockSize) { + const block = cipherText.slice(i, i + blockSize); + const decrypted = decryptBlock(block, S, rounds, w); + plainText.push(...xorBlocks(decrypted, ivBlock)); + ivBlock = block; + } + break; + } + + case "CFB": { + let ivBlock = [...iv]; + for (let i = 0; i < cipherText.length; i += blockSize) { + const encrypted = encryptBlock(ivBlock, S, rounds, w); + const block = cipherText.slice(i, i + blockSize); + plainText.push(...xorBlocks(encrypted, block)); + ivBlock = block; + } + return plainText.slice(0, originalLength); + } + + case "OFB": { + let ivBlock = [...iv]; + for (let i = 0; i < cipherText.length; i += blockSize) { + ivBlock = encryptBlock(ivBlock, S, rounds, w); + const block = cipherText.slice(i, i + blockSize); + plainText.push(...xorBlocks(ivBlock, block)); + } + return plainText.slice(0, originalLength); + } + + case "CTR": { + let counter = [...iv]; + for (let i = 0; i < cipherText.length; i += blockSize) { + const encrypted = encryptBlock(counter, S, rounds, w); + const block = cipherText.slice(i, i + blockSize); + plainText.push(...xorBlocks(encrypted, block)); + counter = incrementCounter(counter); + } + return plainText.slice(0, originalLength); + } + + default: + throw new OperationError(`Invalid block cipher mode: ${mode}`); + } + + // Remove padding for ECB/CBC modes + if (mode === "ECB" || mode === "CBC") { + return removePadding(plainText, padding, blockSize); + } + + return plainText.slice(0, originalLength); +} diff --git a/src/core/operations/RC6Decrypt.mjs b/src/core/operations/RC6Decrypt.mjs new file mode 100644 index 00000000..3185b632 --- /dev/null +++ b/src/core/operations/RC6Decrypt.mjs @@ -0,0 +1,119 @@ +/** + * @author Medjedtxm + * @copyright Crown Copyright 2026 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import Utils from "../Utils.mjs"; +import OperationError from "../errors/OperationError.mjs"; +import { toHex } from "../lib/Hex.mjs"; +import { decryptRC6, getBlockSize, getDefaultRounds } from "../lib/RC6.mjs"; + +/** + * RC6 Decrypt operation + */ +class RC6Decrypt extends Operation { + + /** + * RC6Decrypt constructor + */ + constructor() { + super(); + + this.name = "RC6 Decrypt"; + this.module = "Ciphers"; + 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.

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.

IV: 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.

Padding: In CBC and ECB mode, the PKCS#7 padding scheme is used."; + this.infoURL = "https://wikipedia.org/wiki/RC6"; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + "name": "Key", + "type": "toggleString", + "value": "", + "toggleValues": ["Hex", "UTF8", "Latin1", "Base64"] + }, + { + "name": "IV", + "type": "toggleString", + "value": "", + "toggleValues": ["Hex", "UTF8", "Latin1", "Base64"] + }, + { + "name": "Mode", + "type": "option", + "value": ["CBC", "CFB", "OFB", "CTR", "ECB"] + }, + { + "name": "Input", + "type": "option", + "value": ["Hex", "Raw"] + }, + { + "name": "Output", + "type": "option", + "value": ["Raw", "Hex"] + }, + { + "name": "Padding", + "type": "option", + "value": ["PKCS5", "NO", "ZERO", "RANDOM", "BIT"] + }, + { + "name": "Word Size", + "type": "number", + "value": 32, + "min": 8, + "max": 256, + "step": 8 + }, + { + "name": "Rounds", + "type": "number", + "value": 20, + "min": 1, + "max": 255 + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const key = Utils.convertToByteArray(args[0].string, args[0].option), + iv = Utils.convertToByteArray(args[1].string, args[1].option), + [,, mode, inputType, outputType, padding, wordSize, rounds] = args; + + // Validate word size + if (!Number.isInteger(wordSize) || wordSize < 8 || wordSize > 256 || wordSize % 8 !== 0) + throw new OperationError(`Invalid word size: ${wordSize}. Must be a multiple of 8 between 8 and 256.`); + + const blockSize = getBlockSize(wordSize); + const defaultRounds = getDefaultRounds(wordSize); + + if (iv.length !== blockSize && iv.length !== 0 && mode !== "ECB") + throw new OperationError(`Invalid IV length: ${iv.length} bytes + +RC6-${wordSize} uses an IV length of ${blockSize} bytes (${blockSize * 8} bits). +Make sure you have specified the type correctly (e.g. Hex vs UTF8).`); + + if (!Number.isInteger(rounds) || rounds < 1 || rounds > 255) + throw new OperationError(`Invalid number of rounds: ${rounds} + +Rounds must be an integer between 1 and 255. Standard for w=${wordSize} is ${defaultRounds}.`); + + // Default IV to null bytes if empty (like AES) + const actualIv = iv.length === 0 ? new Array(blockSize).fill(0) : iv; + + input = Utils.convertToByteArray(input, inputType); + const output = decryptRC6(input, key, actualIv, mode, padding, rounds, wordSize); + return outputType === "Hex" ? toHex(output, "") : Utils.byteArrayToUtf8(output); + } + +} + +export default RC6Decrypt; diff --git a/src/core/operations/RC6Encrypt.mjs b/src/core/operations/RC6Encrypt.mjs new file mode 100644 index 00000000..d5ad6d7f --- /dev/null +++ b/src/core/operations/RC6Encrypt.mjs @@ -0,0 +1,119 @@ +/** + * @author Medjedtxm + * @copyright Crown Copyright 2026 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import Utils from "../Utils.mjs"; +import OperationError from "../errors/OperationError.mjs"; +import { toHex } from "../lib/Hex.mjs"; +import { encryptRC6, getBlockSize, getDefaultRounds } from "../lib/RC6.mjs"; + +/** + * RC6 Encrypt operation + */ +class RC6Encrypt extends Operation { + + /** + * RC6Encrypt constructor + */ + constructor() { + super(); + + this.name = "RC6 Encrypt"; + this.module = "Ciphers"; + 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.

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.

IV: 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.

Padding: In CBC and ECB mode, the PKCS#7 padding scheme is used."; + this.infoURL = "https://wikipedia.org/wiki/RC6"; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + "name": "Key", + "type": "toggleString", + "value": "", + "toggleValues": ["Hex", "UTF8", "Latin1", "Base64"] + }, + { + "name": "IV", + "type": "toggleString", + "value": "", + "toggleValues": ["Hex", "UTF8", "Latin1", "Base64"] + }, + { + "name": "Mode", + "type": "option", + "value": ["CBC", "CFB", "OFB", "CTR", "ECB"] + }, + { + "name": "Input", + "type": "option", + "value": ["Raw", "Hex"] + }, + { + "name": "Output", + "type": "option", + "value": ["Hex", "Raw"] + }, + { + "name": "Padding", + "type": "option", + "value": ["PKCS5", "NO", "ZERO", "RANDOM", "BIT"] + }, + { + "name": "Word Size", + "type": "number", + "value": 32, + "min": 8, + "max": 256, + "step": 8 + }, + { + "name": "Rounds", + "type": "number", + "value": 20, + "min": 1, + "max": 255 + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const key = Utils.convertToByteArray(args[0].string, args[0].option), + iv = Utils.convertToByteArray(args[1].string, args[1].option), + [,, mode, inputType, outputType, padding, wordSize, rounds] = args; + + // Validate word size + if (!Number.isInteger(wordSize) || wordSize < 8 || wordSize > 256 || wordSize % 8 !== 0) + throw new OperationError(`Invalid word size: ${wordSize}. Must be a multiple of 8 between 8 and 256.`); + + const blockSize = getBlockSize(wordSize); + const defaultRounds = getDefaultRounds(wordSize); + + if (iv.length !== blockSize && iv.length !== 0 && mode !== "ECB") + throw new OperationError(`Invalid IV length: ${iv.length} bytes + +RC6-${wordSize} uses an IV length of ${blockSize} bytes (${blockSize * 8} bits). +Make sure you have specified the type correctly (e.g. Hex vs UTF8).`); + + if (!Number.isInteger(rounds) || rounds < 1 || rounds > 255) + throw new OperationError(`Invalid number of rounds: ${rounds} + +Rounds must be an integer between 1 and 255. Standard for w=${wordSize} is ${defaultRounds}.`); + + // Default IV to null bytes if empty (like AES) + const actualIv = iv.length === 0 ? new Array(blockSize).fill(0) : iv; + + input = Utils.convertToByteArray(input, inputType); + const output = encryptRC6(input, key, actualIv, mode, padding, rounds, wordSize); + return outputType === "Hex" ? toHex(output, "") : Utils.byteArrayToUtf8(output); + } + +} + +export default RC6Encrypt; diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs index 9d803bcc..493afd67 100644 --- a/tests/operations/index.mjs +++ b/tests/operations/index.mjs @@ -152,6 +152,7 @@ import "./tests/Shuffle.mjs"; import "./tests/SIGABA.mjs"; import "./tests/SM2.mjs"; import "./tests/SM4.mjs"; +import "./tests/RC6.mjs"; // import "./tests/SplitColourChannels.mjs"; // Cannot test operations that use the File type yet import "./tests/SQLBeautify.mjs"; import "./tests/StrUtils.mjs"; diff --git a/tests/operations/tests/RC6.mjs b/tests/operations/tests/RC6.mjs new file mode 100644 index 00000000..b9159ce3 --- /dev/null +++ b/tests/operations/tests/RC6.mjs @@ -0,0 +1,487 @@ +/** + * RC6 cipher tests. + * + * Test vectors from the IETF draft: + * "Test Vectors for RC6 and RC5" + * https://datatracker.ietf.org/doc/html/draft-krovetz-rc6-rc5-vectors-00 + * + * @author Medjedtxm + * @copyright Crown Copyright 2026 + * @license Apache-2.0 + */ + +import TestRegister from "../../lib/TestRegister.mjs"; + +TestRegister.addTests([ + // ============================================================ + // IETF TEST VECTORS - RC6-8/12/4 + // ============================================================ + { + name: "RC6-8/12/4: IETF vector encrypt", + input: "00010203", + expectedOutput: "aefc4612", + recipeConfig: [ + { + op: "RC6 Encrypt", + args: [ + { string: "00010203", option: "Hex" }, + { string: "", option: "Hex" }, + "ECB", "Hex", "Hex", "NO", 8, 12 + ] + } + ] + }, + { + name: "RC6-8/12/4: IETF vector decrypt", + input: "aefc4612", + expectedOutput: "00010203", + recipeConfig: [ + { + op: "RC6 Decrypt", + args: [ + { string: "00010203", option: "Hex" }, + { string: "", option: "Hex" }, + "ECB", "Hex", "Hex", "NO", 8, 12 + ] + } + ] + }, + + // ============================================================ + // IETF TEST VECTORS - RC6-16/16/8 + // ============================================================ + { + name: "RC6-16/16/8: IETF vector encrypt", + input: "0001020304050607", + expectedOutput: "2ff0b68eaeffad5b", + recipeConfig: [ + { + op: "RC6 Encrypt", + args: [ + { string: "0001020304050607", option: "Hex" }, + { string: "", option: "Hex" }, + "ECB", "Hex", "Hex", "NO", 16, 16 + ] + } + ] + }, + { + name: "RC6-16/16/8: IETF vector decrypt", + input: "2ff0b68eaeffad5b", + expectedOutput: "0001020304050607", + recipeConfig: [ + { + op: "RC6 Decrypt", + args: [ + { string: "0001020304050607", option: "Hex" }, + { string: "", option: "Hex" }, + "ECB", "Hex", "Hex", "NO", 16, 16 + ] + } + ] + }, + + // ============================================================ + // IETF TEST VECTORS - RC6-32/20/16 (AES standard) + // ============================================================ + { + name: "RC6-32/20/16: IETF vector encrypt (AES standard)", + input: "000102030405060708090a0b0c0d0e0f", + expectedOutput: "3a96f9c7f6755cfe46f00e3dcd5d2a3c", + recipeConfig: [ + { + op: "RC6 Encrypt", + args: [ + { string: "000102030405060708090a0b0c0d0e0f", option: "Hex" }, + { string: "", option: "Hex" }, + "ECB", "Hex", "Hex", "NO", 32, 20 + ] + } + ] + }, + { + name: "RC6-32/20/16: IETF vector decrypt (AES standard)", + input: "3a96f9c7f6755cfe46f00e3dcd5d2a3c", + expectedOutput: "000102030405060708090a0b0c0d0e0f", + recipeConfig: [ + { + op: "RC6 Decrypt", + args: [ + { string: "000102030405060708090a0b0c0d0e0f", option: "Hex" }, + { string: "", option: "Hex" }, + "ECB", "Hex", "Hex", "NO", 32, 20 + ] + } + ] + }, + + // ============================================================ + // IETF TEST VECTORS - RC6-64/24/24 + // ============================================================ + { + name: "RC6-64/24/24: IETF vector encrypt", + input: "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + expectedOutput: "c002de050bd55e5d36864ab9853338e6dc4a1326c6bdaaeb1bc9e4fd67886617", + recipeConfig: [ + { + op: "RC6 Encrypt", + args: [ + { string: "000102030405060708090a0b0c0d0e0f1011121314151617", option: "Hex" }, + { string: "", option: "Hex" }, + "ECB", "Hex", "Hex", "NO", 64, 24 + ] + } + ] + }, + { + name: "RC6-64/24/24: IETF vector decrypt", + input: "c002de050bd55e5d36864ab9853338e6dc4a1326c6bdaaeb1bc9e4fd67886617", + expectedOutput: "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", + recipeConfig: [ + { + op: "RC6 Decrypt", + args: [ + { string: "000102030405060708090a0b0c0d0e0f1011121314151617", option: "Hex" }, + { string: "", option: "Hex" }, + "ECB", "Hex", "Hex", "NO", 64, 24 + ] + } + ] + }, + + // ============================================================ + // IETF TEST VECTORS - RC6-128/28/32 + // ============================================================ + { + name: "RC6-128/28/32: IETF vector encrypt", + input: "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + expectedOutput: "4ed87c64baffecd4303ee6a79aafaef575b351c024272be70a70b4a392cfc157dba52d529a79e83845bf43d67545383aed3dbf4f0d23640e44cbf6cdaa034dcb", + recipeConfig: [ + { + op: "RC6 Encrypt", + args: [ + { string: "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", option: "Hex" }, + { string: "", option: "Hex" }, + "ECB", "Hex", "Hex", "NO", 128, 28 + ] + } + ] + }, + { + name: "RC6-128/28/32: IETF vector decrypt", + input: "4ed87c64baffecd4303ee6a79aafaef575b351c024272be70a70b4a392cfc157dba52d529a79e83845bf43d67545383aed3dbf4f0d23640e44cbf6cdaa034dcb", + expectedOutput: "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f", + recipeConfig: [ + { + op: "RC6 Decrypt", + args: [ + { string: "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", option: "Hex" }, + { string: "", option: "Hex" }, + "ECB", "Hex", "Hex", "NO", 128, 28 + ] + } + ] + }, + + // ============================================================ + // IETF TEST VECTORS - RC6-24/4/0 (non-power-of-2) + // ============================================================ + { + name: "RC6-24/4/0: IETF non-standard vector encrypt (w=24, empty key)", + input: "000102030405060708090a0b", + expectedOutput: "0177982579be2ee3303269b9", + recipeConfig: [ + { + op: "RC6 Encrypt", + args: [ + { string: "", option: "Hex" }, + { string: "", option: "Hex" }, + "ECB", "Hex", "Hex", "NO", 24, 4 + ] + } + ] + }, + { + name: "RC6-24/4/0: IETF non-standard vector decrypt (w=24, empty key)", + input: "0177982579be2ee3303269b9", + expectedOutput: "000102030405060708090a0b", + recipeConfig: [ + { + op: "RC6 Decrypt", + args: [ + { string: "", option: "Hex" }, + { string: "", option: "Hex" }, + "ECB", "Hex", "Hex", "NO", 24, 4 + ] + } + ] + }, + + // ============================================================ + // IETF TEST VECTORS - RC6-80/4/12 (non-power-of-2) + // ============================================================ + { + name: "RC6-80/4/12: IETF non-standard vector encrypt (w=80)", + input: "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627", + expectedOutput: "26d9d6128601d06dec3817d401f1c0ff715473543875da417c2116d1e87c919a49311b00b4e17962", + recipeConfig: [ + { + op: "RC6 Encrypt", + args: [ + { string: "000102030405060708090a0b", option: "Hex" }, + { string: "", option: "Hex" }, + "ECB", "Hex", "Hex", "NO", 80, 4 + ] + } + ] + }, + { + name: "RC6-80/4/12: IETF non-standard vector decrypt (w=80)", + input: "26d9d6128601d06dec3817d401f1c0ff715473543875da417c2116d1e87c919a49311b00b4e17962", + expectedOutput: "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324252627", + recipeConfig: [ + { + op: "RC6 Decrypt", + args: [ + { string: "000102030405060708090a0b", option: "Hex" }, + { string: "", option: "Hex" }, + "ECB", "Hex", "Hex", "NO", 80, 4 + ] + } + ] + }, + + // ============================================================ + // ADDITIONAL KEY SIZE TESTS - RC6-32 (192-bit and 256-bit keys) + // ============================================================ + { + name: "RC6-32/20/24: 192-bit key encrypt", + input: "000102030405060708090a0b0c0d0e0f", + expectedOutput: "a68a14ff1342262a2bbd21f7966615eb", + recipeConfig: [ + { + op: "RC6 Encrypt", + args: [ + { string: "000102030405060708090a0b0c0d0e0f1011121314151617", option: "Hex" }, + { string: "", option: "Hex" }, + "ECB", "Hex", "Hex", "NO", 32, 20 + ] + } + ] + }, + { + name: "RC6-32/20/32: 256-bit key encrypt", + input: "000102030405060708090a0b0c0d0e0f", + expectedOutput: "921c3ecd43d9426a90089334d67aea2e", + recipeConfig: [ + { + op: "RC6 Encrypt", + args: [ + { string: "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", option: "Hex" }, + { string: "", option: "Hex" }, + "ECB", "Hex", "Hex", "NO", 32, 20 + ] + } + ] + }, + + // ============================================================ + // ROUND-TRIP TESTS - One per word size to verify encrypt/decrypt + // ============================================================ + { + name: "RC6-8 Round-trip: CBC mode", + input: "Hello World!", + expectedOutput: "Hello World!", + recipeConfig: [ + { + op: "RC6 Encrypt", + args: [ + { string: "mysecret", option: "UTF8" }, + { string: "abcd", option: "UTF8" }, + "CBC", "Raw", "Hex", "PKCS5", 8, 12 + ] + }, + { + op: "RC6 Decrypt", + args: [ + { string: "mysecret", option: "UTF8" }, + { string: "abcd", option: "UTF8" }, + "CBC", "Hex", "Raw", "PKCS5", 8, 12 + ] + } + ] + }, + { + name: "RC6-16 Round-trip: CBC mode", + input: "The quick brown fox", + expectedOutput: "The quick brown fox", + recipeConfig: [ + { + op: "RC6 Encrypt", + args: [ + { string: "secretkey1234567", option: "UTF8" }, + { string: "initvec!", option: "UTF8" }, + "CBC", "Raw", "Hex", "PKCS5", 16, 16 + ] + }, + { + op: "RC6 Decrypt", + args: [ + { string: "secretkey1234567", option: "UTF8" }, + { string: "initvec!", option: "UTF8" }, + "CBC", "Hex", "Raw", "PKCS5", 16, 16 + ] + } + ] + }, + { + name: "RC6-32 Round-trip: CBC mode", + input: "The quick brown fox jumps over the lazy dog", + expectedOutput: "The quick brown fox jumps over the lazy dog", + recipeConfig: [ + { + op: "RC6 Encrypt", + args: [ + { string: "aabbccddeeff00112233445566778899", option: "Hex" }, + { string: "00112233445566778899aabbccddeeff", option: "Hex" }, + "CBC", "Raw", "Hex", "PKCS5", 32, 20 + ] + }, + { + op: "RC6 Decrypt", + args: [ + { string: "aabbccddeeff00112233445566778899", option: "Hex" }, + { string: "00112233445566778899aabbccddeeff", option: "Hex" }, + "CBC", "Hex", "Raw", "PKCS5", 32, 20 + ] + } + ] + }, + { + name: "RC6-64 Round-trip: CBC mode", + input: "RC6 with 64-bit words is powerful!", + expectedOutput: "RC6 with 64-bit words is powerful!", + recipeConfig: [ + { + op: "RC6 Encrypt", + args: [ + { string: "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", option: "Hex" }, + { string: "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", option: "Hex" }, + "CBC", "Raw", "Hex", "PKCS5", 64, 24 + ] + }, + { + op: "RC6 Decrypt", + args: [ + { string: "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", option: "Hex" }, + { string: "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", option: "Hex" }, + "CBC", "Hex", "Raw", "PKCS5", 64, 24 + ] + } + ] + }, + { + name: "RC6-128 Round-trip: ECB mode", + input: "RC6 with 128-bit words provides massive block size for testing purposes!", + expectedOutput: "RC6 with 128-bit words provides massive block size for testing purposes!", + recipeConfig: [ + { + op: "RC6 Encrypt", + args: [ + { string: "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", option: "Hex" }, + { string: "", option: "Hex" }, + "ECB", "Raw", "Hex", "PKCS5", 128, 28 + ] + }, + { + op: "RC6 Decrypt", + args: [ + { string: "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f", option: "Hex" }, + { string: "", option: "Hex" }, + "ECB", "Hex", "Raw", "PKCS5", 128, 28 + ] + } + ] + }, + + // ============================================================ + // STREAM MODES TEST - Verify CFB/OFB/CTR work correctly + // ============================================================ + { + name: "RC6-32 Round-trip: CTR mode", + input: "CTR mode test message", + expectedOutput: "CTR mode test message", + recipeConfig: [ + { + op: "RC6 Encrypt", + args: [ + { string: "00112233445566778899aabbccddeeff", option: "Hex" }, + { string: "00000000000000000000000000000001", option: "Hex" }, + "CTR", "Raw", "Hex", "PKCS5", 32, 20 + ] + }, + { + op: "RC6 Decrypt", + args: [ + { string: "00112233445566778899aabbccddeeff", option: "Hex" }, + { string: "00000000000000000000000000000001", option: "Hex" }, + "CTR", "Hex", "Raw", "PKCS5", 32, 20 + ] + } + ] + }, + + // ============================================================ + // CUSTOM ROUNDS TEST - Verify non-standard round count works + // ============================================================ + { + name: "RC6-32 Round-trip: Custom 8 rounds", + input: "Testing custom rounds", + expectedOutput: "Testing custom rounds", + recipeConfig: [ + { + op: "RC6 Encrypt", + args: [ + { string: "00112233445566778899aabbccddeeff", option: "Hex" }, + { string: "", option: "Hex" }, + "ECB", "Raw", "Hex", "PKCS5", 32, 8 + ] + }, + { + op: "RC6 Decrypt", + args: [ + { string: "00112233445566778899aabbccddeeff", option: "Hex" }, + { string: "", option: "Hex" }, + "ECB", "Hex", "Raw", "PKCS5", 32, 8 + ] + } + ] + }, + + // ============================================================ + // EDGE CASE TEST - Padding boundary + // ============================================================ + { + name: "RC6-32 Round-trip: Exact block size input", + input: "1234567890123456", + expectedOutput: "1234567890123456", + recipeConfig: [ + { + op: "RC6 Encrypt", + args: [ + { string: "00112233445566778899aabbccddeeff", option: "Hex" }, + { string: "", option: "Hex" }, + "ECB", "Raw", "Hex", "PKCS5", 32, 20 + ] + }, + { + op: "RC6 Decrypt", + args: [ + { string: "00112233445566778899aabbccddeeff", option: "Hex" }, + { string: "", option: "Hex" }, + "ECB", "Hex", "Raw", "PKCS5", 32, 20 + ] + } + ] + } +]); From f759f4c43b098c7984c68c4c7a629c9cd5512df8 Mon Sep 17 00:00:00 2001 From: p-leriche <7701190+p-leriche@users.noreply.github.com> Date: Sun, 8 Mar 2026 13:46:36 +0000 Subject: [PATCH 09/20] Add Text/Integer Converter operation (#2213) Co-authored-by: GCHQDeveloper581 <63102987+GCHQDeveloper581@users.noreply.github.com> - Additional test case added. --- src/core/config/Categories.json | 1 + src/core/operations/TextIntegerConverter.mjs | 123 +++++++++++ tests/operations/index.mjs | 1 + .../operations/tests/TextIntegerConverter.mjs | 199 ++++++++++++++++++ 4 files changed, 324 insertions(+) create mode 100644 src/core/operations/TextIntegerConverter.mjs create mode 100644 tests/operations/tests/TextIntegerConverter.mjs diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index e59c6aeb..f03fb8ea 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -41,6 +41,7 @@ "From Base", "To BCD", "From BCD", + "Text-Integer Conversion", "To HTML Entity", "From HTML Entity", "URL Encode", diff --git a/src/core/operations/TextIntegerConverter.mjs b/src/core/operations/TextIntegerConverter.mjs new file mode 100644 index 00000000..4e740100 --- /dev/null +++ b/src/core/operations/TextIntegerConverter.mjs @@ -0,0 +1,123 @@ +/** + * @author p-leriche [philip.leriche@cantab.net] + * @copyright Crown Copyright 2025 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import OperationError from "../errors/OperationError.mjs"; + +/* ---------- helper functions ---------- */ + +/** + * Convert text to BigInt (big-endian byte interpretation) + */ +function textToBigInt(text) { + if (text.length === 0) return 0n; + + let result = 0n; + for (let i = 0; i < text.length; i++) { + const charCode = BigInt(text.charCodeAt(i)); + if (charCode > 255n) { + throw new OperationError( + `Character at position ${i} exceeds Latin-1 range (0-255).\n` + + "Only ASCII and Latin-1 characters are supported."); + } + result = (result << 8n) | charCode; + } + return result; +} + +/** + * Convert BigInt to text (big-endian byte interpretation) + */ +function bigIntToText(value) { + if (value === 0n) return ""; + + const bytes = []; + let num = value; + + while (num > 0n) { + bytes.unshift(Number(num & 0xFFn)); + num >>= 8n; + } + + return String.fromCharCode(...bytes); +} + +/* ---------- operation class ---------- */ + +/** + * Text/Integer Converter operation + */ +class TextIntegerConverter extends Operation { + /** + * TextIntegerConverter constructor + */ + constructor() { + super(); + + this.description = + "Converts between text strings and large integers (decimal or hexadecimal).

" + + "Text is interpreted as a big-endian sequence of character codes. For example:
" + + "ABC is 0x414243 (hex) is 4276803 (decimal)
" + + "Input format detection:
" + + "Decimal: digits 0-9 only
" + + "Hexadecimal: 0x... prefix
" + + "Quoted or unquoted text: treated as string

" + + "Character limitations:
" + + "Text input may only contain ASCII and Latin-1 characters (code point < 256).
" + + "Multi-byte Unicode characters will generate an error.

." ; + this.infoURL = "https://wikipedia.org/wiki/Endianness"; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + name: "Output format", + type: "option", + value: ["String", "Decimal", "Hexadecimal"] + } + ]; + this.name = "Text-Integer Conversion"; + this.module = "Default"; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const outputFormat = args[0]; + const trimmed = input.trim(); + + let bigIntValue; + + if (!trimmed) { + // Null input - treat as zero + bigIntValue = 0; + } else if (/^0x[0-9a-f]+$/i.test(trimmed) || + /^[+-]?[0-9]+$/.test(trimmed)) { + // Hex or decimal integer + bigIntValue = BigInt(trimmed); + } else if (/^["'].*["']$/.test(trimmed)) { + // Quoted string: Remove quotes and convert text to BigInt + const text = trimmed.slice(1, -1); + bigIntValue = textToBigInt(text); + } else { + // Assume it's unquoted text + bigIntValue = textToBigInt(trimmed); + } + + // Convert to output format + if (outputFormat === "String") { + return bigIntToText(bigIntValue); + } else if (outputFormat === "Decimal") { + return bigIntValue.toString(); + } else { // Hexadecimal + return "0x" + bigIntValue.toString(16); + } + } +} + +export default TextIntegerConverter; diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs index 493afd67..48ff4c8e 100644 --- a/tests/operations/index.mjs +++ b/tests/operations/index.mjs @@ -165,6 +165,7 @@ import "./tests/SymmetricDifference.mjs"; import "./tests/TakeNthBytes.mjs"; import "./tests/Template.mjs"; import "./tests/TextEncodingBruteForce.mjs"; +import "./tests/TextIntegerConverter.mjs"; import "./tests/ToFromInsensitiveRegex.mjs"; import "./tests/TranslateDateTimeFormat.mjs"; import "./tests/Typex.mjs"; diff --git a/tests/operations/tests/TextIntegerConverter.mjs b/tests/operations/tests/TextIntegerConverter.mjs new file mode 100644 index 00000000..fed8f6c3 --- /dev/null +++ b/tests/operations/tests/TextIntegerConverter.mjs @@ -0,0 +1,199 @@ +/** + * Text-Integer Conversion tests. + * + * @author p-leriche [philip.leriche@cantab.net] + * + * @copyright Crown Copyright 2025 + * @license Apache-2.0 + */ +import TestRegister from "../../lib/TestRegister.mjs"; + +TestRegister.addTests([ + { + name: "Text-Integer Conversion quoted string to decimal", + input: "\"ABC\"", + expectedOutput: "4276803", + recipeConfig: [ + { + op: "Text-Integer Conversion", + args: ["Decimal"], + }, + ], + }, + { + name: "Text-Integer Conversion quoted string to hexadecimal", + input: "\"ABC\"", + expectedOutput: "0x414243", + recipeConfig: [ + { + op: "Text-Integer Conversion", + args: ["Hexadecimal"], + }, + ], + }, + { + name: "Text-Integer Conversion single quoted string to decimal", + input: "'Hello'", + expectedOutput: "310939249775", + recipeConfig: [ + { + op: "Text-Integer Conversion", + args: ["Decimal"], + }, + ], + }, + { + name: "Text-Integer Conversion decimal to string", + input: "4276803", + expectedOutput: "ABC", + recipeConfig: [ + { + op: "Text-Integer Conversion", + args: ["String"], + }, + ], + }, + { + name: "Text-Integer Conversion hexadecimal to string", + input: "0x48656C6C6F", + expectedOutput: "Hello", + recipeConfig: [ + { + op: "Text-Integer Conversion", + args: ["String"], + }, + ], + }, + { + name: "Text-Integer Conversion round-trip string.decimal.string", + input: "\"Test\"", + expectedOutput: "Test", + recipeConfig: [ + { + op: "Text-Integer Conversion", + args: ["Decimal"], + }, + { + op: "Text-Integer Conversion", + args: ["String"], + }, + ], + }, + { + name: "Text-Integer Conversion round-trip string.hex.string", + input: "\"CyberChef\"", + expectedOutput: "CyberChef", + recipeConfig: [ + { + op: "Text-Integer Conversion", + args: ["Hexadecimal"], + }, + { + op: "Text-Integer Conversion", + args: ["String"], + }, + ], + }, + { + name: "Text-Integer Conversion implicit round trip string-string Latin-1", + input: "U+00FF", + expectedOutput: "U+00FF", // U+00FF (Latin small letter y with diaeresis) + recipeConfig: [ + { + op: "Unescape Unicode Characters", + args: ["U+"], + }, + { + op: "Text-Integer Conversion", + args: ["String"], + }, + { + op: "Escape Unicode Characters", + args: ["U+", false, 4, true], + }, + ], + }, + { + name: "Text-Integer Conversion unquoted text to decimal", + input: "Hi", + expectedOutput: "18537", + recipeConfig: [ + { + op: "Text-Integer Conversion", + args: ["Decimal"], + }, + ], + }, + { + name: "Text-Integer Conversion single character", + input: "\"A\"", + expectedOutput: "65", + recipeConfig: [ + { + op: "Text-Integer Conversion", + args: ["Decimal"], + }, + ], + }, + { + name: "Text-Integer Conversion hex to decimal conversion", + input: "0xFF", + expectedOutput: "255", + recipeConfig: [ + { + op: "Text-Integer Conversion", + args: ["Decimal"], + }, + ], + }, + { + name: "Text-Integer Conversion decimal to hex conversion", + input: "255", + expectedOutput: "0xff", + recipeConfig: [ + { + op: "Text-Integer Conversion", + args: ["Hexadecimal"], + }, + ], + }, + { + name: "Text-Integer Conversion large number to string", + input: "113091951015816448506195587157728348242683688608116", + expectedOutput: "Mary had a little cat", + recipeConfig: [ + { + op: "Text-Integer Conversion", + args: ["String"], + }, + ], + }, + { + name: "Text-Integer Conversion whitespace handling (quoted)", + input: "\" test \"", + expectedOutput: "2314978187545944096", + recipeConfig: [ + { + op: "Text-Integer Conversion", + args: ["Decimal"], + }, + ], + }, + { + name: "Text-Integer Conversion non-Latin1 character in input", + input: "61 ce 93 61", + expectedOutput: +`Character at position 1 exceeds Latin-1 range (0-255). +Only ASCII and Latin-1 characters are supported.`, + recipeConfig: [ + { + "op": "From Hex", + "args": ["Auto"] + }, + { + op: "Text-Integer Conversion", + args: ["Decimal"], + }, + ], + }, +]); From a19261d5f745bc293da4a9204fdc37ee62fc59fc Mon Sep 17 00:00:00 2001 From: Thomas M <44269971+thomasxm@users.noreply.github.com> Date: Sun, 8 Mar 2026 19:07:46 +0000 Subject: [PATCH 10/20] feat: add ARM disassembler operation (#2156) --- package-lock.json | 885 +++++++++++----------- package.json | 1 + src/core/config/Categories.json | 1 + src/core/operations/DisassembleARM.mjs | 193 +++++ tests/operations/index.mjs | 1 + tests/operations/tests/DisassembleARM.mjs | 377 +++++++++ 6 files changed, 1025 insertions(+), 433 deletions(-) create mode 100644 src/core/operations/DisassembleARM.mjs create mode 100644 tests/operations/tests/DisassembleARM.mjs diff --git a/package-lock.json b/package-lock.json index ab3f3bbf..6ab7c7fe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { + "@alexaltea/capstone-js": "^3.0.5", "@astronautlabs/amf": "^0.0.6", "@blu3r4y/lzma": "^2.3.3", "@wavesenterprise/crypto-gost-js": "^2.1.0-RC1", @@ -161,6 +162,26 @@ "worker-loader": "^3.0.8" } }, + "node_modules/@alexaltea/capstone-js": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@alexaltea/capstone-js/-/capstone-js-3.0.5.tgz", + "integrity": "sha512-HWa4d5vblYc3OEJ9MpcXFo0gV/oDLTI5iH7ng80Gs3/Wo3lcYvB14gDDwSr9So1F+fuwIET8meo6TxTezEyqTg==" + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@asamuzakjp/css-color": { "version": "2.8.3", "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-2.8.3.tgz", @@ -236,23 +257,23 @@ } }, "node_modules/@babel/core": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.0.tgz", - "integrity": "sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.26.0.tgz", + "integrity": "sha512-i1SLeK+DzNnQ3LL/CswPCa/E5u4lh1k6IAEphON8F+cXt0t9euTshDru0q7/IqMa1PMPz5RnHuHscF8/ZJsStg==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-compilation-targets": "^7.28.6", - "@babel/helper-module-transforms": "^7.28.6", - "@babel/helpers": "^7.28.6", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/traverse": "^7.29.0", - "@babel/types": "^7.29.0", - "@jridgewell/remapping": "^2.3.5", + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.26.0", + "@babel/generator": "^7.26.0", + "@babel/helper-compilation-targets": "^7.25.9", + "@babel/helper-module-transforms": "^7.26.0", + "@babel/helpers": "^7.26.0", + "@babel/parser": "^7.26.0", + "@babel/template": "^7.25.9", + "@babel/traverse": "^7.25.9", + "@babel/types": "^7.26.0", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -374,9 +395,9 @@ } }, "node_modules/@babel/helper-define-polyfill-provider": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.6.tgz", - "integrity": "sha512-mOAsxeeKkUKayvZR3HeTYD/fICpCPLJrU5ZjelT/PA6WHtNDBOE436YiaEUvHN454bRM3CebhDsIpieCc4texA==", + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.7.tgz", + "integrity": "sha512-6Fqi8MtQ/PweQ9xvux65emkLQ83uB+qAVtfHkC9UodyHMIZdxNI01HjLCLUtybElp2KY2XNE0nOgyP1E1vXw9w==", "dev": true, "license": "MIT", "dependencies": { @@ -565,15 +586,15 @@ } }, "node_modules/@babel/helpers": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", - "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", + "version": "7.26.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", + "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@babel/template": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/template": "^7.25.9", + "@babel/types": "^7.26.0" }, "engines": { "node": ">=6.9.0" @@ -1704,13 +1725,13 @@ } }, "node_modules/@babel/preset-env/node_modules/babel-plugin-polyfill-corejs3": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.0.tgz", - "integrity": "sha512-AvDcMxJ34W4Wgy4KBIIePQTAOP1Ie2WFwkQp3dB7FQ/f0lI5+nM96zUnYEOE1P9sEg0es5VCP0HxiWu5fUHZAQ==", + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.14.1.tgz", + "integrity": "sha512-ENp89vM9Pw4kv/koBb5N2f9bDZsR0hpf3BdPMOg/pkS3pwO4dzNnQZVXtBbeyAadgm865DmQG2jMMLqmZXvuCw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.6", + "@babel/helper-define-polyfill-provider": "^0.6.7", "core-js-compat": "^3.48.0" }, "peerDependencies": { @@ -1832,9 +1853,9 @@ } }, "node_modules/@codemirror/language": { - "version": "6.12.1", - "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.12.1.tgz", - "integrity": "sha512-Fa6xkSiuGKc8XC8Cn96T+TQHYj4ZZ7RdFmXA3i9xe/3hLHfwPZdM+dqfX0Cp0zQklBKhVD8Yzc8LS45rkqcwpQ==", + "version": "6.12.2", + "resolved": "https://registry.npmjs.org/@codemirror/language/-/language-6.12.2.tgz", + "integrity": "sha512-jEPmz2nGGDxhRTg3lTpzmIyGKxz3Gp3SJES4b0nAuE5SWQoKdT5GoQ69cwMmFd+wvFUhYirtDTr0/DRHpQAyWg==", "dev": true, "license": "MIT", "dependencies": { @@ -1869,9 +1890,9 @@ } }, "node_modules/@codemirror/view": { - "version": "6.39.15", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.39.15.tgz", - "integrity": "sha512-aCWjgweIIXLBHh7bY6cACvXuyrZ0xGafjQ2VInjp4RM4gMfscK5uESiNdrH0pE+e1lZr2B4ONGsjchl2KsKZzg==", + "version": "6.39.16", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.39.16.tgz", + "integrity": "sha512-m6S22fFpKtOWhq8HuhzsI1WzUP/hB9THbDj0Tl5KX4gbO6Y91hwBl7Yky33NdvB6IffuRFiBxf1R8kJMyXmA4Q==", "dev": true, "license": "MIT", "dependencies": { @@ -2077,9 +2098,9 @@ "license": "MIT" }, "node_modules/@cspell/dict-css": { - "version": "4.0.19", - "resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-4.0.19.tgz", - "integrity": "sha512-VYHtPnZt/Zd/ATbW3rtexWpBnHUohUrQOHff/2JBhsVgxOrksAxJnLAO43Q1ayLJBJUUwNVo+RU0sx0aaysZfg==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-4.1.0.tgz", + "integrity": "sha512-bfuvlTeGoK5QgXzzjn+PvqXU5J6mwraIdESNDSvPyplr/EbGFSuvgW3TOuoVNqW4WdDI7eM4tmoP5Dn1ZVgLag==", "dev": true, "license": "MIT" }, @@ -2126,9 +2147,9 @@ "license": "MIT" }, "node_modules/@cspell/dict-en_us": { - "version": "4.4.29", - "resolved": "https://registry.npmjs.org/@cspell/dict-en_us/-/dict-en_us-4.4.29.tgz", - "integrity": "sha512-G3B27++9ziRdgbrY/G/QZdFAnMzzx17u8nCb2Xyd4q6luLpzViRM/CW3jA+Mb/cGT5zR/9N+Yz9SrGu1s0bq7g==", + "version": "4.4.30", + "resolved": "https://registry.npmjs.org/@cspell/dict-en_us/-/dict-en_us-4.4.30.tgz", + "integrity": "sha512-+eVO/VNw8IzQpDIL/SCj+ytd5WbzbHZdU+GAM8eUY2ZU1KTxRw6BoDO+hEFB4cGkD9x+BXm0OKVGSWHNCSGdVw==", "dev": true, "license": "MIT" }, @@ -2147,9 +2168,9 @@ "license": "MIT" }, "node_modules/@cspell/dict-filetypes": { - "version": "3.0.15", - "resolved": "https://registry.npmjs.org/@cspell/dict-filetypes/-/dict-filetypes-3.0.15.tgz", - "integrity": "sha512-uDMeqYlLlK476w/muEFQGBy9BdQWS0mQ7BJiy/iQv5XUWZxE2O54ZQd9nW8GyQMzAgoyg5SG4hf9l039Qt66oA==", + "version": "3.0.16", + "resolved": "https://registry.npmjs.org/@cspell/dict-filetypes/-/dict-filetypes-3.0.16.tgz", + "integrity": "sha512-SyrtuK2/sx+cr94jOp2/uOAb43ngZEVISUTRj4SR6SfoGULVV1iJS7Drqn7Ul9HJ731QDttwWlOUgcQ+yMRblg==", "dev": true, "license": "MIT" }, @@ -2287,13 +2308,13 @@ "license": "MIT" }, "node_modules/@cspell/dict-markdown": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/@cspell/dict-markdown/-/dict-markdown-2.0.14.tgz", - "integrity": "sha512-uLKPNJsUcumMQTsZZgAK9RgDLyQhUz/uvbQTEkvF/Q4XfC1i/BnA8XrOrd0+Vp6+tPOKyA+omI5LRWfMu5K/Lw==", + "version": "2.0.15", + "resolved": "https://registry.npmjs.org/@cspell/dict-markdown/-/dict-markdown-2.0.15.tgz", + "integrity": "sha512-xz3LJfFCIJaxHu5Msu9UUSev1R1urVkERb5h1Yc5lJyNOkk/SQTSlNyME0Oma1sXlp6dLnIekL8GyeXJYszQ2w==", "dev": true, "license": "MIT", "peerDependencies": { - "@cspell/dict-css": "^4.0.19", + "@cspell/dict-css": "^4.1.0", "@cspell/dict-html": "^4.0.14", "@cspell/dict-html-symbol-entities": "^4.0.5", "@cspell/dict-typescript": "^3.2.3" @@ -2314,9 +2335,9 @@ "license": "MIT" }, "node_modules/@cspell/dict-npm": { - "version": "5.2.34", - "resolved": "https://registry.npmjs.org/@cspell/dict-npm/-/dict-npm-5.2.34.tgz", - "integrity": "sha512-M2MtfmYeHIPBuC8esMU4JQXHKma7Xt7VyBWUk67B62KDu61sxebQ2HeizdqmN2sLEJsTkq3bZT5PGzHpZ0LEWQ==", + "version": "5.2.36", + "resolved": "https://registry.npmjs.org/@cspell/dict-npm/-/dict-npm-5.2.36.tgz", + "integrity": "sha512-QeoanpVt8QrSxDQVseXn+qk4sy79TAkbgB0G7q3klsZAByr61gXd1yDQ/0wp8xXsyPx+M/BIj5Qd6B8GnozFLA==", "dev": true, "license": "MIT" }, @@ -2335,9 +2356,9 @@ "license": "MIT" }, "node_modules/@cspell/dict-public-licenses": { - "version": "2.0.15", - "resolved": "https://registry.npmjs.org/@cspell/dict-public-licenses/-/dict-public-licenses-2.0.15.tgz", - "integrity": "sha512-cJEOs901H13Pfy0fl4dCD1U+xpWIMaEPq8MeYU83FfDZvellAuSo4GqWCripfIqlhns/L6+UZEIJSOZnjgy7Wg==", + "version": "2.0.16", + "resolved": "https://registry.npmjs.org/@cspell/dict-public-licenses/-/dict-public-licenses-2.0.16.tgz", + "integrity": "sha512-EQRrPvEOmwhwWezV+W7LjXbIBjiy6y/shrET6Qcpnk3XANTzfvWflf9PnJ5kId/oKWvihFy0za0AV1JHd03pSQ==", "dev": true, "license": "MIT" }, @@ -2387,9 +2408,9 @@ "license": "MIT" }, "node_modules/@cspell/dict-software-terms": { - "version": "5.1.21", - "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-5.1.21.tgz", - "integrity": "sha512-3lAB4OXsf6rs5zbwe4/nKmwyAJAvjs5KTRrPckzHx7q9dYpviW+UxDyhevCCsRfmcu24OhYP7BVQWXxLvYk4xA==", + "version": "5.1.24", + "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-5.1.24.tgz", + "integrity": "sha512-Y+5b5mw8lnovcoyuiVJJX5PpNPMbdpNyILR4wJDsUMWPK2ZVcl0yyG2UYJmevY7jq/+LY48Ai9RSp0ARAlDzEQ==", "dev": true, "license": "MIT" }, @@ -2654,9 +2675,9 @@ } }, "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", - "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", "dev": true, "license": "MIT", "engines": { @@ -2664,20 +2685,33 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.1.tgz", - "integrity": "sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==", + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", "dev": true, "license": "Apache-2.0", "dependencies": { "@eslint/object-schema": "^2.1.7", "debug": "^4.3.1", - "minimatch": "^3.1.2" + "minimatch": "^3.1.5" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@eslint/config-helpers": { "version": "0.4.2", "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", @@ -2705,9 +2739,9 @@ } }, "node_modules/@eslint/eslintrc": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.4.tgz", - "integrity": "sha512-4h4MVF8pmBsncB60r0wSJiIeUKTSD4m7FmTFThG8RHlsg9ajqckLm9OraguFGZE4vVdpiI1Q4+hFnisopmG6gQ==", + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", + "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", "dev": true, "license": "MIT", "dependencies": { @@ -2718,7 +2752,7 @@ "ignore": "^5.2.0", "import-fresh": "^3.2.1", "js-yaml": "^4.1.1", - "minimatch": "^3.1.3", + "minimatch": "^3.1.5", "strip-json-comments": "^3.1.1" }, "engines": { @@ -2742,9 +2776,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.3.tgz", - "integrity": "sha512-M2GCs7Vk83NxkUyQV1bkABc4yxgz9kILhHImZiBPAZ9ybuvCb0/H7lEl5XvIg3g+9d4eNotkZA5IWwYl0tibaA==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -2755,9 +2789,9 @@ } }, "node_modules/@eslint/js": { - "version": "9.39.3", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.3.tgz", - "integrity": "sha512-1B1VkCq6FuUNlQvlBYb+1jDu/gV297TIs/OeiaSR9l1H27SVW55ONE1e1Vp16NqP683+xEGzxYtv4XCiDPaQiw==", + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", "dev": true, "license": "MIT", "engines": { @@ -3395,18 +3429,6 @@ "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, - "license": "MIT", - "peer": true, - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, "node_modules/@jridgewell/resolve-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", @@ -4652,9 +4674,9 @@ } }, "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", "dependencies": { @@ -4998,9 +5020,9 @@ } }, "node_modules/asn1.js/node_modules/bn.js": { - "version": "4.12.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", - "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", "license": "MIT" }, "node_modules/assert": { @@ -5067,9 +5089,9 @@ "license": "MIT" }, "node_modules/autoprefixer": { - "version": "10.4.24", - "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.24.tgz", - "integrity": "sha512-uHZg7N9ULTVbutaIsDRoUkoS8/h3bdsmVJYZ5l3wv8Cp/6UIIoRDm90hZ+BwxUj/hGBEzLxdHNSKuFpn8WOyZw==", + "version": "10.4.27", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.27.tgz", + "integrity": "sha512-NP9APE+tO+LuJGn7/9+cohklunJsXWiaWEfV3si4Gi/XHDwVNgkwr1J3RQYFIvPy76GmJ9/bW8vyoU1LcxwKHA==", "dev": true, "funding": [ { @@ -5088,7 +5110,7 @@ "license": "MIT", "dependencies": { "browserslist": "^4.28.1", - "caniuse-lite": "^1.0.30001766", + "caniuse-lite": "^1.0.30001774", "fraction.js": "^5.3.4", "picocolors": "^1.1.1", "postcss-value-parser": "^4.2.0" @@ -5147,21 +5169,21 @@ } }, "node_modules/axios": { - "version": "1.13.5", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.5.tgz", - "integrity": "sha512-cz4ur7Vb0xS4/KUN0tPWe44eqxrIu31me+fbang3ijiNscE129POzipJJA6zniq2C/Z6sJCjMimjS8Lc/GAs8Q==", + "version": "1.7.9", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", + "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", "dev": true, "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.11", - "form-data": "^4.0.5", + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", "proxy-from-env": "^1.1.0" } }, "node_modules/babel-loader": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-10.0.0.tgz", - "integrity": "sha512-z8jt+EdS61AMw22nSfoNJAZ0vrtmhPRVi6ghL3rCeRZI8cdNYFiV5xeV3HbE7rlZZNmGH8BVccwWt8/ED0QOHA==", + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-10.1.0.tgz", + "integrity": "sha512-5HTUZa013O4SWEYlJDHexrqSIYkWatfA9w/ZZQa7V2nMc0dRWkfu/0pmioC7XMYm8M7Z/3+q42NWj6e+fAT0MQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5171,19 +5193,28 @@ "node": "^18.20.0 || ^20.10.0 || >=22.0.0" }, "peerDependencies": { - "@babel/core": "^7.12.0", + "@babel/core": "^7.12.0 || ^8.0.0-beta.1", + "@rspack/core": "^1.0.0 || ^2.0.0-0", "webpack": ">=5.61.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } } }, "node_modules/babel-plugin-polyfill-corejs2": { - "version": "0.4.15", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.15.tgz", - "integrity": "sha512-hR3GwrRwHUfYwGfrisXPIDP3JcYfBrW7wKE7+Au6wDYl7fm/ka1NEII6kORzxNU556JjfidZeBsO10kYvtV1aw==", + "version": "0.4.16", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.16.tgz", + "integrity": "sha512-xaVwwSfebXf0ooE11BJovZYKhFjIvQo7TsyVpETuIeH2JHv0k/T6Y5j22pPTvqYqmpkxdlPAJlyJ0tfOJAoMxw==", "dev": true, "license": "MIT", "dependencies": { "@babel/compat-data": "^7.28.6", - "@babel/helper-define-polyfill-provider": "^0.6.6", + "@babel/helper-define-polyfill-provider": "^0.6.7", "semver": "^6.3.1" }, "peerDependencies": { @@ -5205,13 +5236,13 @@ } }, "node_modules/babel-plugin-polyfill-regenerator": { - "version": "0.6.6", - "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.6.tgz", - "integrity": "sha512-hYm+XLYRMvupxiQzrvXUj7YyvFFVfv5gI0R71AJzudg1g2AI2vyCPPIFEBjk162/wFzti3inBHo7isWFuEVS/A==", + "version": "0.6.7", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.6.7.tgz", + "integrity": "sha512-OTYbUlSwXhNgr4g6efMZgsO8//jA61P7ZbRX3iTT53VON8l+WQS8IAUEVo4a4cWknrg2W8Cj4gQhRYNCJ8GkAA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-define-polyfill-provider": "^0.6.6" + "@babel/helper-define-polyfill-provider": "^0.6.7" }, "peerDependencies": { "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" @@ -5285,9 +5316,9 @@ "license": "MIT" }, "node_modules/basic-ftp": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.2.0.tgz", - "integrity": "sha512-VoMINM2rqJwJgfdHq6RiUudKt2BV+FY5ZFezP/ypmwayk68+NzzAQy4XXLlqsGD4MCzq3DrmNFD/uUmBJuGoXw==", + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", + "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", "dev": true, "license": "MIT", "engines": { @@ -5416,9 +5447,9 @@ "license": "BSD-3-Clause" }, "node_modules/bn.js": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.3.tgz", - "integrity": "sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", "license": "MIT" }, "node_modules/body": { @@ -5434,24 +5465,24 @@ } }, "node_modules/body-parser": { - "version": "1.20.4", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", - "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dev": true, "license": "MIT", "dependencies": { - "bytes": "~3.1.2", + "bytes": "3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", - "destroy": "~1.2.0", - "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", - "on-finished": "~2.4.1", - "qs": "~6.14.0", - "raw-body": "~2.5.3", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.13.0", + "raw-body": "2.5.2", "type-is": "~1.6.18", - "unpipe": "~1.0.0" + "unpipe": "1.0.0" }, "engines": { "node": ">= 0.8", @@ -5479,24 +5510,20 @@ } }, "node_modules/body-parser/node_modules/http-errors": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", - "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", "dev": true, "license": "MIT", "dependencies": { - "depd": "~2.0.0", - "inherits": "~2.0.4", - "setprototypeof": "~1.2.0", - "statuses": "~2.0.2", - "toidentifier": "~1.0.1" + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" }, "engines": { "node": ">= 0.8" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" } }, "node_modules/body-parser/node_modules/iconv-lite": { @@ -5533,13 +5560,13 @@ } }, "node_modules/body-parser/node_modules/qs": { - "version": "6.14.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", - "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.1.0" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -5549,16 +5576,16 @@ } }, "node_modules/body-parser/node_modules/raw-body": { - "version": "2.5.3", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", - "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", "dev": true, "license": "MIT", "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", - "unpipe": "~1.0.0" + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" }, "engines": { "node": ">= 0.8" @@ -5572,9 +5599,9 @@ "license": "ISC" }, "node_modules/body-parser/node_modules/statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "dev": true, "license": "MIT", "engines": { @@ -5707,9 +5734,9 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", - "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, "license": "MIT", "dependencies": { @@ -5795,23 +5822,24 @@ } }, "node_modules/browserify-sign": { - "version": "4.2.5", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.5.tgz", - "integrity": "sha512-C2AUdAJg6rlM2W5QMp2Q4KGQMVBwR1lIimTsUnutJ8bMpW5B52pGpR2gEnNBNwijumDo5FojQ0L9JrXA8m4YEw==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.3.tgz", + "integrity": "sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==", "license": "ISC", "dependencies": { - "bn.js": "^5.2.2", - "browserify-rsa": "^4.1.1", + "bn.js": "^5.2.1", + "browserify-rsa": "^4.1.0", "create-hash": "^1.2.0", "create-hmac": "^1.1.7", - "elliptic": "^6.6.1", + "elliptic": "^6.5.5", + "hash-base": "~3.0", "inherits": "^2.0.4", - "parse-asn1": "^5.1.9", + "parse-asn1": "^5.1.7", "readable-stream": "^2.3.8", "safe-buffer": "^5.2.1" }, "engines": { - "node": ">= 0.10" + "node": ">= 0.12" } }, "node_modules/browserify-zlib": { @@ -6056,9 +6084,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001769", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001769.tgz", - "integrity": "sha512-BCfFL1sHijQlBGWBMuJyhZUhzo7wer5sVj9hqekB/7xn0Ypy+pER/edCYQm4exbXj4WiySGp40P8UuTh6w1srg==", + "version": "1.0.30001777", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001777.tgz", + "integrity": "sha512-tmN+fJxroPndC74efCdp12j+0rk0RHwV5Jwa1zWaFVyw2ZxAuPeG8ZgWC3Wz7uSjT3qMRQ5XHZ4COgQmsCMJAQ==", "dev": true, "funding": [ { @@ -6492,14 +6520,13 @@ } }, "node_modules/comment-json": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.5.1.tgz", - "integrity": "sha512-taEtr3ozUmOB7it68Jll7s0Pwm+aoiHyXKrEC8SEodL4rNpdfDLqa7PfBlrgFoCNNdR8ImL+muti5IGvktJAAg==", + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.6.2.tgz", + "integrity": "sha512-R2rze/hDX30uul4NZoIZ76ImSJLFxn/1/ZxtKC1L77y2X1k+yYu1joKbAtMA2Fg3hZrTOiw0I5mwVMo0cf250w==", "dev": true, "license": "MIT", "dependencies": { "array-timsort": "^1.0.3", - "core-util-is": "^1.0.3", "esprima": "^4.0.1" }, "engines": { @@ -6568,9 +6595,9 @@ } }, "node_modules/compression": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", - "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.5.tgz", + "integrity": "sha512-bQJ0YRck5ak3LgtnpKkiabX5pNF7tMUh1BSy2ZBOTh0Dim0BUu6aPPwByIns6/A5Prh8PufSPerMDUklpzes2Q==", "dev": true, "license": "MIT", "dependencies": { @@ -6578,7 +6605,7 @@ "compressible": "~2.0.18", "debug": "2.6.9", "negotiator": "~0.6.4", - "on-headers": "~1.1.0", + "on-headers": "~1.0.2", "safe-buffer": "5.2.1", "vary": "~1.1.2" }, @@ -6905,9 +6932,9 @@ } }, "node_modules/create-ecdh/node_modules/bn.js": { - "version": "4.12.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", - "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", "license": "MIT" }, "node_modules/create-hash": { @@ -8157,15 +8184,16 @@ } }, "node_modules/diffie-hellman/node_modules/bn.js": { - "version": "4.12.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", - "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", "license": "MIT" }, "node_modules/discontinuous-range": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/discontinuous-range/-/discontinuous-range-1.0.0.tgz", - "integrity": "sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ==" + "integrity": "sha512-c68LpLbO+7kP/b1Hr1qs8/BJ09F5khZGTxqxZuhzxpmwJKOgRFHJWIb9/KmqnqHhLdO55aOxFH/EGBvUQbL/RQ==", + "license": "MIT" }, "node_modules/dns-packet": { "version": "5.6.1", @@ -8245,10 +8273,13 @@ } }, "node_modules/dompurify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.1.tgz", - "integrity": "sha512-qkdCKzLNtrgPFP1Vo+98FRzJnBRGe4ffyCea9IwHB1fyxPOeNTHpLKYGd4Uk9xvNoH0ZoOjwZxNptyMwqrId1Q==", + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.2.tgz", + "integrity": "sha512-6obghkliLdmKa56xdbLOpUZ43pAR6xFy1uOrxBaIDjT+yaRuuybLjGS9eVBoSR/UPU5fq3OXClEHLJNGvbxKpQ==", "license": "(MPL-2.0 OR Apache-2.0)", + "engines": { + "node": ">=20" + }, "optionalDependencies": { "@types/trusted-types": "^2.0.7" } @@ -8366,9 +8397,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.5.302", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.302.tgz", - "integrity": "sha512-sM6HAN2LyK82IyPBpznDRqlTQAtuSaO+ShzFiWTvoMJLHyZ+Y39r8VMfHzwbU8MVBzQ4Wdn85+wlZl2TLGIlwg==", + "version": "1.5.307", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.307.tgz", + "integrity": "sha512-5z3uFKBWjiNR44nFcYdkcXjKMbg5KXNdciu7mhTPo9tB7NbqSNP2sSnGR+fqknZSCwKkBN+oxiiajWs4dT6ORg==", "dev": true, "license": "ISC" }, @@ -8388,9 +8419,9 @@ } }, "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", - "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", "license": "MIT" }, "node_modules/emoji-regex": { @@ -8431,9 +8462,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.19.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.19.0.tgz", - "integrity": "sha512-phv3E1Xl4tQOShqSte26C7Fl84EwUdZsyOuSSk9qtAGyyQs2s3jJzComh+Abf4g187lUUAvH+H26omrqia2aGg==", + "version": "5.20.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.0.tgz", + "integrity": "sha512-/ce7+jQ1PQ6rVXwe+jKEg5hW5ciicHwIQUagZkp6IufBoY3YDgdTTY1azVs0qoRgVmvsNB+rbjLJxDAeHHtwsQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8544,6 +8575,13 @@ "dev": true, "license": "MIT" }, + "node_modules/es-module-lexer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", + "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", + "dev": true, + "license": "MIT" + }, "node_modules/es-object-atoms": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", @@ -8556,22 +8594,6 @@ "node": ">= 0.4" } }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/es6-object-assign": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", @@ -8653,25 +8675,25 @@ } }, "node_modules/eslint": { - "version": "9.39.3", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.3.tgz", - "integrity": "sha512-VmQ+sifHUbI/IcSopBCF/HO3YiHQx/AVd3UVyYL6weuwW+HvON9VYn5l6Zl1WZzPWXPNZrSQpxwkkZ/VuvJZzg==", + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.4.tgz", + "integrity": "sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==", "dev": true, "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.1", + "@eslint/config-array": "^0.21.2", "@eslint/config-helpers": "^0.4.2", "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.39.3", + "@eslint/eslintrc": "^3.3.5", + "@eslint/js": "9.39.4", "@eslint/plugin-kit": "^0.4.1", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", - "ajv": "^6.12.4", + "ajv": "^6.14.0", "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", @@ -8690,7 +8712,7 @@ "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", + "minimatch": "^3.1.5", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, @@ -8873,6 +8895,19 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/eslint/node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -8931,9 +8966,9 @@ } }, "node_modules/esquery": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", - "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -9091,40 +9126,40 @@ } }, "node_modules/express": { - "version": "4.22.1", - "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", - "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", + "version": "4.21.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", + "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", "dev": true, "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "~1.20.3", - "content-disposition": "~0.5.4", + "body-parser": "1.20.3", + "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "~0.7.1", - "cookie-signature": "~1.0.6", + "cookie": "0.7.1", + "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "~1.3.1", - "fresh": "~0.5.2", - "http-errors": "~2.0.0", + "finalhandler": "1.3.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", - "on-finished": "~2.4.1", + "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "~0.1.12", + "path-to-regexp": "0.1.12", "proxy-addr": "~2.0.7", - "qs": "~6.14.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "~0.19.0", - "serve-static": "~1.16.2", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", - "statuses": "~2.0.1", + "statuses": "2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" @@ -9214,13 +9249,13 @@ } }, "node_modules/express/node_modules/qs": { - "version": "6.14.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", - "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.1.0" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -9418,9 +9453,9 @@ } }, "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "license": "MIT", "dependencies": { @@ -9583,9 +9618,9 @@ "license": "ISC" }, "node_modules/follow-redirects": { - "version": "1.15.11", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", - "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "version": "1.15.9", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", + "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", "dev": true, "funding": [ { @@ -9666,16 +9701,14 @@ } }, "node_modules/form-data": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", - "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", "dev": true, "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "hasown": "^2.0.2", "mime-types": "^2.1.12" }, "engines": { @@ -10520,9 +10553,9 @@ } }, "node_modules/grunt/node_modules/js-yaml": { - "version": "3.14.2", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", - "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, "license": "MIT", "dependencies": { @@ -10791,9 +10824,9 @@ } }, "node_modules/html-entities": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.6.0.tgz", - "integrity": "sha512-kig+rMn/QOVRvr7c86gQ8lWXq+Hkv6CbAH1hLu+RG338StTpE8Z0b44SDVaqVu7HGKf27frdmUYEs9hTUX/cLQ==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", + "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", "dev": true, "funding": [ { @@ -10986,9 +11019,9 @@ } }, "node_modules/http-proxy-middleware": { - "version": "2.0.9", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz", - "integrity": "sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz", + "integrity": "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==", "dev": true, "license": "MIT", "dependencies": { @@ -11958,15 +11991,16 @@ } }, "node_modules/jake": { - "version": "10.9.4", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.4.tgz", - "integrity": "sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==", + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.2.tgz", + "integrity": "sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "async": "^3.2.6", + "async": "^3.2.3", + "chalk": "^4.0.2", "filelist": "^1.0.4", - "picocolors": "^1.1.1" + "minimatch": "^3.1.2" }, "bin": { "jake": "bin/cli.js" @@ -11975,6 +12009,52 @@ "node": ">=10" } }, + "node_modules/jake/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jake/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jake/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/jest-worker": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", @@ -12301,23 +12381,23 @@ } }, "node_modules/jwa": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", - "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", "license": "MIT", "dependencies": { - "buffer-equal-constant-time": "^1.0.1", + "buffer-equal-constant-time": "1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "node_modules/jws": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.3.tgz", - "integrity": "sha512-byiJ0FLRdLdSVSReO/U4E7RoEyOCKnEnEPMjq3HxWtvzLsV08/i5RQKsFVNkCldrCaPr2vDNAOMsfs8T/Hze7g==", + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", "license": "MIT", "dependencies": { - "jwa": "^1.4.2", + "jwa": "^1.4.1", "safe-buffer": "^5.0.1" } }, @@ -12912,9 +12992,9 @@ } }, "node_modules/miller-rabin/node_modules/bn.js": { - "version": "4.12.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", - "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", "license": "MIT" }, "node_modules/mime": { @@ -13109,9 +13189,9 @@ } }, "node_modules/mocha/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", "dev": true, "license": "ISC", "dependencies": { @@ -13173,9 +13253,10 @@ } }, "node_modules/moo": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz", - "integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q==" + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.3.tgz", + "integrity": "sha512-m2fmM2dDm7GZQsY7KK2cme8agi+AAljILjQnof7p1ZMDe6dQ4bdnSMx0cPppudoeNv5hEFQirN6u+O4fDE0IWA==", + "license": "BSD-3-Clause" }, "node_modules/more-entropy": { "version": "0.0.7", @@ -13186,9 +13267,9 @@ } }, "node_modules/morgan": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.1.tgz", - "integrity": "sha512-223dMRJtI/l25dJKWpgij2cMtywuG/WiUKXdvwfbhGKBhy1puASqXwFzmWZ7+K73vUPoR7SS2Qz2cI/g9MKw0A==", + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", + "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", "dev": true, "license": "MIT", "dependencies": { @@ -13196,7 +13277,7 @@ "debug": "2.6.9", "depd": "~2.0.0", "on-finished": "~2.3.0", - "on-headers": "~1.1.0" + "on-headers": "~1.0.2" }, "engines": { "node": ">= 0.8.0" @@ -13286,6 +13367,7 @@ "version": "2.20.1", "resolved": "https://registry.npmjs.org/nearley/-/nearley-2.20.1.tgz", "integrity": "sha512-+Mc8UaAebFzgV+KpI5n7DasuuQCHA89dmwm7JXw3TV43ukfNQ9DnBH3Mdb2g/I4Fdxc26pwimBWvjIw0UAILSQ==", + "license": "MIT", "dependencies": { "commander": "^2.19.0", "moo": "^0.5.0", @@ -13306,7 +13388,8 @@ "node_modules/nearley/node_modules/commander": { "version": "2.20.3", "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT" }, "node_modules/negotiator": { "version": "0.6.3", @@ -13628,9 +13711,9 @@ "license": "CC0-1.0" }, "node_modules/node-releases": { - "version": "2.0.27", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.27.tgz", - "integrity": "sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==", + "version": "2.0.36", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.36.tgz", + "integrity": "sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==", "dev": true, "license": "MIT" }, @@ -13862,9 +13945,9 @@ } }, "node_modules/on-headers": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", - "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", "dev": true, "license": "MIT", "engines": { @@ -14226,15 +14309,16 @@ } }, "node_modules/parse-asn1": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.9.tgz", - "integrity": "sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==", + "version": "5.1.7", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.7.tgz", + "integrity": "sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==", "license": "ISC", "dependencies": { "asn1.js": "^4.10.1", "browserify-aes": "^1.2.0", "evp_bytestokey": "^1.0.3", - "pbkdf2": "^3.1.5", + "hash-base": "~3.0", + "pbkdf2": "^3.1.2", "safe-buffer": "^5.2.1" }, "engines": { @@ -14470,20 +14554,19 @@ } }, "node_modules/pbkdf2": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.5.tgz", - "integrity": "sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", "license": "MIT", "dependencies": { - "create-hash": "^1.2.0", - "create-hmac": "^1.1.7", - "ripemd160": "^2.0.3", - "safe-buffer": "^5.2.1", - "sha.js": "^2.4.12", - "to-buffer": "^1.2.1" + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" }, "engines": { - "node": ">= 0.10" + "node": ">=0.12" } }, "node_modules/peek-readable": { @@ -14631,9 +14714,9 @@ } }, "node_modules/postcss": { - "version": "8.5.6", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz", - "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==", + "version": "8.5.8", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", "dev": true, "funding": [ { @@ -15002,9 +15085,9 @@ } }, "node_modules/public-encrypt/node_modules/bn.js": { - "version": "4.12.3", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", - "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", + "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", "license": "MIT" }, "node_modules/pump": { @@ -15075,9 +15158,9 @@ "license": "MIT" }, "node_modules/qs": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz", - "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==", + "version": "6.14.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", + "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" @@ -15112,12 +15195,14 @@ "node_modules/railroad-diagrams": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/railroad-diagrams/-/railroad-diagrams-1.0.0.tgz", - "integrity": "sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A==" + "integrity": "sha512-cz93DjNeLY0idrCNOH6PviZGRN9GJhsdm9hpn1YCS879fj4W+x5IFJhhkRZcwVgMmFF7R82UA/7Oh+R8lLZg6A==", + "license": "CC0-1.0" }, "node_modules/randexp": { "version": "0.4.6", "resolved": "https://registry.npmjs.org/randexp/-/randexp-0.4.6.tgz", "integrity": "sha512-80WNmd9DA0tmZrw9qQa62GPPWfuXJknrmVmLcxvq4uZBdYqb1wYoKTmnlGUchvVWe0XiLupYkBoXVOxz3C8DYQ==", + "license": "MIT", "dependencies": { "discontinuous-range": "1.0.0", "ret": "~0.1.10" @@ -15272,9 +15357,9 @@ } }, "node_modules/readdir-glob/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "license": "MIT", "dependencies": { @@ -15554,6 +15639,7 @@ "version": "0.1.15", "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "license": "MIT", "engines": { "node": ">=0.12" } @@ -15593,31 +15679,13 @@ } }, "node_modules/ripemd160": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz", - "integrity": "sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", "license": "MIT", "dependencies": { - "hash-base": "^3.1.2", - "inherits": "^2.0.4" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/ripemd160/node_modules/hash-base": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.2.tgz", - "integrity": "sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==", - "license": "MIT", - "dependencies": { - "inherits": "^2.0.4", - "readable-stream": "^2.3.8", - "safe-buffer": "^5.2.1", - "to-buffer": "^1.2.1" - }, - "engines": { - "node": ">= 0.8" + "hash-base": "^3.0.0", + "inherits": "^2.0.1" } }, "node_modules/rison": { @@ -15747,9 +15815,9 @@ } }, "node_modules/schema-utils/node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "version": "8.17.1", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", + "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", "dev": true, "license": "MIT", "dependencies": { @@ -16054,23 +16122,16 @@ "license": "ISC" }, "node_modules/sha.js": { - "version": "2.4.12", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", - "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", "license": "(MIT AND BSD-3-Clause)", "dependencies": { - "inherits": "^2.0.4", - "safe-buffer": "^5.2.1", - "to-buffer": "^1.2.0" + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" }, "bin": { "sha.js": "bin.js" - }, - "engines": { - "node": ">= 0.10" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" } }, "node_modules/shebang-command": { @@ -16202,12 +16263,12 @@ "license": "ISC" }, "node_modules/simple-xml-to-json": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/simple-xml-to-json/-/simple-xml-to-json-1.2.2.tgz", - "integrity": "sha512-bmJJf5YiYL60eOQk3gaVxbM6vgYuwrFydCEAA2x3jccHUTsAffiPyblS/yQGr8GDUQVxSDm3WwLNL5HmRqDUcg==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/simple-xml-to-json/-/simple-xml-to-json-1.2.3.tgz", + "integrity": "sha512-kWJDCr9EWtZ+/EYYM5MareWj2cRnZGF93YDNpH4jQiHB+hBIZnfPFSQiVMzZOdk+zXWqTZ/9fTeQNu2DqeiudA==", "license": "MIT", "engines": { - "node": ">=14.20.0" + "node": ">=20.12.2" } }, "node_modules/sirv": { @@ -16226,9 +16287,9 @@ } }, "node_modules/sitemap": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-8.0.2.tgz", - "integrity": "sha512-LwktpJcyZDoa0IL6KT++lQ53pbSrx2c9ge41/SeLTyqy2XUNA6uR4+P9u5IVo5lPeL2arAcOKn1aZAxoYbCKlQ==", + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/sitemap/-/sitemap-8.0.3.tgz", + "integrity": "sha512-9Ew1tR2WYw8RGE2XLy7GjkusvYXy8Rg6y8TYuBuQMfIEdGcWoJpY2Wr5DzsEiL/TKCw56+YKTCCUHglorEYK+A==", "dev": true, "license": "MIT", "dependencies": { @@ -16465,9 +16526,10 @@ "license": "BSD-3-Clause" }, "node_modules/sql-formatter": { - "version": "15.6.5", - "resolved": "https://registry.npmjs.org/sql-formatter/-/sql-formatter-15.6.5.tgz", - "integrity": "sha512-fr4TyM1udCSrOHOmouotwUi8dxIDhSLpYNmPePGFVzxq8/i8jd828IapE49QXG7Gzkswxo5WwdAGnYX4YpKoTg==", + "version": "15.7.2", + "resolved": "https://registry.npmjs.org/sql-formatter/-/sql-formatter-15.7.2.tgz", + "integrity": "sha512-b0BGoM81KFRVSpZFwPpIPU5gng4YD8DI/taLD96NXCFRf5af3FzSE4aSwjKmxcyTmf/MfPu91j75883nRrWDBw==", + "license": "MIT", "dependencies": { "argparse": "^2.0.1", "nearley": "^2.20.1" @@ -16893,16 +16955,15 @@ } }, "node_modules/terser-webpack-plugin": { - "version": "5.3.16", - "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.16.tgz", - "integrity": "sha512-h9oBFCWrq78NyWWVcSwZarJkZ01c2AyGrzs1crmHZO3QUg9D61Wu4NPjBy69n7JqylFF5y+CsUZYmYEIZ3mR+Q==", + "version": "5.3.17", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.17.tgz", + "integrity": "sha512-YR7PtUp6GMU91BgSJmlaX/rS2lGDbAF7D+Wtq7hRO+MiljNmodYvqslzCFiYVAgW+Qoaaia/QUIP4lGXufjdZw==", "dev": true, "license": "MIT", "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "jest-worker": "^27.4.5", "schema-utils": "^4.3.0", - "serialize-javascript": "^6.0.2", "terser": "^5.31.1" }, "engines": { @@ -16953,9 +17014,9 @@ } }, "node_modules/tesseract.js-core": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/tesseract.js-core/-/tesseract.js-core-6.0.0.tgz", - "integrity": "sha512-1Qncm/9oKM7xgrQXZXNB+NRh19qiXGhxlrR8EwFbK5SaUbPZnS5OMtP/ghtqfd23hsr1ZvZbZjeuAGcMxd/ooA==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/tesseract.js-core/-/tesseract.js-core-6.1.2.tgz", + "integrity": "sha512-pv4GjmramjdObhDyR1q85Td8X60Puu/lGQn7Kw2id05LLgHhAcWgnz6xSdMCSxBMWjQDmMyDXPTC2aqADdpiow==", "license": "Apache-2.0" }, "node_modules/thingies": { @@ -17069,35 +17130,15 @@ } }, "node_modules/tmp": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", - "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", "dev": true, "license": "MIT", "engines": { "node": ">=14.14" } }, - "node_modules/to-buffer": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", - "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==", - "license": "MIT", - "dependencies": { - "isarray": "^2.0.5", - "safe-buffer": "^5.2.1", - "typed-array-buffer": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/to-buffer/node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "license": "MIT" - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -17270,20 +17311,6 @@ "node": ">= 0.6" } }, - "node_modules/typed-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", - "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/ua-parser-js": { "version": "1.0.41", "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.41.tgz", @@ -17703,9 +17730,9 @@ } }, "node_modules/webpack": { - "version": "5.105.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.2.tgz", - "integrity": "sha512-dRXm0a2qcHPUBEzVk8uph0xWSjV/xZxenQQbLwnwP7caQCYpqG1qddwlyEkIDkYn0K8tvmcrZ+bOrzoQ3HxCDw==", + "version": "5.105.4", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.105.4.tgz", + "integrity": "sha512-jTywjboN9aHxFlToqb0K0Zs9SbBoW4zRUlGzI2tYNxVYcEi/IPpn+Xi4ye5jTLvX2YeLuic/IvxNot+Q1jMoOw==", "dev": true, "license": "MIT", "dependencies": { @@ -17715,11 +17742,11 @@ "@webassemblyjs/ast": "^1.14.1", "@webassemblyjs/wasm-edit": "^1.14.1", "@webassemblyjs/wasm-parser": "^1.14.1", - "acorn": "^8.15.0", + "acorn": "^8.16.0", "acorn-import-phases": "^1.0.3", "browserslist": "^4.28.1", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.19.0", + "enhanced-resolve": "^5.20.0", "es-module-lexer": "^2.0.0", "eslint-scope": "5.1.1", "events": "^3.2.0", @@ -17731,9 +17758,9 @@ "neo-async": "^2.6.2", "schema-utils": "^4.3.3", "tapable": "^2.3.0", - "terser-webpack-plugin": "^5.3.16", + "terser-webpack-plugin": "^5.3.17", "watchpack": "^2.5.1", - "webpack-sources": "^3.3.3" + "webpack-sources": "^3.3.4" }, "bin": { "webpack": "bin/webpack.js" @@ -17917,9 +17944,9 @@ } }, "node_modules/webpack-dev-server/node_modules/brace-expansion": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", - "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dev": true, "license": "MIT", "dependencies": { @@ -17940,10 +17967,9 @@ } }, "node_modules/webpack-dev-server/node_modules/glob": { - "version": "10.5.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", - "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", - "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "version": "10.4.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", + "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", "dev": true, "license": "ISC", "dependencies": { @@ -18048,13 +18074,6 @@ "node": ">=10.13.0" } }, - "node_modules/webpack/node_modules/es-module-lexer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.0.0.tgz", - "integrity": "sha512-5POEcUuZybH7IdmGsD8wlf0AI55wMecM9rVBTI/qEAy2c1kTOm3DjFYjrBdI2K3BaJjJYfYFeRtM0t9ssnRuxw==", - "dev": true, - "license": "MIT" - }, "node_modules/websocket-driver": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", diff --git a/package.json b/package.json index 1602b1b6..d3519e0f 100644 --- a/package.json +++ b/package.json @@ -93,6 +93,7 @@ "worker-loader": "^3.0.8" }, "dependencies": { + "@alexaltea/capstone-js": "^3.0.5", "@astronautlabs/amf": "^0.0.6", "@blu3r4y/lzma": "^2.3.3", "@wavesenterprise/crypto-gost-js": "^2.1.0-RC1", diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index f03fb8ea..8b62046e 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -559,6 +559,7 @@ "Chi Square", "P-list Viewer", "Disassemble x86", + "Disassemble ARM", "Pseudo-Random Number Generator", "Pseudo-Random Integer Generator", "Generate De Bruijn Sequence", diff --git a/src/core/operations/DisassembleARM.mjs b/src/core/operations/DisassembleARM.mjs new file mode 100644 index 00000000..d8cb56da --- /dev/null +++ b/src/core/operations/DisassembleARM.mjs @@ -0,0 +1,193 @@ +/** + * @author MedjedThomasXM + * @copyright Crown Copyright 2024 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import OperationError from "../errors/OperationError.mjs"; +import { isWorkerEnvironment } from "../Utils.mjs"; +import cs from "@alexaltea/capstone-js/dist/capstone.min.js"; + +/** + * Disassemble ARM operation + */ +class DisassembleARM extends Operation { + + /** + * DisassembleARM constructor + */ + constructor() { + super(); + + this.name = "Disassemble ARM"; + this.module = "Shellcode"; + this.description = "Disassembles ARM machine code into assembly language.

Supports ARM (32-bit), Thumb, and ARM64 (AArch64) architectures using the Capstone disassembly framework.

Input should be in hexadecimal."; + this.infoURL = "https://wikipedia.org/wiki/ARM_architecture_family"; + this.inputType = "string"; + this.outputType = "string"; + this.args = [ + { + "name": "Architecture", + "type": "option", + "value": ["ARM (32-bit)", "ARM64 (AArch64)"] + }, + { + "name": "Mode", + "type": "option", + "value": ["ARM", "Thumb", "Thumb + Cortex-M", "ARMv8"] + }, + { + "name": "Endianness", + "type": "option", + "value": ["Little Endian", "Big Endian"] + }, + { + "name": "Starting address (hex)", + "type": "number", + "value": 0 + }, + { + "name": "Show instruction hex", + "type": "boolean", + "value": true + }, + { + "name": "Show instruction position", + "type": "boolean", + "value": true + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {string} + */ + async run(input, args) { + const [ + architecture, + mode, + endianness, + startAddress, + showHex, + showPosition + ] = args; + + // Remove whitespace from input + const hexInput = input.replace(/\s/g, ""); + + // Validate hex input + if (!/^[0-9a-fA-F]*$/.test(hexInput)) { + throw new OperationError("Invalid hexadecimal input. Please provide valid hex characters only."); + } + + if (hexInput.length === 0) { + return ""; + } + + if (hexInput.length % 2 !== 0) { + throw new OperationError("Invalid hexadecimal input. Length must be even."); + } + + // Convert hex string to byte array + const bytes = []; + for (let i = 0; i < hexInput.length; i += 2) { + bytes.push(parseInt(hexInput.substr(i, 2), 16)); + } + + // Determine architecture constant + let arch; + if (architecture === "ARM64 (AArch64)") { + arch = cs.ARCH_ARM64; + } else { + arch = cs.ARCH_ARM; + } + + // Determine mode constant + let modeValue = cs.MODE_LITTLE_ENDIAN; + + if (architecture === "ARM (32-bit)") { + switch (mode) { + case "ARM": + modeValue = cs.MODE_ARM; + break; + case "Thumb": + modeValue = cs.MODE_THUMB; + break; + case "Thumb + Cortex-M": + modeValue = cs.MODE_THUMB | cs.MODE_MCLASS; + break; + case "ARMv8": + modeValue = cs.MODE_ARM | cs.MODE_V8; + break; + default: + modeValue = cs.MODE_ARM; + } + } else { + // ARM64 only has one mode (ARM mode is default for ARM64) + modeValue = cs.MODE_ARM; + } + + // Add endianness + if (endianness === "Big Endian") { + modeValue |= cs.MODE_BIG_ENDIAN; + } + + if (isWorkerEnvironment()) { + self.sendStatusMessage("Disassembling..."); + } + + let disassembler; + try { + disassembler = new cs.Capstone(arch, modeValue); + } catch (e) { + throw new OperationError(`Failed to initialise Capstone disassembler: ${e}`); + } + + let instructions; + try { + instructions = disassembler.disasm(bytes, startAddress); + } catch (e) { + disassembler.close(); + // Check if it's a "no valid instructions" error (code 0 means OK but nothing decoded) + if (e && e.includes && e.includes("code 0:")) { + throw new OperationError(`No valid ${architecture} instructions found in input. The bytes may be for a different architecture or mode.`); + } + throw new OperationError(`Disassembly failed: ${e}`); + } + + // Format output + const output = []; + for (const insn of instructions) { + let line = ""; + + if (showPosition) { + // Format address as hex with 0x prefix + const addrHex = "0x" + insn.address.toString(16).padStart(8, "0"); + line += addrHex + " "; + } + + if (showHex) { + // Format instruction bytes as hex + const bytesHex = insn.bytes.map(b => b.toString(16).padStart(2, "0")).join(""); + line += bytesHex.padEnd(16, " ") + " "; + } + + line += insn.mnemonic; + if (insn.op_str) { + line += " " + insn.op_str; + } + + output.push(line); + } + + disassembler.close(); + + return output.join("\n"); + } + +} + +export default DisassembleARM; diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs index 48ff4c8e..fb03a5f7 100644 --- a/tests/operations/index.mjs +++ b/tests/operations/index.mjs @@ -61,6 +61,7 @@ import "./tests/Crypt.mjs"; import "./tests/CSV.mjs"; import "./tests/DateTime.mjs"; import "./tests/DefangIP.mjs"; +import "./tests/DisassembleARM.mjs"; import "./tests/DropNthBytes.mjs"; import "./tests/ECDSA.mjs"; import "./tests/ELFInfo.mjs"; diff --git a/tests/operations/tests/DisassembleARM.mjs b/tests/operations/tests/DisassembleARM.mjs new file mode 100644 index 00000000..5306e9ce --- /dev/null +++ b/tests/operations/tests/DisassembleARM.mjs @@ -0,0 +1,377 @@ +/** + * Disassemble ARM tests. + * + * @author MedjedThomasXM + * + * @copyright Crown Copyright 2024 + * @license Apache-2.0 + */ +import TestRegister from "../../lib/TestRegister.mjs"; + +TestRegister.addTests([ + // ==================== ARM32 TESTS ==================== + { + name: "Disassemble ARM: ARM32 NOP (mov r0, r0)", + input: "00 00 a0 e1", + expectedMatch: /mov\s+r0,\s*r0/, + recipeConfig: [ + { + op: "Disassemble ARM", + args: ["ARM (32-bit)", "ARM", "Little Endian", 0, true, true], + }, + ], + }, + { + name: "Disassemble ARM: ARM32 bx lr", + input: "1e ff 2f e1", + expectedMatch: /bx\s+lr/, + recipeConfig: [ + { + op: "Disassemble ARM", + args: ["ARM (32-bit)", "ARM", "Little Endian", 0, true, true], + }, + ], + }, + { + name: "Disassemble ARM: ARM32 push {fp, lr}", + input: "00 48 2d e9", + expectedMatch: /push\s+\{fp,\s*lr\}/, + recipeConfig: [ + { + op: "Disassemble ARM", + args: ["ARM (32-bit)", "ARM", "Little Endian", 0, true, true], + }, + ], + }, + { + name: "Disassemble ARM: ARM32 add fp, sp, #4", + input: "04 b0 8d e2", + expectedMatch: /add\s+fp,\s*sp/, + recipeConfig: [ + { + op: "Disassemble ARM", + args: ["ARM (32-bit)", "ARM", "Little Endian", 0, true, true], + }, + ], + }, + { + name: "Disassemble ARM: ARM32 ldr r0, [r1]", + input: "00 00 91 e5", + expectedMatch: /ldr\s+r0,\s*\[r1\]/, + recipeConfig: [ + { + op: "Disassemble ARM", + args: ["ARM (32-bit)", "ARM", "Little Endian", 0, true, true], + }, + ], + }, + { + name: "Disassemble ARM: ARM32 str r0, [r1]", + input: "00 00 81 e5", + expectedMatch: /str\s+r0,\s*\[r1\]/, + recipeConfig: [ + { + op: "Disassemble ARM", + args: ["ARM (32-bit)", "ARM", "Little Endian", 0, true, true], + }, + ], + }, + { + name: "Disassemble ARM: ARM32 bl (branch link)", + input: "00 00 00 eb", + expectedMatch: /bl\s+/, + recipeConfig: [ + { + op: "Disassemble ARM", + args: ["ARM (32-bit)", "ARM", "Little Endian", 0, true, true], + }, + ], + }, + { + name: "Disassemble ARM: ARM32 mul r0, r1, r2", + input: "91 02 00 e0", + expectedMatch: /mul\s+r0,\s*r1,\s*r2/, + recipeConfig: [ + { + op: "Disassemble ARM", + args: ["ARM (32-bit)", "ARM", "Little Endian", 0, true, true], + }, + ], + }, + + // ==================== ARM32 THUMB TESTS ==================== + { + name: "Disassemble ARM: Thumb mov r0, r0", + input: "00 46", + expectedMatch: /mov\s+r0,\s*r0/, + recipeConfig: [ + { + op: "Disassemble ARM", + args: ["ARM (32-bit)", "Thumb", "Little Endian", 0, true, true], + }, + ], + }, + { + name: "Disassemble ARM: Thumb bx lr", + input: "70 47", + expectedMatch: /bx\s+lr/, + recipeConfig: [ + { + op: "Disassemble ARM", + args: ["ARM (32-bit)", "Thumb", "Little Endian", 0, true, true], + }, + ], + }, + { + name: "Disassemble ARM: Thumb push {r4, lr}", + input: "10 b5", + expectedMatch: /push\s+\{r4,\s*lr\}/, + recipeConfig: [ + { + op: "Disassemble ARM", + args: ["ARM (32-bit)", "Thumb", "Little Endian", 0, true, true], + }, + ], + }, + { + name: "Disassemble ARM: Thumb pop {r4, pc}", + input: "10 bd", + expectedMatch: /pop\s+\{r4,\s*pc\}/, + recipeConfig: [ + { + op: "Disassemble ARM", + args: ["ARM (32-bit)", "Thumb", "Little Endian", 0, true, true], + }, + ], + }, + + // ==================== ARM64 TESTS ==================== + { + name: "Disassemble ARM: ARM64 ret", + input: "c0 03 5f d6", + expectedMatch: /ret/, + recipeConfig: [ + { + op: "Disassemble ARM", + args: ["ARM64 (AArch64)", "ARM", "Little Endian", 0, true, true], + }, + ], + }, + { + name: "Disassemble ARM: ARM64 mov x0, #0", + input: "00 00 80 d2", + expectedMatch: /mov[z]?\s+x0,\s*#0/, + recipeConfig: [ + { + op: "Disassemble ARM", + args: ["ARM64 (AArch64)", "ARM", "Little Endian", 0, true, true], + }, + ], + }, + { + name: "Disassemble ARM: ARM64 stp x29, x30, [sp, #-16]!", + input: "fd 7b bf a9", + expectedMatch: /stp\s+x29,\s*x30,\s*\[sp/, + recipeConfig: [ + { + op: "Disassemble ARM", + args: ["ARM64 (AArch64)", "ARM", "Little Endian", 0, true, true], + }, + ], + }, + { + name: "Disassemble ARM: ARM64 ldp x29, x30, [sp], #16", + input: "fd 7b c1 a8", + expectedMatch: /ldp\s+x29,\s*x30,\s*\[sp\]/, + recipeConfig: [ + { + op: "Disassemble ARM", + args: ["ARM64 (AArch64)", "ARM", "Little Endian", 0, true, true], + }, + ], + }, + { + name: "Disassemble ARM: ARM64 add x0, x1, x2", + input: "20 00 02 8b", + expectedMatch: /add\s+x0,\s*x1,\s*x2/, + recipeConfig: [ + { + op: "Disassemble ARM", + args: ["ARM64 (AArch64)", "ARM", "Little Endian", 0, true, true], + }, + ], + }, + { + name: "Disassemble ARM: ARM64 sub x0, x1, x2", + input: "20 00 02 cb", + expectedMatch: /sub\s+x0,\s*x1,\s*x2/, + recipeConfig: [ + { + op: "Disassemble ARM", + args: ["ARM64 (AArch64)", "ARM", "Little Endian", 0, true, true], + }, + ], + }, + { + name: "Disassemble ARM: ARM64 mul x0, x1, x2", + input: "20 7c 02 9b", + expectedMatch: /mul\s+x0,\s*x1,\s*x2/, + recipeConfig: [ + { + op: "Disassemble ARM", + args: ["ARM64 (AArch64)", "ARM", "Little Endian", 0, true, true], + }, + ], + }, + { + name: "Disassemble ARM: ARM64 ldr x0, [x1]", + input: "20 00 40 f9", + expectedMatch: /ldr\s+x0,\s*\[x1\]/, + recipeConfig: [ + { + op: "Disassemble ARM", + args: ["ARM64 (AArch64)", "ARM", "Little Endian", 0, true, true], + }, + ], + }, + { + name: "Disassemble ARM: ARM64 str x0, [x1]", + input: "20 00 00 f9", + expectedMatch: /str\s+x0,\s*\[x1\]/, + recipeConfig: [ + { + op: "Disassemble ARM", + args: ["ARM64 (AArch64)", "ARM", "Little Endian", 0, true, true], + }, + ], + }, + { + name: "Disassemble ARM: ARM64 bl (branch link)", + input: "00 00 00 94", + expectedMatch: /bl\s+/, + recipeConfig: [ + { + op: "Disassemble ARM", + args: ["ARM64 (AArch64)", "ARM", "Little Endian", 0, true, true], + }, + ], + }, + { + name: "Disassemble ARM: ARM64 cbz x0", + input: "00 00 00 b4", + expectedMatch: /cbz\s+x0/, + recipeConfig: [ + { + op: "Disassemble ARM", + args: ["ARM64 (AArch64)", "ARM", "Little Endian", 0, true, true], + }, + ], + }, + { + name: "Disassemble ARM: ARM64 cbnz x0", + input: "00 00 00 b5", + expectedMatch: /cbnz\s+x0/, + recipeConfig: [ + { + op: "Disassemble ARM", + args: ["ARM64 (AArch64)", "ARM", "Little Endian", 0, true, true], + }, + ], + }, + { + name: "Disassemble ARM: ARM64 sub sp, sp, #0x20", + input: "ff 83 00 d1", + expectedMatch: /sub\s+sp,\s*sp/, + recipeConfig: [ + { + op: "Disassemble ARM", + args: ["ARM64 (AArch64)", "ARM", "Little Endian", 0, true, true], + }, + ], + }, + { + name: "Disassemble ARM: ARM64 add sp, sp, #0x20", + input: "ff 83 00 91", + expectedMatch: /add\s+sp,\s*sp/, + recipeConfig: [ + { + op: "Disassemble ARM", + args: ["ARM64 (AArch64)", "ARM", "Little Endian", 0, true, true], + }, + ], + }, + + // ==================== MULTI-INSTRUCTION TESTS ==================== + { + name: "Disassemble ARM: ARM32 multiple instructions", + input: "00 48 2d e9 04 b0 8d e2 00 00 a0 e1 00 88 bd e8", + expectedMatch: /push.*\n.*add.*\n.*mov.*\n.*pop/s, + recipeConfig: [ + { + op: "Disassemble ARM", + args: ["ARM (32-bit)", "ARM", "Little Endian", 0, true, true], + }, + ], + }, + { + name: "Disassemble ARM: ARM64 function prologue/epilogue", + input: "fd 7b bf a9 fd 03 00 91 00 00 80 52 fd 7b c1 a8 c0 03 5f d6", + expectedMatch: /stp.*\n.*mov.*\n.*mov.*\n.*ldp.*\n.*ret/s, + recipeConfig: [ + { + op: "Disassemble ARM", + args: ["ARM64 (AArch64)", "ARM", "Little Endian", 0, true, true], + }, + ], + }, + + // ==================== ADDRESS TESTS ==================== + { + name: "Disassemble ARM: ARM64 with start address 0x1000", + input: "c0 03 5f d6", + expectedMatch: /0x00001000/, + recipeConfig: [ + { + op: "Disassemble ARM", + args: ["ARM64 (AArch64)", "ARM", "Little Endian", 4096, true, true], + }, + ], + }, + { + name: "Disassemble ARM: ARM32 with start address 0x8000", + input: "00 00 a0 e1", + expectedMatch: /0x00008000/, + recipeConfig: [ + { + op: "Disassemble ARM", + args: ["ARM (32-bit)", "ARM", "Little Endian", 32768, true, true], + }, + ], + }, + + // ==================== ENDIANNESS TESTS ==================== + { + name: "Disassemble ARM: ARM32 Big Endian", + input: "e1 a0 00 00", + expectedMatch: /mov\s+r0,\s*r0/, + recipeConfig: [ + { + op: "Disassemble ARM", + args: ["ARM (32-bit)", "ARM", "Big Endian", 0, true, true], + }, + ], + }, + + // ==================== EDGE CASES ==================== + { + name: "Disassemble ARM: Empty input", + input: "", + expectedOutput: "", + recipeConfig: [ + { + op: "Disassemble ARM", + args: ["ARM64 (AArch64)", "ARM", "Little Endian", 0, true, true], + }, + ], + }, +]); From 3f91df2381b6384a72b6e0223c4fd9ddf3d50606 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Mar 2026 15:44:02 +0000 Subject: [PATCH 11/20] Bump basic-ftp from 5.0.5 to 5.2.0 (#2231) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6ab7c7fe..82b09719 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5316,9 +5316,9 @@ "license": "MIT" }, "node_modules/basic-ftp": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.0.5.tgz", - "integrity": "sha512-4Bcg1P8xhUuqcii/S0Z9wiHIrQVPMermM1any+MX5GeGD7faD3/msQUDGLol9wOcz4/jbg/WJnGqoJF6LiBdtg==", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.2.0.tgz", + "integrity": "sha512-VoMINM2rqJwJgfdHq6RiUudKt2BV+FY5ZFezP/ypmwayk68+NzzAQy4XXLlqsGD4MCzq3DrmNFD/uUmBJuGoXw==", "dev": true, "license": "MIT", "engines": { From c39ae52f7fffc1830a9f781052d9afe745a916b3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Mar 2026 10:03:27 +0000 Subject: [PATCH 12/20] Bump form-data from 4.0.1 to 4.0.5 (#2228) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 24 +++++++++++++++++++++--- 1 file changed, 21 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 82b09719..42ddaf4a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8594,6 +8594,22 @@ "node": ">= 0.4" } }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/es6-object-assign": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/es6-object-assign/-/es6-object-assign-1.1.0.tgz", @@ -9701,14 +9717,16 @@ } }, "node_modules/form-data": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", - "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", "dev": true, "license": "MIT", "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", "mime-types": "^2.1.12" }, "engines": { From 76bf4f44db2ccbe5407e7b8ad21d299250099e25 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Mar 2026 10:29:22 +0000 Subject: [PATCH 13/20] Bump pbkdf2 from 3.1.2 to 3.1.5 (#2229) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 98 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 79 insertions(+), 19 deletions(-) diff --git a/package-lock.json b/package-lock.json index 42ddaf4a..66507f80 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14572,19 +14572,20 @@ } }, "node_modules/pbkdf2": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", - "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.5.tgz", + "integrity": "sha512-Q3CG/cYvCO1ye4QKkuH7EXxs3VC/rI1/trd+qX2+PolbaKG0H+bgcZzrTt96mMyRtejk+JMCiLUn3y29W8qmFQ==", "license": "MIT", "dependencies": { - "create-hash": "^1.1.2", - "create-hmac": "^1.1.4", - "ripemd160": "^2.0.1", - "safe-buffer": "^5.0.1", - "sha.js": "^2.4.8" + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "ripemd160": "^2.0.3", + "safe-buffer": "^5.2.1", + "sha.js": "^2.4.12", + "to-buffer": "^1.2.1" }, "engines": { - "node": ">=0.12" + "node": ">= 0.10" } }, "node_modules/peek-readable": { @@ -15697,13 +15698,31 @@ } }, "node_modules/ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz", + "integrity": "sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==", "license": "MIT", "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" + "hash-base": "^3.1.2", + "inherits": "^2.0.4" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/ripemd160/node_modules/hash-base": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.2.tgz", + "integrity": "sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.1" + }, + "engines": { + "node": ">= 0.8" } }, "node_modules/rison": { @@ -16140,16 +16159,23 @@ "license": "ISC" }, "node_modules/sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "version": "2.4.12", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", + "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", "license": "(MIT AND BSD-3-Clause)", "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.0" }, "bin": { "sha.js": "bin.js" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/shebang-command": { @@ -17157,6 +17183,26 @@ "node": ">=14.14" } }, + "node_modules/to-buffer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", + "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==", + "license": "MIT", + "dependencies": { + "isarray": "^2.0.5", + "safe-buffer": "^5.2.1", + "typed-array-buffer": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/to-buffer/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "license": "MIT" + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -17329,6 +17375,20 @@ "node": ">= 0.6" } }, + "node_modules/typed-array-buffer": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/ua-parser-js": { "version": "1.0.41", "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.41.tgz", From 64224dacb58b7dfecabf4824d55f36a14c6a1a5c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 10 Mar 2026 14:58:09 +0000 Subject: [PATCH 14/20] Bump jws from 3.2.2 to 3.2.3 (#2235) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 66507f80..4500c9c7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12399,23 +12399,23 @@ } }, "node_modules/jwa": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", - "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", + "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", "license": "MIT", "dependencies": { - "buffer-equal-constant-time": "1.0.1", + "buffer-equal-constant-time": "^1.0.1", "ecdsa-sig-formatter": "1.0.11", "safe-buffer": "^5.0.1" } }, "node_modules/jws": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", - "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.3.tgz", + "integrity": "sha512-byiJ0FLRdLdSVSReO/U4E7RoEyOCKnEnEPMjq3HxWtvzLsV08/i5RQKsFVNkCldrCaPr2vDNAOMsfs8T/Hze7g==", "license": "MIT", "dependencies": { - "jwa": "^1.4.1", + "jwa": "^1.4.2", "safe-buffer": "^5.0.1" } }, From 47ba05850bd1ea93f443c3e70e3c7db0c238cdd6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 11 Mar 2026 06:53:14 +0000 Subject: [PATCH 15/20] Bump axios from 1.7.9 to 1.13.6 (#2234) Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package-lock.json | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4500c9c7..33c3c9aa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5169,14 +5169,14 @@ } }, "node_modules/axios": { - "version": "1.7.9", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz", - "integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==", + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.6.tgz", + "integrity": "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==", "dev": true, "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", "proxy-from-env": "^1.1.0" } }, @@ -9634,9 +9634,9 @@ "license": "ISC" }, "node_modules/follow-redirects": { - "version": "1.15.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.9.tgz", - "integrity": "sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==", + "version": "1.15.11", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", "dev": true, "funding": [ { From d195a51e2e8df475be8056a215d3461b9342e260 Mon Sep 17 00:00:00 2001 From: GCHQDeveloper581 <63102987+GCHQDeveloper581@users.noreply.github.com> Date: Wed, 11 Mar 2026 12:05:50 +0000 Subject: [PATCH 16/20] Update some dependencies, including a number causing npm audit warnings (#2236) Also includes a fix for some minor linting warnings. --- package-lock.json | 430 +++++++++++++++------------ package.json | 22 +- tests/node/tests/lib/BigIntUtils.mjs | 44 +-- 3 files changed, 275 insertions(+), 221 deletions(-) diff --git a/package-lock.json b/package-lock.json index 33c3c9aa..88c8d5e1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -38,7 +38,7 @@ "d3": "7.9.0", "d3-hexbin": "^0.2.2", "diff": "^5.2.2", - "dompurify": "^3.3.1", + "dompurify": "^3.3.3", "es6-promisify": "^7.0.0", "escodegen": "^2.1.0", "esprima": "^4.0.1", @@ -60,7 +60,7 @@ "json5": "^2.2.3", "jsonata": "^2.1.0", "jsonpath-plus": "^10.4.0", - "jsonwebtoken": "9.0.0", + "jsonwebtoken": "9.0.3", "jsqr": "^1.4.0", "jsrsasign": "^11.1.1", "kbpgp": "^2.1.17", @@ -93,7 +93,7 @@ "snackbarjs": "^1.1.0", "sortablejs": "^1.15.7", "split.js": "^1.6.5", - "sql-formatter": "^15.6.5", + "sql-formatter": "^15.6.12", "ssdeep.js": "0.0.3", "stream-browserify": "^3.0.0", "tesseract.js": "^6.0.1", @@ -114,11 +114,11 @@ "@babel/preset-env": "^7.29.0", "@babel/runtime": "^7.28.6", "@codemirror/commands": "^6.10.2", - "@codemirror/language": "^6.12.1", + "@codemirror/language": "^6.12.2", "@codemirror/search": "^6.6.0", "@codemirror/state": "^6.5.4", - "@codemirror/view": "^6.39.15", - "autoprefixer": "^10.4.24", + "@codemirror/view": "^6.39.17", + "autoprefixer": "^10.4.27", "babel-loader": "^10.0.0", "base64-loader": "^1.0.0", "chromedriver": "^130.0.4", @@ -129,7 +129,7 @@ "core-js": "^3.48.0", "cspell": "^8.19.4", "css-loader": "7.1.4", - "eslint": "^9.39.3", + "eslint": "^9.39.4", "eslint-plugin-jsdoc": "^50.8.0", "globals": "^15.15.0", "grunt": "^1.6.1", @@ -145,17 +145,17 @@ "grunt-zip": "^1.0.0", "html-webpack-plugin": "^5.6.6", "imports-loader": "^5.0.0", - "mini-css-extract-plugin": "2.10.0", + "mini-css-extract-plugin": "2.10.1", "modify-source-webpack-plugin": "^4.1.0", "nightwatch": "^3.15.0", - "postcss": "^8.5.6", + "postcss": "^8.5.8", "postcss-css-variables": "^0.19.0", "postcss-import": "^16.1.1", "postcss-loader": "^8.2.1", "prompt": "^1.3.0", - "sitemap": "^8.0.2", + "sitemap": "^8.0.3", "terser": "^5.46.0", - "webpack": "^5.105.2", + "webpack": "^5.105.4", "webpack-bundle-analyzer": "^4.10.2", "webpack-dev-server": "5.0.4", "webpack-node-externals": "^3.0.0", @@ -586,15 +586,15 @@ } }, "node_modules/@babel/helpers": { - "version": "7.26.0", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.26.0.tgz", - "integrity": "sha512-tbhNuIxNcVb21pInl3ZSjksLCvgdZy9KwJ8brv993QtIVKJBBkYXz4q4ZbAv31GdnC+R90np23L5FbEBlthAEw==", + "version": "7.28.6", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.28.6.tgz", + "integrity": "sha512-xOBvwq86HHdB7WUDTfKfT/Vuxh7gElQ+Sfti2Cy6yIWNW05P8iUslOVcZ4/sKbE+/jQaukQAdz/gf3724kYdqw==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@babel/template": "^7.25.9", - "@babel/types": "^7.26.0" + "@babel/template": "^7.28.6", + "@babel/types": "^7.28.6" }, "engines": { "node": ">=6.9.0" @@ -1890,9 +1890,9 @@ } }, "node_modules/@codemirror/view": { - "version": "6.39.16", - "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.39.16.tgz", - "integrity": "sha512-m6S22fFpKtOWhq8HuhzsI1WzUP/hB9THbDj0Tl5KX4gbO6Y91hwBl7Yky33NdvB6IffuRFiBxf1R8kJMyXmA4Q==", + "version": "6.39.17", + "resolved": "https://registry.npmjs.org/@codemirror/view/-/view-6.39.17.tgz", + "integrity": "sha512-Aim4lFqhbijnchl83RLfABWueSGs1oUCSv0mru91QdhpXQeNKprIdRO9LWA4cYkJvuYTKGJN7++9MXx8XW43ag==", "dev": true, "license": "MIT", "dependencies": { @@ -4674,9 +4674,9 @@ } }, "node_modules/ajv-formats/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "dev": true, "license": "MIT", "dependencies": { @@ -5020,9 +5020,9 @@ } }, "node_modules/asn1.js/node_modules/bn.js": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", - "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "license": "MIT" }, "node_modules/assert": { @@ -5447,9 +5447,9 @@ "license": "BSD-3-Clause" }, "node_modules/bn.js": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", - "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==", + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.3.tgz", + "integrity": "sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==", "license": "MIT" }, "node_modules/body": { @@ -5465,24 +5465,24 @@ } }, "node_modules/body-parser": { - "version": "1.20.3", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", - "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", + "version": "1.20.4", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", + "integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", "dev": true, "license": "MIT", "dependencies": { - "bytes": "3.1.2", + "bytes": "~3.1.2", "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", - "destroy": "1.2.0", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "on-finished": "2.4.1", - "qs": "6.13.0", - "raw-body": "2.5.2", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.14.0", + "raw-body": "~2.5.3", "type-is": "~1.6.18", - "unpipe": "1.0.0" + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8", @@ -5510,20 +5510,24 @@ } }, "node_modules/body-parser/node_modules/http-errors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", - "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "dev": true, "license": "MIT", "dependencies": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" + "depd": "~2.0.0", + "inherits": "~2.0.4", + "setprototypeof": "~1.2.0", + "statuses": "~2.0.2", + "toidentifier": "~1.0.1" }, "engines": { "node": ">= 0.8" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/body-parser/node_modules/iconv-lite": { @@ -5560,13 +5564,13 @@ } }, "node_modules/body-parser/node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", + "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.6" + "side-channel": "^1.1.0" }, "engines": { "node": ">=0.6" @@ -5576,16 +5580,16 @@ } }, "node_modules/body-parser/node_modules/raw-body": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", - "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", "dev": true, "license": "MIT", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" }, "engines": { "node": ">= 0.8" @@ -5599,9 +5603,9 @@ "license": "ISC" }, "node_modules/body-parser/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "dev": true, "license": "MIT", "engines": { @@ -5734,9 +5738,9 @@ } }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz", + "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==", "dev": true, "license": "MIT", "dependencies": { @@ -5822,24 +5826,23 @@ } }, "node_modules/browserify-sign": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.3.tgz", - "integrity": "sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==", + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.5.tgz", + "integrity": "sha512-C2AUdAJg6rlM2W5QMp2Q4KGQMVBwR1lIimTsUnutJ8bMpW5B52pGpR2gEnNBNwijumDo5FojQ0L9JrXA8m4YEw==", "license": "ISC", "dependencies": { - "bn.js": "^5.2.1", - "browserify-rsa": "^4.1.0", + "bn.js": "^5.2.2", + "browserify-rsa": "^4.1.1", "create-hash": "^1.2.0", "create-hmac": "^1.1.7", - "elliptic": "^6.5.5", - "hash-base": "~3.0", + "elliptic": "^6.6.1", "inherits": "^2.0.4", - "parse-asn1": "^5.1.7", + "parse-asn1": "^5.1.9", "readable-stream": "^2.3.8", "safe-buffer": "^5.2.1" }, "engines": { - "node": ">= 0.12" + "node": ">= 0.10" } }, "node_modules/browserify-zlib": { @@ -6595,9 +6598,9 @@ } }, "node_modules/compression": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.5.tgz", - "integrity": "sha512-bQJ0YRck5ak3LgtnpKkiabX5pNF7tMUh1BSy2ZBOTh0Dim0BUu6aPPwByIns6/A5Prh8PufSPerMDUklpzes2Q==", + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-9mAqGPHLakhCLeNyxPkK4xVo746zQ/czLH1Ky+vkitMnWfWZps8r0qXuwhwizagCRttsL4lfG4pIOvaWLpAP0w==", "dev": true, "license": "MIT", "dependencies": { @@ -6605,7 +6608,7 @@ "compressible": "~2.0.18", "debug": "2.6.9", "negotiator": "~0.6.4", - "on-headers": "~1.0.2", + "on-headers": "~1.1.0", "safe-buffer": "5.2.1", "vary": "~1.1.2" }, @@ -6932,9 +6935,9 @@ } }, "node_modules/create-ecdh/node_modules/bn.js": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", - "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "license": "MIT" }, "node_modules/create-hash": { @@ -8184,9 +8187,9 @@ } }, "node_modules/diffie-hellman/node_modules/bn.js": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", - "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "license": "MIT" }, "node_modules/discontinuous-range": { @@ -8273,13 +8276,10 @@ } }, "node_modules/dompurify": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.2.tgz", - "integrity": "sha512-6obghkliLdmKa56xdbLOpUZ43pAR6xFy1uOrxBaIDjT+yaRuuybLjGS9eVBoSR/UPU5fq3OXClEHLJNGvbxKpQ==", + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.3.3.tgz", + "integrity": "sha512-Oj6pzI2+RqBfFG+qOaOLbFXLQ90ARpcGG6UePL82bJLtdsa6CYJD7nmiU8MW9nQNOtCHV3lZ/Bzq1X0QYbBZCA==", "license": "(MPL-2.0 OR Apache-2.0)", - "engines": { - "node": ">=20" - }, "optionalDependencies": { "@types/trusted-types": "^2.0.7" } @@ -8419,9 +8419,9 @@ } }, "node_modules/elliptic/node_modules/bn.js": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", - "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "license": "MIT" }, "node_modules/emoji-regex": { @@ -9142,40 +9142,40 @@ } }, "node_modules/express": { - "version": "4.21.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.21.2.tgz", - "integrity": "sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==", + "version": "4.22.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", + "integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", "dev": true, "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.3", - "content-disposition": "0.5.4", + "body-parser": "~1.20.3", + "content-disposition": "~0.5.4", "content-type": "~1.0.4", - "cookie": "0.7.1", - "cookie-signature": "1.0.6", + "cookie": "~0.7.1", + "cookie-signature": "~1.0.6", "debug": "2.6.9", "depd": "2.0.0", "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.3.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", + "finalhandler": "~1.3.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.0", "merge-descriptors": "1.0.3", "methods": "~1.1.2", - "on-finished": "2.4.1", + "on-finished": "~2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.12", + "path-to-regexp": "~0.1.12", "proxy-addr": "~2.0.7", - "qs": "6.13.0", + "qs": "~6.14.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.19.0", - "serve-static": "1.16.2", + "send": "~0.19.0", + "serve-static": "~1.16.2", "setprototypeof": "1.2.0", - "statuses": "2.0.1", + "statuses": "~2.0.1", "type-is": "~1.6.18", "utils-merge": "1.0.1", "vary": "~1.1.2" @@ -9265,13 +9265,13 @@ } }, "node_modules/express/node_modules/qs": { - "version": "6.13.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", - "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", + "version": "6.14.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.2.tgz", + "integrity": "sha512-V/yCWTTF7VJ9hIh18Ugr2zhJMP01MY7c5kh4J870L7imm6/DIzBsNLTXzMwUA3yZ5b/KBqLx8Kp3uRvd7xSe3Q==", "dev": true, "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.6" + "side-channel": "^1.1.0" }, "engines": { "node": ">=0.6" @@ -9469,9 +9469,9 @@ } }, "node_modules/filelist/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "license": "MIT", "dependencies": { @@ -9479,9 +9479,9 @@ } }, "node_modules/filelist/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", "dev": true, "license": "ISC", "dependencies": { @@ -10571,9 +10571,9 @@ } }, "node_modules/grunt/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "3.14.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.2.tgz", + "integrity": "sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==", "dev": true, "license": "MIT", "dependencies": { @@ -11037,9 +11037,9 @@ } }, "node_modules/http-proxy-middleware": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.7.tgz", - "integrity": "sha512-fgVY8AV7qU7z/MmXJ/rxwbrtQH4jBQ9m7kp3llF0liB7glmFeVZFBepQb32T3y8n8k2+AEYuMPCpinYW+/CuRA==", + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.9.tgz", + "integrity": "sha512-c1IyJYLYppU574+YI7R4QyX2ystMtVXZwIdzazUIPIJsHuWNd+mho2j+bKoHftndicGj9yh+xjd+l0yj7VeT1Q==", "dev": true, "license": "MIT", "dependencies": { @@ -12343,15 +12343,21 @@ } }, "node_modules/jsonwebtoken": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", - "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", + "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", "license": "MIT", "dependencies": { - "jws": "^3.2.2", - "lodash": "^4.17.21", + "jws": "^4.0.1", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", "ms": "^2.1.1", - "semver": "^7.3.8" + "semver": "^7.5.4" }, "engines": { "node": ">=12", @@ -12399,9 +12405,9 @@ } }, "node_modules/jwa": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.2.tgz", - "integrity": "sha512-eeH5JO+21J78qMvTIDdBXidBd6nG2kZjg5Ohz/1fpa28Z4CcsWUzJ1ZZyFq/3z3N17aZy+ZuBoHljASbL1WfOw==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", "license": "MIT", "dependencies": { "buffer-equal-constant-time": "^1.0.1", @@ -12410,12 +12416,12 @@ } }, "node_modules/jws": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.3.tgz", - "integrity": "sha512-byiJ0FLRdLdSVSReO/U4E7RoEyOCKnEnEPMjq3HxWtvzLsV08/i5RQKsFVNkCldrCaPr2vDNAOMsfs8T/Hze7g==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", "license": "MIT", "dependencies": { - "jwa": "^1.4.2", + "jwa": "^2.0.1", "safe-buffer": "^5.0.1" } }, @@ -12693,6 +12699,18 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "license": "MIT" + }, "node_modules/lodash.isfinite": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/lodash.isfinite/-/lodash.isfinite-3.3.2.tgz", @@ -12700,11 +12718,28 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "license": "MIT" + }, "node_modules/lodash.isplainobject": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", - "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", "license": "MIT" }, "node_modules/lodash.merge": { @@ -12714,6 +12749,12 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "license": "MIT" + }, "node_modules/lodash.union": { "version": "4.6.0", "resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz", @@ -13010,9 +13051,9 @@ } }, "node_modules/miller-rabin/node_modules/bn.js": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", - "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "license": "MIT" }, "node_modules/mime": { @@ -13062,9 +13103,9 @@ } }, "node_modules/mini-css-extract-plugin": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.10.0.tgz", - "integrity": "sha512-540P2c5dYnJlyJxTaSloliZexv8rji6rY8FhQN+WF/82iHQfA23j/xtJx97L+mXOML27EqksSek/g4eK7jaL3g==", + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.10.1.tgz", + "integrity": "sha512-k7G3Y5QOegl380tXmZ68foBRRjE9Ljavx835ObdvmZjQ639izvZD8CS7BkWw1qKPPzHsGL/JDhl0uyU1zc2rJw==", "dev": true, "license": "MIT", "dependencies": { @@ -13285,9 +13326,9 @@ } }, "node_modules/morgan": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.0.tgz", - "integrity": "sha512-AbegBVI4sh6El+1gNwvD5YIck7nSA36weD7xvIxG4in80j/UoK8AEGaWnnz8v1GxonMCltmlNs5ZKbGvl9b1XQ==", + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.10.1.tgz", + "integrity": "sha512-223dMRJtI/l25dJKWpgij2cMtywuG/WiUKXdvwfbhGKBhy1puASqXwFzmWZ7+K73vUPoR7SS2Qz2cI/g9MKw0A==", "dev": true, "license": "MIT", "dependencies": { @@ -13295,7 +13336,7 @@ "debug": "2.6.9", "depd": "~2.0.0", "on-finished": "~2.3.0", - "on-headers": "~1.0.2" + "on-headers": "~1.1.0" }, "engines": { "node": ">= 0.8.0" @@ -13582,6 +13623,19 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/nightwatch/node_modules/glob/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/nightwatch/node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -13963,9 +14017,9 @@ } }, "node_modules/on-headers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", - "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.1.0.tgz", + "integrity": "sha512-737ZY3yNnXy37FHkQxPzt4UZ2UWPWiCZWLvFZ4fu5cueciegX0zGPnrlY6bwRg4FdQOe9YU8MkmJwGhoMybl8A==", "dev": true, "license": "MIT", "engines": { @@ -14327,16 +14381,15 @@ } }, "node_modules/parse-asn1": { - "version": "5.1.7", - "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.7.tgz", - "integrity": "sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==", + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.9.tgz", + "integrity": "sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==", "license": "ISC", "dependencies": { "asn1.js": "^4.10.1", "browserify-aes": "^1.2.0", "evp_bytestokey": "^1.0.3", - "hash-base": "~3.0", - "pbkdf2": "^3.1.2", + "pbkdf2": "^3.1.5", "safe-buffer": "^5.2.1" }, "engines": { @@ -15104,9 +15157,9 @@ } }, "node_modules/public-encrypt/node_modules/bn.js": { - "version": "4.12.1", - "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz", - "integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==", + "version": "4.12.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.3.tgz", + "integrity": "sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==", "license": "MIT" }, "node_modules/pump": { @@ -15177,9 +15230,9 @@ "license": "MIT" }, "node_modules/qs": { - "version": "6.14.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz", - "integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz", + "integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==", "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.1.0" @@ -15376,9 +15429,9 @@ } }, "node_modules/readdir-glob/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "license": "MIT", "dependencies": { @@ -15386,9 +15439,9 @@ } }, "node_modules/readdir-glob/node_modules/minimatch": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", - "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", "dev": true, "license": "ISC", "dependencies": { @@ -15852,9 +15905,9 @@ } }, "node_modules/schema-utils/node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", "dev": true, "license": "MIT", "dependencies": { @@ -16307,12 +16360,12 @@ "license": "ISC" }, "node_modules/simple-xml-to-json": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/simple-xml-to-json/-/simple-xml-to-json-1.2.3.tgz", - "integrity": "sha512-kWJDCr9EWtZ+/EYYM5MareWj2cRnZGF93YDNpH4jQiHB+hBIZnfPFSQiVMzZOdk+zXWqTZ/9fTeQNu2DqeiudA==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/simple-xml-to-json/-/simple-xml-to-json-1.2.2.tgz", + "integrity": "sha512-bmJJf5YiYL60eOQk3gaVxbM6vgYuwrFydCEAA2x3jccHUTsAffiPyblS/yQGr8GDUQVxSDm3WwLNL5HmRqDUcg==", "license": "MIT", "engines": { - "node": ">=20.12.2" + "node": ">=14.20.0" } }, "node_modules/sirv": { @@ -17174,9 +17227,9 @@ } }, "node_modules/tmp": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", - "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", + "integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", "dev": true, "license": "MIT", "engines": { @@ -18022,9 +18075,9 @@ } }, "node_modules/webpack-dev-server/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz", + "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==", "dev": true, "license": "MIT", "dependencies": { @@ -18045,9 +18098,10 @@ } }, "node_modules/webpack-dev-server/node_modules/glob": { - "version": "10.4.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.4.5.tgz", - "integrity": "sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==", + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.5.0.tgz", + "integrity": "sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", "dev": true, "license": "ISC", "dependencies": { @@ -18082,13 +18136,13 @@ } }, "node_modules/webpack-dev-server/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" diff --git a/package.json b/package.json index d3519e0f..bcbcd48b 100644 --- a/package.json +++ b/package.json @@ -45,11 +45,11 @@ "@babel/preset-env": "^7.29.0", "@babel/runtime": "^7.28.6", "@codemirror/commands": "^6.10.2", - "@codemirror/language": "^6.12.1", + "@codemirror/language": "^6.12.2", "@codemirror/search": "^6.6.0", "@codemirror/state": "^6.5.4", - "@codemirror/view": "^6.39.15", - "autoprefixer": "^10.4.24", + "@codemirror/view": "^6.39.17", + "autoprefixer": "^10.4.27", "babel-loader": "^10.0.0", "base64-loader": "^1.0.0", "chromedriver": "^130.0.4", @@ -60,7 +60,7 @@ "core-js": "^3.48.0", "cspell": "^8.19.4", "css-loader": "7.1.4", - "eslint": "^9.39.3", + "eslint": "^9.39.4", "eslint-plugin-jsdoc": "^50.8.0", "globals": "^15.15.0", "grunt": "^1.6.1", @@ -76,17 +76,17 @@ "grunt-zip": "^1.0.0", "html-webpack-plugin": "^5.6.6", "imports-loader": "^5.0.0", - "mini-css-extract-plugin": "2.10.0", + "mini-css-extract-plugin": "2.10.1", "modify-source-webpack-plugin": "^4.1.0", "nightwatch": "^3.15.0", - "postcss": "^8.5.6", + "postcss": "^8.5.8", "postcss-css-variables": "^0.19.0", "postcss-import": "^16.1.1", "postcss-loader": "^8.2.1", "prompt": "^1.3.0", - "sitemap": "^8.0.2", + "sitemap": "^8.0.3", "terser": "^5.46.0", - "webpack": "^5.105.2", + "webpack": "^5.105.4", "webpack-bundle-analyzer": "^4.10.2", "webpack-dev-server": "5.0.4", "webpack-node-externals": "^3.0.0", @@ -121,7 +121,7 @@ "d3": "7.9.0", "d3-hexbin": "^0.2.2", "diff": "^5.2.2", - "dompurify": "^3.3.1", + "dompurify": "^3.3.3", "es6-promisify": "^7.0.0", "escodegen": "^2.1.0", "esprima": "^4.0.1", @@ -143,7 +143,7 @@ "json5": "^2.2.3", "jsonata": "^2.1.0", "jsonpath-plus": "^10.4.0", - "jsonwebtoken": "9.0.0", + "jsonwebtoken": "9.0.3", "jsqr": "^1.4.0", "jsrsasign": "^11.1.1", "kbpgp": "^2.1.17", @@ -176,7 +176,7 @@ "snackbarjs": "^1.1.0", "sortablejs": "^1.15.7", "split.js": "^1.6.5", - "sql-formatter": "^15.6.5", + "sql-formatter": "^15.6.12", "ssdeep.js": "0.0.3", "stream-browserify": "^3.0.0", "tesseract.js": "^6.0.1", diff --git a/tests/node/tests/lib/BigIntUtils.mjs b/tests/node/tests/lib/BigIntUtils.mjs index d75a4893..f745f91b 100644 --- a/tests/node/tests/lib/BigIntUtils.mjs +++ b/tests/node/tests/lib/BigIntUtils.mjs @@ -9,46 +9,46 @@ TestRegister.addApiTests([ const value = parseBigInt("1", "test value"); assert.deepStrictEqual(value, BigInt("1")); }), - + it("BigIntUtils: parseBigInt - large decimal", () => { const value = parseBigInt("123456789012345678901234567890", "test value"); assert.deepStrictEqual(value, BigInt("123456789012345678901234567890")); }), - + it("BigIntUtils: parseBigInt - hexadecimal lowercase", () => { const value = parseBigInt("0xff", "test value"); assert.deepStrictEqual(value, BigInt("255")); }), - + it("BigIntUtils: parseBigInt - hexadecimal uppercase", () => { const value = parseBigInt("0xFF", "test value"); assert.deepStrictEqual(value, BigInt("255")); }), - + it("BigIntUtils: parseBigInt - large hexadecimal", () => { const value = parseBigInt("0x123456789ABCDEF", "test value"); assert.deepStrictEqual(value, BigInt("0x123456789ABCDEF")); }), - + it("BigIntUtils: parseBigInt - whitespace trimming", () => { const value = parseBigInt(" 42 ", "test value"); assert.deepStrictEqual(value, BigInt("42")); }), - + it("BigIntUtils: parseBigInt - invalid input (text)", () => { assert.throws(() => parseBigInt("test", "test value"), { name: "Error", message: "test value must be decimal or hex (0x...)" }); }), - + it("BigIntUtils: parseBigInt - invalid input (hex without prefix)", () => { assert.throws(() => parseBigInt("FF", "test value"), { name: "Error", message: "test value must be decimal or hex (0x...)" }); }), - + it("BigIntUtils: parseBigInt - invalid input (mixed)", () => { assert.throws(() => parseBigInt("12abc", "test value"), { name: "Error", @@ -65,40 +65,40 @@ TestRegister.addApiTests([ const bezout2 = BigInt("1"); assert.deepStrictEqual(egcd(a, b), [gcd, bezout1, bezout2]); }), - + it("BigIntUtils: egcd - coprime numbers", () => { const [g, x, y] = egcd(BigInt("3"), BigInt("11")); assert.strictEqual(g, BigInt("1")); - // Verify Bézout identity: a*x + b*y = gcd + // Verify Bézout identity: a*x + b*y = gcd assert.strictEqual(BigInt("3") * x + BigInt("11") * y, g); }), - + it("BigIntUtils: egcd - non-coprime numbers", () => { const [g, x, y] = egcd(BigInt("240"), BigInt("46")); assert.strictEqual(g, BigInt("2")); - // Verify Bézout identity + // Verify Bézout identity assert.strictEqual(BigInt("240") * x + BigInt("46") * y, g); }), - + it("BigIntUtils: egcd - with zero", () => { const [g, x, y] = egcd(BigInt("17"), BigInt("0")); assert.strictEqual(g, BigInt("17")); assert.strictEqual(x, BigInt("1")); assert.strictEqual(y, BigInt("0")); }), - + it("BigIntUtils: egcd - identical numbers", () => { const [g, x, y] = egcd(BigInt("42"), BigInt("42")); assert.strictEqual(g, BigInt("42")); - // Verify Bézout identity + // Verify Bézout identity assert.strictEqual(BigInt("42") * x + BigInt("42") * y, g); }), - + it("BigIntUtils: egcd - large numbers", () => { const a = BigInt("123456789012345678901234567890"); const b = BigInt("987654321098765432109876543210"); const [g, x, y] = egcd(a, b); - // Verify Bézout identity + // Verify Bézout identity assert.strictEqual(a * x + b * y, g); }), @@ -108,7 +108,7 @@ TestRegister.addApiTests([ const result = modPow(BigInt("2"), BigInt("10"), BigInt("1000")); assert.strictEqual(result, BigInt("24")); }), - + it("BigIntUtils: modPow - RSA-like example", () => { // Common RSA public exponent const base = BigInt("123456789"); @@ -119,26 +119,26 @@ TestRegister.addApiTests([ assert(result < mod); assert(result >= BigInt("0")); }), - + it("BigIntUtils: modPow - exponent zero", () => { // Any number^0 = 1 const result = modPow(BigInt("999"), BigInt("0"), BigInt("100")); assert.strictEqual(result, BigInt("1")); }), - + it("BigIntUtils: modPow - base zero", () => { // 0^n = 0 const result = modPow(BigInt("0"), BigInt("5"), BigInt("100")); assert.strictEqual(result, BigInt("0")); }), - + it("BigIntUtils: modPow - large exponent", () => { // Test with very large exponent (efficient algorithm should handle this) const result = modPow(BigInt("3"), BigInt("1000000"), BigInt("1000000007")); assert(result >= BigInt("0")); assert(result < BigInt("1000000007")); }), - + it("BigIntUtils: modPow - modular inverse verification", () => { // If a*x . 1 (mod m), then modPow(a, 1, m) * x . 1 (mod m) const a = BigInt("3"); From 4deaa0de20d87bca166d1ed24075d308aa40bbbb Mon Sep 17 00:00:00 2001 From: am-periphery <138065765+am-periphery@users.noreply.github.com> Date: Sun, 15 Mar 2026 09:35:11 +0000 Subject: [PATCH 17/20] Fix broken Docker link in README (#2250) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 89f0371d..cc18a83f 100755 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Cryptographic operations in CyberChef should not be relied upon to provide secur **Prerequisites** -- [Docker](hhttps://www.docker.com/products/docker-desktop/) +- [Docker](https://www.docker.com/products/docker-desktop/) - Docker Desktop must be open and running on your machine From eef8d55d86742a3fd46ddfc5540cebfcb2ec012e Mon Sep 17 00:00:00 2001 From: John Brick Date: Thu, 19 Mar 2026 13:10:35 +0300 Subject: [PATCH 18/20] fix(A1Z26): return empty string instead of empty array for empty input (#2257) --- src/core/operations/A1Z26CipherDecode.mjs | 2 +- tests/operations/index.mjs | 1 + tests/operations/tests/A1Z26CipherDecode.mjs | 33 ++++++++++++++++++++ 3 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 tests/operations/tests/A1Z26CipherDecode.mjs diff --git a/src/core/operations/A1Z26CipherDecode.mjs b/src/core/operations/A1Z26CipherDecode.mjs index 0b097c2b..cc9aafbf 100644 --- a/src/core/operations/A1Z26CipherDecode.mjs +++ b/src/core/operations/A1Z26CipherDecode.mjs @@ -76,7 +76,7 @@ class A1Z26CipherDecode extends Operation { const delim = Utils.charRep(args[0] || "Space"); if (input.length === 0) { - return []; + return ""; } const bites = input.split(delim); diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs index fb03a5f7..3585e270 100644 --- a/tests/operations/index.mjs +++ b/tests/operations/index.mjs @@ -14,6 +14,7 @@ import { setLongTestFailure, logTestReport } from "../lib/utils.mjs"; import TestRegister from "../lib/TestRegister.mjs"; +import "./tests/A1Z26CipherDecode.mjs"; import "./tests/AESKeyWrap.mjs"; import "./tests/AlternatingCaps.mjs"; import "./tests/AvroToJSON.mjs"; diff --git a/tests/operations/tests/A1Z26CipherDecode.mjs b/tests/operations/tests/A1Z26CipherDecode.mjs new file mode 100644 index 00000000..97020e0b --- /dev/null +++ b/tests/operations/tests/A1Z26CipherDecode.mjs @@ -0,0 +1,33 @@ +/** + * A1Z26 Cipher Decode tests + * + * @author brick-pixel + * @copyright Crown Copyright 2026 + * @license Apache-2.0 + */ +import TestRegister from "../../lib/TestRegister.mjs"; + +TestRegister.addTests([ + { + "name": "A1Z26 Cipher Decode: basic decode", + "input": "8 5 12 12 15", + "expectedOutput": "hello", + "recipeConfig": [ + { + "op": "A1Z26 Cipher Decode", + "args": ["Space"] + } + ] + }, + { + "name": "A1Z26 Cipher Decode: empty input returns empty string", + "input": "", + "expectedOutput": "", + "recipeConfig": [ + { + "op": "A1Z26 Cipher Decode", + "args": ["Space"] + } + ] + } +]); From 19bc8169ce706d09ea46b7462c0f430d56bd7b7b Mon Sep 17 00:00:00 2001 From: GCHQDeveloper581 <63102987+GCHQDeveloper581@users.noreply.github.com> Date: Thu, 19 Mar 2026 10:13:03 +0000 Subject: [PATCH 19/20] Configure dependabot updates (#2259) --- .github/dependabot.yml | 72 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 .github/dependabot.yml diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..cc66c319 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,72 @@ +# See the documentation for all configuration options: +# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file + +version: 2 +updates: + # + # Check for minor/patch versions only on a weekly basis - we are likely to be able to + # merge these routinely. Major versions we'll check for and update manually. + # + - package-ecosystem: 'npm' + directory: '/' + versioning-strategy: increase + schedule: + interval: 'weekly' + day: 'friday' + time: '03:00' + timezone: Europe/London + commit-message: + prefix: 'chore (deps): ' + ignore: + # we'll do any major version updates manually + - dependency-name: '*' + update-types: ['version-update:semver-major'] + # packages we can't currently update + # see issue #2214 for rationale for each of these + - dependency-name: '@xmldom/xmldom' + versions: [ '>=0.9.0' ] + - dependency-name: 'bcryptjs' + versions: [ '>=3.0.0' ] + - dependency-name: 'bootstrap' + versions: [ '>=5.0.0' ] + - dependency-name: 'bson' + versions: [ '>=5.0.0' ] + - dependency-name: 'cbor' + versions: [ '>=10.0.0' ] + - dependency-name: 'cspell' + versions: [ '>=9.0.0' ] + - dependency-name: 'eslint' + versions: [ '>=10.0.0' ] + - dependency-name: 'eslint-plugin-jsdoc' + versions: [ '>=51.0.0' ] + - dependency-name: 'fernet' + versions: [ '>=0.4.0' ] + - dependency-name: 'geodesy' + versions: [ '>=2.0.0' ] + - dependency-name: 'otpauth' + versions: [ '>=9.4.0' ] + - dependency-name: 'webpack-dev-server' + versions: [ '>=5.1.0' ] + groups: + # + # Grouping so we don't get a seperate PR for every patch version. + # + patch-updates: + applies-to: version-updates + patterns: + - '*' + update-types: + - 'patch' + + # Can't enable this until we are using Node 24 as the latest actions all require this version + # - package-ecosystem: "github-actions" + # # Workflow files stored in the default location of `.github/workflows`; no need to + # # specify `/.github/workflows` for `directory` + # directory: '/' + # schedule: + # interval: 'weekly' + # day: 'friday' + # time: '03:00' + # timezone: Europe/London + # commit-message: + # prefix: 'chore (deps): ' From d9dacf6b8fe064ff56037f1a52b0ada509d5dda4 Mon Sep 17 00:00:00 2001 From: GCHQDeveloper581 <63102987+GCHQDeveloper581@users.noreply.github.com> Date: Thu, 19 Mar 2026 11:47:31 +0000 Subject: [PATCH 20/20] Fix Jq issue (#2210) * Revert "fix: jq-web -> jq-wasm, includes jq version 1.8.1 (gchq#2223)" This reverts commit 0c6454e. (but leave new tests intact) * Return jq-web to 0.5.1 --- package-lock.json | 12 ++++++------ package.json | 2 +- src/core/operations/Jq.mjs | 21 +++++++++++---------- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/package-lock.json b/package-lock.json index 88c8d5e1..b4b293e2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -53,7 +53,7 @@ "highlight.js": "^11.11.1", "ieee754": "^1.2.1", "jimp": "^1.6.0", - "jq-wasm": "^1.1.0-jq-1.8.1", + "jq-web": "^0.5.1", "jquery": "3.7.1", "js-sha3": "^0.9.3", "jsesc": "^3.1.0", @@ -12158,11 +12158,11 @@ "integrity": "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==", "license": "BSD-3-Clause" }, - "node_modules/jq-wasm": { - "version": "1.1.0-jq-1.8.1", - "resolved": "https://registry.npmjs.org/jq-wasm/-/jq-wasm-1.1.0-jq-1.8.1.tgz", - "integrity": "sha512-lWfu34lpDFIygOYcL5TzxhZIApDR9iR5XywcVoyUAZ6jlQrj8HKHOKeCcHgUm2dE9RVdbP3eqNAKGLuj+k4seQ==", - "license": "MIT" + "node_modules/jq-web": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/jq-web/-/jq-web-0.5.1.tgz", + "integrity": "sha512-3Fa3E6g3U1O1j46ljy0EM10yRr4txzILga8J7bqOG8F89gZ6Lilz82WG9z6TItWpYEO0YGa4W8yFGj+NMM1xqQ==", + "license": "ISC" }, "node_modules/jquery": { "version": "3.7.1", diff --git a/package.json b/package.json index bcbcd48b..2948556e 100644 --- a/package.json +++ b/package.json @@ -136,7 +136,7 @@ "highlight.js": "^11.11.1", "ieee754": "^1.2.1", "jimp": "^1.6.0", - "jq-wasm": "^1.1.0-jq-1.8.1", + "jq-web": "^0.5.1", "jquery": "3.7.1", "js-sha3": "^0.9.3", "jsesc": "^3.1.0", diff --git a/src/core/operations/Jq.mjs b/src/core/operations/Jq.mjs index 4584d1a9..c1e02b34 100644 --- a/src/core/operations/Jq.mjs +++ b/src/core/operations/Jq.mjs @@ -6,7 +6,7 @@ import Operation from "../Operation.mjs"; import OperationError from "../errors/OperationError.mjs"; -import * as jq from "jq-wasm"; +import jq from "jq-web"; /** * jq operation @@ -40,15 +40,16 @@ class Jq extends Operation { * @returns {string} */ run(input, args) { - return (async () => { - const [query] = args; - try { - const result = await jq.json(input, query); - return JSON.stringify(result); - } catch (err) { - throw new OperationError(`Invalid jq expression: ${err.message}`); - } - })(); + const [query] = args; + let result; + + try { + result = jq.json(input, query); + } catch (err) { + throw new OperationError(`Invalid jq expression: ${err.message}`); + } + + return JSON.stringify(result); } }