Merge branch 'master' into feature/aes-iv-from-input

This commit is contained in:
andreas 2026-06-05 14:56:32 +02:00 committed by GitHub
commit 796268f369
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
16 changed files with 534 additions and 98 deletions

View File

@ -41,6 +41,8 @@ updates:
versions: [ '>=2.0.0' ] versions: [ '>=2.0.0' ]
- dependency-name: 'jimp' - dependency-name: 'jimp'
versions: [ '1.6.1' ] versions: [ '1.6.1' ]
- dependency-name: 'jq-web'
versions: [ '>=0.6.0' ]
groups: groups:
# #
# Grouping so patch version updates are batched together in a single PR # Grouping so patch version updates are batched together in a single PR

View File

@ -27,7 +27,7 @@ RUN npm run build
######################################### #########################################
# Package static build files into nginx # # Package static build files into nginx #
######################################### #########################################
FROM nginxinc/nginx-unprivileged:stable-alpine@sha256:df0e9edf92b8436ff797fe5a2cbfc66be1df775c113d322ccadf5c7f3100eda8 AS cyberchef FROM nginxinc/nginx-unprivileged:stable-alpine@sha256:0a1e718ff1e1a22fc519d0c2e5b6872681f01e37c8a2817ec43ce6e716103929 AS cyberchef
LABEL maintainer="GCHQ <oss@gchq.gov.uk>" LABEL maintainer="GCHQ <oss@gchq.gov.uk>"

155
package-lock.json generated
View File

@ -39,7 +39,7 @@
"d3": "7.9.0", "d3": "7.9.0",
"d3-hexbin": "^0.2.2", "d3-hexbin": "^0.2.2",
"diff": "^5.2.2", "diff": "^5.2.2",
"dompurify": "^3.4.6", "dompurify": "^3.4.7",
"es6-promisify": "^7.0.0", "es6-promisify": "^7.0.0",
"escodegen": "^2.1.0", "escodegen": "^2.1.0",
"esprima": "^4.0.1", "esprima": "^4.0.1",
@ -58,7 +58,7 @@
"js-sha3": "^0.9.3", "js-sha3": "^0.9.3",
"jsesc": "^3.1.0", "jsesc": "^3.1.0",
"json5": "^2.2.3", "json5": "^2.2.3",
"jsonata": "^2.1.0", "jsonata": "^2.2.1",
"jsonpath-plus": "^10.4.0", "jsonpath-plus": "^10.4.0",
"jsonwebtoken": "9.0.3", "jsonwebtoken": "9.0.3",
"jsqr": "^1.4.0", "jsqr": "^1.4.0",
@ -71,7 +71,7 @@
"loglevel-message-prefix": "^3.0.0", "loglevel-message-prefix": "^3.0.0",
"lz-string": "^1.5.0", "lz-string": "^1.5.0",
"lz4js": "^0.2.0", "lz4js": "^0.2.0",
"markdown-it": "^14.1.1", "markdown-it": "^14.2.0",
"moment": "^2.30.1", "moment": "^2.30.1",
"moment-timezone": "^0.6.2", "moment-timezone": "^0.6.2",
"ngeohash": "^0.6.3", "ngeohash": "^0.6.3",
@ -85,7 +85,7 @@
"path": "^0.12.7", "path": "^0.12.7",
"popper.js": "^1.16.1", "popper.js": "^1.16.1",
"process": "^0.11.10", "process": "^0.11.10",
"protobufjs": "^7.6.1", "protobufjs": "^7.6.2",
"punycode.js": "^2.3.1", "punycode.js": "^2.3.1",
"qr-image": "^3.2.0", "qr-image": "^3.2.0",
"reflect-metadata": "^0.2.2", "reflect-metadata": "^0.2.2",
@ -109,7 +109,7 @@
"zlibjs": "^0.3.1" "zlibjs": "^0.3.1"
}, },
"devDependencies": { "devDependencies": {
"@babel/eslint-parser": "^7.28.6", "@babel/eslint-parser": "^7.29.7",
"@babel/plugin-syntax-import-assertions": "^7.28.6", "@babel/plugin-syntax-import-assertions": "^7.28.6",
"@babel/plugin-transform-runtime": "^7.29.7", "@babel/plugin-transform-runtime": "^7.29.7",
"@babel/preset-env": "^7.29.7", "@babel/preset-env": "^7.29.7",
@ -149,7 +149,7 @@
"imports-loader": "^5.0.0", "imports-loader": "^5.0.0",
"mini-css-extract-plugin": "2.10.2", "mini-css-extract-plugin": "2.10.2",
"modify-source-webpack-plugin": "^4.1.0", "modify-source-webpack-plugin": "^4.1.0",
"nightwatch": "^3.15.0", "nightwatch": "^3.16.0",
"postcss": "^8.5.15", "postcss": "^8.5.15",
"postcss-css-variables": "^0.19.0", "postcss-css-variables": "^0.19.0",
"postcss-import": "^16.1.1", "postcss-import": "^16.1.1",
@ -279,9 +279,9 @@
} }
}, },
"node_modules/@babel/eslint-parser": { "node_modules/@babel/eslint-parser": {
"version": "7.28.6", "version": "7.29.7",
"resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.28.6.tgz", "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.29.7.tgz",
"integrity": "sha512-QGmsKi2PBO/MHSQk+AAgA9R6OHQr+VqnniFE0eMWZcVcfBZoA2dKn2hUsl3Csg/Plt9opRUWdY7//VXsrIlEiA==", "integrity": "sha512-zxt+UJTOMKvUt3yOg+D58MLuz334pHp93qifMFcjIIO+9hN6t+ufw2gi7vDPMpxvfnHRR+3VVXvIjineCcgyXw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -5972,9 +5972,9 @@
} }
}, },
"node_modules/body-parser": { "node_modules/body-parser": {
"version": "1.20.4", "version": "1.20.5",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.4.tgz", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.5.tgz",
"integrity": "sha512-ZTgYYLMOXY9qKU/57FAo8F+HA2dGX7bqGc71txDRC1rS4frdFI5R7NhluHxH6M0YItAP0sHB4uqAOcYKxO6uGA==", "integrity": "sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -5986,7 +5986,7 @@
"http-errors": "~2.0.1", "http-errors": "~2.0.1",
"iconv-lite": "~0.4.24", "iconv-lite": "~0.4.24",
"on-finished": "~2.4.1", "on-finished": "~2.4.1",
"qs": "~6.14.0", "qs": "~6.15.1",
"raw-body": "~2.5.3", "raw-body": "~2.5.3",
"type-is": "~1.6.18", "type-is": "~1.6.18",
"unpipe": "~1.0.0" "unpipe": "~1.0.0"
@ -6070,22 +6070,6 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"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==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
"side-channel": "^1.1.0"
},
"engines": {
"node": ">=0.6"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/body-parser/node_modules/raw-body": { "node_modules/body-parser/node_modules/raw-body": {
"version": "2.5.3", "version": "2.5.3",
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz",
@ -8636,9 +8620,9 @@
} }
}, },
"node_modules/dompurify": { "node_modules/dompurify": {
"version": "3.4.6", "version": "3.4.7",
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.6.tgz", "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.7.tgz",
"integrity": "sha512-+7gzEI8trIIQkVCvQ3ucGtNfH3nOmDgVTzc62rAAOlMxLth78pwpPoZCPc7CyRzAQF89MqcfPdEWkDwnjgqktg==", "integrity": "sha512-2jBxDJY4RR06tQNy4w5FlFH7kfxsQZlufd0sbv+chfHCxeJwrFw2baUDsSwvBISD4K4RDbd0PTfy3uNXsR6siA==",
"license": "(MPL-2.0 OR Apache-2.0)", "license": "(MPL-2.0 OR Apache-2.0)",
"optionalDependencies": { "optionalDependencies": {
"@types/trusted-types": "^2.0.7" "@types/trusted-types": "^2.0.7"
@ -9442,15 +9426,15 @@
} }
}, },
"node_modules/express": { "node_modules/express": {
"version": "4.22.1", "version": "4.22.2",
"resolved": "https://registry.npmjs.org/express/-/express-4.22.1.tgz", "resolved": "https://registry.npmjs.org/express/-/express-4.22.2.tgz",
"integrity": "sha512-F2X8g9P1X7uCPZMA3MVf9wcTqlyNp7IhH5qPCI0izhaOIYXaW9L535tGA3qmjRzpH+bZczqq7hVKxTR4NWnu+g==", "integrity": "sha512-IuL+Elrou2ZvCFHs18/CIzy2Nzvo25nZ1/D2eIZlz7c+QUayAcYoiM2BthCjs+EBHVpjYjcuLDAiCWgeIX3X1Q==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"accepts": "~1.3.8", "accepts": "~1.3.8",
"array-flatten": "1.1.1", "array-flatten": "1.1.1",
"body-parser": "~1.20.3", "body-parser": "~1.20.5",
"content-disposition": "~0.5.4", "content-disposition": "~0.5.4",
"content-type": "~1.0.4", "content-type": "~1.0.4",
"cookie": "~0.7.1", "cookie": "~0.7.1",
@ -9469,7 +9453,7 @@
"parseurl": "~1.3.3", "parseurl": "~1.3.3",
"path-to-regexp": "~0.1.12", "path-to-regexp": "~0.1.12",
"proxy-addr": "~2.0.7", "proxy-addr": "~2.0.7",
"qs": "~6.14.0", "qs": "~6.15.1",
"range-parser": "~1.2.1", "range-parser": "~1.2.1",
"safe-buffer": "5.2.1", "safe-buffer": "5.2.1",
"send": "~0.19.0", "send": "~0.19.0",
@ -9568,22 +9552,6 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"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==",
"dev": true,
"license": "BSD-3-Clause",
"dependencies": {
"side-channel": "^1.1.0"
},
"engines": {
"node": ">=0.6"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/express/node_modules/statuses": { "node_modules/express/node_modules/statuses": {
"version": "2.0.2", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz",
@ -12445,9 +12413,9 @@
} }
}, },
"node_modules/jsonata": { "node_modules/jsonata": {
"version": "2.1.0", "version": "2.2.1",
"resolved": "https://registry.npmjs.org/jsonata/-/jsonata-2.1.0.tgz", "resolved": "https://registry.npmjs.org/jsonata/-/jsonata-2.2.1.tgz",
"integrity": "sha512-OCzaRMK8HobtX8fp37uIVmL8CY1IGc/a6gLsDqz3quExFR09/U78HUzWYr7T31UEB6+Eu0/8dkVD5fFDOl9a8w==", "integrity": "sha512-xd1uwUrKeIcJbsWhaoS3qAX4Ea8m0Mw0G5nlnAQvPT7TbZ5qaPdzBVTQia9KfyuyQm+nenfyjvzUDTRYHsC2sw==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 8" "node": ">= 8"
@ -12715,9 +12683,19 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/linkify-it": { "node_modules/linkify-it": {
"version": "5.0.0", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.0.tgz", "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.1.tgz",
"integrity": "sha512-5aHCbzQRADcdP+ATqnDuhhJ/MRIqDkZX5pyjFHRRysS8vZ5AbqGEoFIb6pYHPZ+L/OC2Lc+xT8uHVVR5CAK/wQ==", "integrity": "sha512-wVoTjP4Q6R0NW5hiZkVJaFZPWgtXfoGF+6LucL3/FtiNjmcHhYjEr5f1Kqjirc1nBW07J/ZuRFumqr2oqccEWg==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/puzrin"
},
{
"type": "github",
"url": "https://github.com/sponsors/markdown-it"
}
],
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"uc.micro": "^2.0.0" "uc.micro": "^2.0.0"
@ -13034,14 +13012,24 @@
} }
}, },
"node_modules/markdown-it": { "node_modules/markdown-it": {
"version": "14.1.1", "version": "14.2.0",
"resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.1.1.tgz", "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.2.0.tgz",
"integrity": "sha512-BuU2qnTti9YKgK5N+IeMubp14ZUKUUw7yeJbkjtosvHiP0AZ5c8IAgEMk79D0eC8F23r4Ac/q8cAIFdm2FtyoA==", "integrity": "sha512-1TGiQiJVRQ3NPmZH6sx5Cfnmg6GQm9jvC1ch4TK511NjSJvjzKLzn5pPfZRNZkRPZP0HqCioSndqH8v2nRaWVQ==",
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/puzrin"
},
{
"type": "github",
"url": "https://github.com/sponsors/markdown-it"
}
],
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"argparse": "^2.0.1", "argparse": "^2.0.1",
"entities": "^4.4.0", "entities": "^4.4.0",
"linkify-it": "^5.0.0", "linkify-it": "^5.0.1",
"mdurl": "^2.0.0", "mdurl": "^2.0.0",
"punycode.js": "^2.3.1", "punycode.js": "^2.3.1",
"uc.micro": "^2.1.0" "uc.micro": "^2.1.0"
@ -13589,9 +13577,9 @@
} }
}, },
"node_modules/nightwatch": { "node_modules/nightwatch": {
"version": "3.15.0", "version": "3.16.0",
"resolved": "https://registry.npmjs.org/nightwatch/-/nightwatch-3.15.0.tgz", "resolved": "https://registry.npmjs.org/nightwatch/-/nightwatch-3.16.0.tgz",
"integrity": "sha512-Vvh7TsDyEN1YzOsDNoafEUPJDQ6jfnmJPAsWo/EmygljZiRk1Ja/pEqNAhE5UdYJzF38SNO46gJS8IRk9mUNfA==", "integrity": "sha512-B0/zFPY5ujEwIWIPqo2ClgITZ3chB3Nfq86YNWCyE3/P8BrCSvv2Y6BNUA+9mgu8WM/XF6GNlV3LONzZ1S+JSQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -13616,7 +13604,7 @@
"glob": "7.2.3", "glob": "7.2.3",
"jsdom": "^24.1.0", "jsdom": "^24.1.0",
"lodash": "^4.17.21", "lodash": "^4.17.21",
"minimatch": "3.1.2", "minimatch": "3.1.5",
"minimist": "1.2.6", "minimist": "1.2.6",
"mocha": "10.8.2", "mocha": "10.8.2",
"nightwatch-axe-verbose": "^2.3.0", "nightwatch-axe-verbose": "^2.3.0",
@ -13634,7 +13622,7 @@
"nightwatch": "bin/nightwatch" "nightwatch": "bin/nightwatch"
}, },
"engines": { "engines": {
"node": ">= 16" "node": ">= 18.20.5"
}, },
"peerDependencies": { "peerDependencies": {
"@cucumber/cucumber": "*" "@cucumber/cucumber": "*"
@ -13713,19 +13701,6 @@
"node": ">=10" "node": ">=10"
} }
}, },
"node_modules/nightwatch/node_modules/minimatch": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
"dev": true,
"license": "ISC",
"dependencies": {
"brace-expansion": "^1.1.7"
},
"engines": {
"node": "*"
}
},
"node_modules/nightwatch/node_modules/minimist": { "node_modules/nightwatch/node_modules/minimist": {
"version": "1.2.6", "version": "1.2.6",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz",
@ -15133,9 +15108,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/protobufjs": { "node_modules/protobufjs": {
"version": "7.6.1", "version": "7.6.2",
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.6.1.tgz", "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.6.2.tgz",
"integrity": "sha512-4K0myLaWL5EteuSAro91EGFgcfVgxb64Jx+7oDAY6GOkXD4M69yuSEljNcInGVCA5sOPxmZ/EqDLj2x0Q0+Ygg==", "integrity": "sha512-N9EiLovGEQOJSPF26Ij7qUGvahfEnq0eeYZ02aigIedkmz1qZSwjnP9SBITHJuF/6MYbIW4HDN8zdYjsjqJKXQ==",
"hasInstallScript": true, "hasInstallScript": true,
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"dependencies": { "dependencies": {
@ -15368,9 +15343,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/qs": { "node_modules/qs": {
"version": "6.15.0", "version": "6.15.2",
"resolved": "https://registry.npmjs.org/qs/-/qs-6.15.0.tgz", "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz",
"integrity": "sha512-mAZTtNCeetKMH+pSjrb76NAM8V9a05I9aBZOHztWy/UqcJdQYNsf59vrRKWnojAT9Y+GbIvoTBC++CPHqpDBhQ==", "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==",
"license": "BSD-3-Clause", "license": "BSD-3-Clause",
"dependencies": { "dependencies": {
"side-channel": "^1.1.0" "side-channel": "^1.1.0"
@ -17352,9 +17327,9 @@
} }
}, },
"node_modules/tmp": { "node_modules/tmp": {
"version": "0.2.5", "version": "0.2.7",
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.5.tgz", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz",
"integrity": "sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==", "integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {

View File

@ -39,7 +39,7 @@
"node >= 24" "node >= 24"
], ],
"devDependencies": { "devDependencies": {
"@babel/eslint-parser": "^7.28.6", "@babel/eslint-parser": "^7.29.7",
"@babel/plugin-syntax-import-assertions": "^7.28.6", "@babel/plugin-syntax-import-assertions": "^7.28.6",
"@babel/plugin-transform-runtime": "^7.29.7", "@babel/plugin-transform-runtime": "^7.29.7",
"@babel/preset-env": "^7.29.7", "@babel/preset-env": "^7.29.7",
@ -79,7 +79,7 @@
"imports-loader": "^5.0.0", "imports-loader": "^5.0.0",
"mini-css-extract-plugin": "2.10.2", "mini-css-extract-plugin": "2.10.2",
"modify-source-webpack-plugin": "^4.1.0", "modify-source-webpack-plugin": "^4.1.0",
"nightwatch": "^3.15.0", "nightwatch": "^3.16.0",
"postcss": "^8.5.15", "postcss": "^8.5.15",
"postcss-css-variables": "^0.19.0", "postcss-css-variables": "^0.19.0",
"postcss-import": "^16.1.1", "postcss-import": "^16.1.1",
@ -123,7 +123,7 @@
"d3": "7.9.0", "d3": "7.9.0",
"d3-hexbin": "^0.2.2", "d3-hexbin": "^0.2.2",
"diff": "^5.2.2", "diff": "^5.2.2",
"dompurify": "^3.4.6", "dompurify": "^3.4.7",
"es6-promisify": "^7.0.0", "es6-promisify": "^7.0.0",
"escodegen": "^2.1.0", "escodegen": "^2.1.0",
"esprima": "^4.0.1", "esprima": "^4.0.1",
@ -142,7 +142,7 @@
"js-sha3": "^0.9.3", "js-sha3": "^0.9.3",
"jsesc": "^3.1.0", "jsesc": "^3.1.0",
"json5": "^2.2.3", "json5": "^2.2.3",
"jsonata": "^2.1.0", "jsonata": "^2.2.1",
"jsonpath-plus": "^10.4.0", "jsonpath-plus": "^10.4.0",
"jsonwebtoken": "9.0.3", "jsonwebtoken": "9.0.3",
"jsqr": "^1.4.0", "jsqr": "^1.4.0",
@ -155,7 +155,7 @@
"loglevel-message-prefix": "^3.0.0", "loglevel-message-prefix": "^3.0.0",
"lz-string": "^1.5.0", "lz-string": "^1.5.0",
"lz4js": "^0.2.0", "lz4js": "^0.2.0",
"markdown-it": "^14.1.1", "markdown-it": "^14.2.0",
"moment": "^2.30.1", "moment": "^2.30.1",
"moment-timezone": "^0.6.2", "moment-timezone": "^0.6.2",
"ngeohash": "^0.6.3", "ngeohash": "^0.6.3",
@ -169,7 +169,7 @@
"path": "^0.12.7", "path": "^0.12.7",
"popper.js": "^1.16.1", "popper.js": "^1.16.1",
"process": "^0.11.10", "process": "^0.11.10",
"protobufjs": "^7.6.1", "protobufjs": "^7.6.2",
"punycode.js": "^2.3.1", "punycode.js": "^2.3.1",
"qr-image": "^3.2.0", "qr-image": "^3.2.0",
"reflect-metadata": "^0.2.2", "reflect-metadata": "^0.2.2",

View File

@ -49,6 +49,7 @@
"Escape Unicode Characters", "Escape Unicode Characters",
"Unescape Unicode Characters", "Unescape Unicode Characters",
"Normalise Unicode", "Normalise Unicode",
"Escape Smart Characters",
"To Quoted Printable", "To Quoted Printable",
"From Quoted Printable", "From Quoted Printable",
"To Punycode", "To Punycode",
@ -304,6 +305,7 @@
"Diff", "Diff",
"Remove whitespace", "Remove whitespace",
"Remove null bytes", "Remove null bytes",
"Remove ANSI Escape Codes",
"To Upper case", "To Upper case",
"To Lower case", "To Lower case",
"Swap case", "Swap case",

View File

@ -5,6 +5,7 @@
*/ */
import Operation from "../Operation.mjs"; import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import cptable from "codepage"; import cptable from "codepage";
import {CHR_ENC_CODE_PAGES} from "../lib/ChrEnc.mjs"; import {CHR_ENC_CODE_PAGES} from "../lib/ChrEnc.mjs";
@ -48,6 +49,9 @@ class DecodeText extends Operation {
*/ */
run(input, args) { run(input, args) {
const format = CHR_ENC_CODE_PAGES[args[0]]; const format = CHR_ENC_CODE_PAGES[args[0]];
if (!format) {
throw new OperationError("Invalid encoding");
}
return cptable.utils.decode(format, new Uint8Array(input)); return cptable.utils.decode(format, new Uint8Array(input));
} }

View File

@ -5,6 +5,7 @@
*/ */
import Operation from "../Operation.mjs"; import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import cptable from "codepage"; import cptable from "codepage";
import {CHR_ENC_CODE_PAGES} from "../lib/ChrEnc.mjs"; import {CHR_ENC_CODE_PAGES} from "../lib/ChrEnc.mjs";
@ -48,6 +49,9 @@ class EncodeText extends Operation {
*/ */
run(input, args) { run(input, args) {
const format = CHR_ENC_CODE_PAGES[args[0]]; const format = CHR_ENC_CODE_PAGES[args[0]];
if (!format) {
throw new OperationError("Invalid encoding");
}
const encoded = cptable.utils.encode(format, input); const encoded = cptable.utils.encode(format, input);
return new Uint8Array(encoded).buffer; return new Uint8Array(encoded).buffer;
} }

View File

@ -0,0 +1,129 @@
/**
* @author HarelKatz [github.com/HarelKatz]
* @copyright Crown Copyright 2026
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
/**
* Escape Smart Characters operation
*/
class EscapeSmartCharacters extends Operation {
/**
* EscapeSmartCharacters constructor
*/
constructor() {
super();
this.name = "Escape Smart Characters";
this.module = "Default";
this.description = "Converts smart (typographic) Unicode characters — e.g. smart quotes, em/en dashes, ellipses, ©, ®, ™, arrows — into their plain ASCII equivalents.<br><br>Characters with no ASCII mapping (e.g. <code>☣</code>) are handled according to the 'Unmappable characters' option.<br><br>e.g. <code>“Hello” — world…</code> becomes <code>\"Hello\" -- world...</code>";
this.infoURL = "";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
name: "Unmappable characters",
type: "option",
value: ["Include", "Remove", "Replace with '.'"]
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const [unmappable] = args;
let result = "";
for (const ch of input) {
if (ch.codePointAt(0) < 128) {
result += ch;
} else if (Object.prototype.hasOwnProperty.call(SMART_MAP, ch)) {
result += SMART_MAP[ch];
} else {
switch (unmappable) {
case "Remove":
break;
case "Replace with '.'":
result += ".";
break;
case "Include":
default:
result += ch;
break;
}
}
}
return result;
}
}
const SMART_MAP = {
// Smart double quotes
"“": "\"", // “ left double quotation mark
"”": "\"", // ” right double quotation mark
"„": "\"", // „ double low-9 quotation mark
"‟": "\"", // ‟ double high-reversed-9 quotation mark
"″": "\"", // ″ double prime
// Smart single quotes / apostrophes
"": "'", // left single quotation mark
"": "'", // right single quotation mark / apostrophe
"": "'", // single low-9 quotation mark
"": "'", // single high-reversed-9 quotation mark
"": "'", // prime
// Dashes & hyphens
"": "-", // hyphen
"": "-", // non-breaking hyphen
"": "-", // figure dash
"": "-", // en dash
"—": "--", // — em dash
"―": "--", // ― horizontal bar
// Ellipsis
"…": "...", // …
// Trademark / copyright symbols
"©": "(c)", // ©
"®": "(r)", // ®
"™": "(tm)", // ™
// Arrows
"←": "<--", // ←
"→": "-->", // →
"↑": "^", // ↑
"↓": "v", // ↓
"↔": "<->", // ↔
"⇐": "<==", // ⇐
"⇒": "==>", // ⇒
"⇔": "<=>", // ⇔
// Guillemets
"«": "<<", // «
"»": ">>", // »
"": "<", //
"": ">", //
// Math & misc symbols
"×": "x", // ×
"÷": "/", // ÷
"±": "+/-", // ±
"•": "*", // •
"·": ".", // ·
// Non-ASCII spaces
"\u00A0": " ", // NBSP
"\u2002": " ", // en space
"\u2003": " ", // em space
"\u2009": " ", // thin space
"\u200A": " " // hair space
};
export default EscapeSmartCharacters;

View File

@ -0,0 +1,41 @@
/**
* @author Louis-Ladd [lewisharshman1@gmail.com]
* @copyright Crown Copyright 2025
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
/**
* Remove ANSI Escape Codes operation
*/
class RemoveANSIEscapeCodes extends Operation {
/**
* RemoveANSIEscapeCodes constructor
*/
constructor() {
super();
this.name = "Remove ANSI Escape Codes";
this.module = "Default";
this.description = "Removes ANSI Escape Codes.";
this.infoURL = "https://wikipedia.org/wiki/ANSI_escape_code";
this.inputType = "string";
this.outputType = "string";
this.args = [];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const ansiRegex = /\x1B\[[0-?]*[ -/]*[@-~]/g;
return input.replace(ansiRegex, "");
}
}
export default RemoveANSIEscapeCodes;

View File

@ -166,6 +166,7 @@ class HTMLIngredient {
id="${this.id}" id="${this.id}"
tabindex="${this.tabIndex}" tabindex="${this.tabIndex}"
arg-name="${this.name}" arg-name="${this.name}"
data-target="${this.target}"
${this.disabled ? "disabled" : ""}>`; ${this.disabled ? "disabled" : ""}>`;
for (i = 0; i < this.value.length; i++) { for (i = 0; i < this.value.length; i++) {
if ((m = this.value[i].name.match(/\[([a-z0-9 -()^]+)\]/i))) { if ((m = this.value[i].name.match(/\[([a-z0-9 -()^]+)\]/i))) {

View File

@ -487,11 +487,19 @@ class RecipeWaiter {
* @param {HTMLElement} op * @param {HTMLElement} op
*/ */
triggerArgEvents(op) { triggerArgEvents(op) {
// Trigger populateOption and argSelector events // Trigger argSelector events and populateOption events only where the target is empty.
// When loading a saved recipe, arguments are populated before this method is called, so
// re-triggering populateOption events would overwrite saved custom values with defaults.
const args = op.querySelectorAll(".arg");
const triggerableOptions = op.querySelectorAll(".populate-option, .arg-selector"); const triggerableOptions = op.querySelectorAll(".populate-option, .arg-selector");
const evt = new Event("change", {bubbles: true}); const evt = new Event("change", {bubbles: true});
if (triggerableOptions.length) { if (triggerableOptions.length) {
for (const el of triggerableOptions) { for (const el of triggerableOptions) {
if (el.classList.contains("populate-option")) {
const target = args[el.getAttribute("data-target")];
if (target && target.value !== "") continue;
}
el.dispatchEvent(evt); el.dispatchEvent(evt);
} }
} }

View File

@ -0,0 +1,48 @@
/**
* Regression tests for recipe loading behaviour.
*
* @author C85297 [95289555+C85297@users.noreply.github.com]
* @copyright Crown Copyright
* @license Apache-2.0
*/
const utils = require("./browserUtils.js");
module.exports = {
before: browser => {
browser
.resizeWindow(1280, 800)
.url(browser.launchUrl)
.useCss()
.waitForElementNotPresent("#preloader", 10000);
},
"Recipe load preserves populated arguments": browser => {
const inputFormat = "HH:mm:ss a MMM DD, YYYY ";
const input = "10:20:30 pm Sep 26, 2019 ";
utils.loadRecipe(
browser,
"Translate DateTime Format",
input,
[
"Standard date and time",
inputFormat,
"UTC",
"DD/MM/YYYY HH:mm:ss",
"UTC"
]
);
browser.execute(() => {
return Array.from(document.querySelectorAll("#rec-list li.operation .arg"))
.map(arg => arg.value);
}, [], function({value}) {
browser.expect(value[1]).to.equal(inputFormat);
});
},
after: browser => {
browser.end();
}
};

View File

@ -69,6 +69,7 @@ import "./tests/DropNthBytes.mjs";
import "./tests/ECDSA.mjs"; import "./tests/ECDSA.mjs";
import "./tests/ELFInfo.mjs"; import "./tests/ELFInfo.mjs";
import "./tests/Enigma.mjs"; import "./tests/Enigma.mjs";
import "./tests/EscapeSmartCharacters.mjs";
import "./tests/ExtractAudioMetadata.mjs"; import "./tests/ExtractAudioMetadata.mjs";
import "./tests/ExtractEmailAddresses.mjs"; import "./tests/ExtractEmailAddresses.mjs";
import "./tests/ExtractHashes.mjs"; import "./tests/ExtractHashes.mjs";
@ -148,6 +149,7 @@ import "./tests/Rabbit.mjs";
import "./tests/RAKE.mjs"; import "./tests/RAKE.mjs";
import "./tests/Regex.mjs"; import "./tests/Regex.mjs";
import "./tests/Register.mjs"; import "./tests/Register.mjs";
import "./tests/RemoveANSIEscapeCodes.mjs";
import "./tests/RegularExpression.mjs"; import "./tests/RegularExpression.mjs";
import "./tests/RenderMarkdown.mjs"; import "./tests/RenderMarkdown.mjs";
import "./tests/RisonEncodeDecode.mjs"; import "./tests/RisonEncodeDecode.mjs";

View File

@ -68,6 +68,32 @@ TestRegister.addTests([
}, },
], ],
}, },
{
name: "Encode text: empty encoding",
input: "hello",
expectedOutput: "Invalid encoding",
recipeConfig: [
{
"op": "Encode text",
"args": [""]
},
],
},
{
name: "Decode text: empty encoding",
input: "68 65 6c 6c 6f",
expectedOutput: "Invalid encoding",
recipeConfig: [
{
"op": "From Hex",
"args": ["Space"]
},
{
"op": "Decode text",
"args": [""]
},
],
},
{ {
name: "Generate Base64 Windows PowerShell", name: "Generate Base64 Windows PowerShell",
input: "ZABpAHIAIAAiAGMAOgBcAHAAcgBvAGcAcgBhAG0AIABmAGkAbABlAHMAIgAgAA==", input: "ZABpAHIAIAAiAGMAOgBcAHAAcgBvAGcAcgBhAG0AIABmAGkAbABlAHMAIgAgAA==",

View File

@ -0,0 +1,132 @@
/**
* Escape Smart Characters tests
*
* @author HarelKatz [github.com/HarelKatz]
* @copyright Crown Copyright 2026
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";
TestRegister.addTests([
{
"name": "Escape Smart Characters: smart quotes and apostrophes",
"input": "“Hello,” she said, yes.",
"expectedOutput": "\"Hello,\" she said, 'yes.'",
"recipeConfig": [
{
"op": "Escape Smart Characters",
"args": ["Include"]
}
]
},
{
"name": "Escape Smart Characters: em dash, en dash and ellipsis",
"input": "page 13 — wait…",
"expectedOutput": "page 1-3 -- wait...",
"recipeConfig": [
{
"op": "Escape Smart Characters",
"args": ["Include"]
}
]
},
{
"name": "Escape Smart Characters: trademark symbols",
"input": "Foo© Bar® Baz™",
"expectedOutput": "Foo(c) Bar(r) Baz(tm)",
"recipeConfig": [
{
"op": "Escape Smart Characters",
"args": ["Include"]
}
]
},
{
"name": "Escape Smart Characters: arrows and guillemets",
"input": "← → ↔ ⇒ « »",
"expectedOutput": "<-- --> <-> ==> << >>",
"recipeConfig": [
{
"op": "Escape Smart Characters",
"args": ["Include"]
}
]
},
{
"name": "Escape Smart Characters: math and misc",
"input": "3 × 4 ÷ 2 = 6, ±0.5 • item",
"expectedOutput": "3 x 4 / 2 = 6, +/-0.5 * item",
"recipeConfig": [
{
"op": "Escape Smart Characters",
"args": ["Include"]
}
]
},
{
"name": "Escape Smart Characters: NBSP becomes regular space",
"input": "a bc",
"expectedOutput": "a b c",
"recipeConfig": [
{
"op": "Escape Smart Characters",
"args": ["Include"]
}
]
},
{
"name": "Escape Smart Characters: unmappable Include preserves char",
"input": "warning: ☣ hazard",
"expectedOutput": "warning: ☣ hazard",
"recipeConfig": [
{
"op": "Escape Smart Characters",
"args": ["Include"]
}
]
},
{
"name": "Escape Smart Characters: unmappable Remove drops char",
"input": "warning: ☣ hazard",
"expectedOutput": "warning: hazard",
"recipeConfig": [
{
"op": "Escape Smart Characters",
"args": ["Remove"]
}
]
},
{
"name": "Escape Smart Characters: unmappable Replace substitutes dot",
"input": "warning: ☣ hazard",
"expectedOutput": "warning: . hazard",
"recipeConfig": [
{
"op": "Escape Smart Characters",
"args": ["Replace with '.'"]
}
]
},
{
"name": "Escape Smart Characters: pure ASCII passes through",
"input": "hello world! 123",
"expectedOutput": "hello world! 123",
"recipeConfig": [
{
"op": "Escape Smart Characters",
"args": ["Include"]
}
]
},
{
"name": "Escape Smart Characters: empty input",
"input": "",
"expectedOutput": "",
"recipeConfig": [
{
"op": "Escape Smart Characters",
"args": ["Include"]
}
]
}
]);

View File

@ -0,0 +1,62 @@
/**
* @author Louis-Ladd [lewisharshman1@gmail.com]
* @copyright Crown Copyright 2025
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";
TestRegister.addTests([
{
"name": "Remove ANSI Escape Codes: text using x1b escape code",
"input": "\x1b[31mHello, \x1b[31mWorld!",
"expectedOutput": "Hello, World!",
"recipeConfig": [
{
"op": "Remove ANSI Escape Codes",
"args": [],
},
],
},
{
"name": "Remove ANSI Escape Codes: text with incomplete codes",
"input": "\x1b[31 Hello, World!",
"expectedOutput": "ello, World!",
"recipeConfig": [
{
"op": "Remove ANSI Escape Codes",
"args": [],
},
],
},
{
"name": "Remove ANSI Escape Codes: cursor commands and clear screen",
"input": "\x1b[2J\x1b[H\x1b[3BHello, World!",
"expectedOutput": "Hello, World!",
"recipeConfig": [
{
"op": "Remove ANSI Escape Codes",
"args": [],
},
],
},
{
"name": "Remove ANSI Escape Codes: text containing javascript escape representation of ansi escape codes",
// input/output expressed in hex to avoid accidental interpretation of Javascript escapes and to make the test case explicit
"input": "5c 30 33 33 5b 33 32 3b 31 3b 33 3b 34 3b 39 6d 48 65 6c 6c 6f 2c 20 5c 30 33 33 5b 33 32 3b 31 3b 33 3b 34 3b 39 6d 57 6f 72 6c 64 21",
"expectedOutput": "5c 30 33 33 5b 33 32 3b 31 3b 33 3b 34 3b 39 6d 48 65 6c 6c 6f 2c 20 5c 30 33 33 5b 33 32 3b 31 3b 33 3b 34 3b 39 6d 57 6f 72 6c 64 21",
"recipeConfig": [
{
"op": "From Hex",
"args": ["Auto"]
},
{
"op": "Remove ANSI Escape Codes",
"args": []
},
{
"op": "To Hex",
"args": ["Space", 0]
}
],
},
]);