Merge branch 'master' into jwt-decode-verify
This commit is contained in:
commit
8cefec8698
@ -4,7 +4,7 @@
|
||||
# Modifier --platform=$BUILDPLATFORM limits the platform to "BUILDPLATFORM" during buildx multi-platform builds
|
||||
# This is because npm "chromedriver" package is not compatiable with all platforms
|
||||
# For more info see: https://docs.docker.com/build/building/multi-platform/#cross-compilation
|
||||
FROM --platform=$BUILDPLATFORM node:24-alpine@sha256:fb71d01345f11b708a3553c66e7c74074f2d506400ea81973343d915cb64eef0 AS builder
|
||||
FROM --platform=$BUILDPLATFORM node:24-alpine@sha256:156b55f92e98ccd5ef49578a8cea0df4679826564bad1c9d4ef04462b9f0ded6 AS builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
@ -27,7 +27,7 @@ RUN npm run build
|
||||
#########################################
|
||||
# Package static build files into nginx #
|
||||
#########################################
|
||||
FROM nginxinc/nginx-unprivileged:stable-alpine@sha256:37f356a5eba5d187365b4f59cd6cc29f1f922ad18146d554b576a80983377e6a AS cyberchef
|
||||
FROM nginxinc/nginx-unprivileged:stable-alpine@sha256:fafa1102c789119971b3d83f9293f1ef5526bc73583a12e13ff5cd1299ed8b6c AS cyberchef
|
||||
|
||||
LABEL maintainer="GCHQ <oss@gchq.gov.uk>"
|
||||
|
||||
|
||||
56
package-lock.json
generated
56
package-lock.json
generated
@ -21,7 +21,7 @@
|
||||
"assert": "^2.1.0",
|
||||
"avsc": "^5.7.9",
|
||||
"bcryptjs": "^3.0.3",
|
||||
"bignumber.js": "^11.1.3",
|
||||
"bignumber.js": "^11.1.4",
|
||||
"blakejs": "^1.2.1",
|
||||
"bootstrap": "4.6.2",
|
||||
"bootstrap-colorpicker": "^3.4.0",
|
||||
@ -39,7 +39,7 @@
|
||||
"d3": "7.9.0",
|
||||
"d3-hexbin": "^0.2.2",
|
||||
"diff": "^9.0.0",
|
||||
"dompurify": "^3.4.9",
|
||||
"dompurify": "^3.4.11",
|
||||
"es6-promisify": "^7.0.0",
|
||||
"escodegen": "^2.1.0",
|
||||
"esprima": "^4.0.1",
|
||||
@ -85,7 +85,7 @@
|
||||
"path": "^0.12.7",
|
||||
"popper.js": "^1.16.1",
|
||||
"process": "^0.11.10",
|
||||
"protobufjs": "^8.6.2",
|
||||
"protobufjs": "^8.6.4",
|
||||
"punycode.js": "^2.3.1",
|
||||
"qr-image": "^3.2.0",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
@ -116,7 +116,7 @@
|
||||
"@babel/runtime": "^7.29.7",
|
||||
"@codemirror/commands": "^6.10.3",
|
||||
"@codemirror/language": "^6.12.3",
|
||||
"@codemirror/search": "^6.7.0",
|
||||
"@codemirror/search": "^6.7.1",
|
||||
"@codemirror/state": "^6.5.4",
|
||||
"@codemirror/view": "^6.43.1",
|
||||
"@puppeteer/browsers": "3.0.4",
|
||||
@ -159,7 +159,7 @@
|
||||
"terser": "^5.48.0",
|
||||
"webpack": "^5.107.2",
|
||||
"webpack-bundle-analyzer": "^5.3.0",
|
||||
"webpack-dev-server": "^5.2.4",
|
||||
"webpack-dev-server": "^5.2.5",
|
||||
"webpack-node-externals": "^3.0.0",
|
||||
"worker-loader": "^3.0.8"
|
||||
},
|
||||
@ -1876,9 +1876,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@codemirror/search": {
|
||||
"version": "6.7.0",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.7.0.tgz",
|
||||
"integrity": "sha512-ZvGm99wc/s2cITtMT15LFdn8aH/aS+V+DqyGq/N5ZlV5vWtH+nILvC2nw0zX7ByNoHHDZ2IxxdW38O0tc5nVHg==",
|
||||
"version": "6.7.1",
|
||||
"resolved": "https://registry.npmjs.org/@codemirror/search/-/search-6.7.1.tgz",
|
||||
"integrity": "sha512-uMe5UO6PamJtSHrXhhHOzSX3ReWtiJrva6GnPMwSOrZtiExb5X5eExhr2OUZQVvdxPsKpY3Ro2mFbQadpPWmHA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@ -5794,9 +5794,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/bignumber.js": {
|
||||
"version": "11.1.3",
|
||||
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-11.1.3.tgz",
|
||||
"integrity": "sha512-+esZiNSo6VgFokTsYX6mYqNJfFd/IczzZCd4Z7cR8e+AQWhvIcj6nqQ1h9814D9u/TApU0jjTVmfWL0Pd1ZBdA==",
|
||||
"version": "11.1.4",
|
||||
"resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-11.1.4.tgz",
|
||||
"integrity": "sha512-AJ9dSeaUGj2xu7tEwmdqb51dqdb633xo4njI9K8ZFfcLrNr0XN8/EPkkZUNaF9fkCblGt2zVwZymesUdGynEkQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/binary-extensions": {
|
||||
@ -8585,9 +8585,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/dompurify": {
|
||||
"version": "3.4.9",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.9.tgz",
|
||||
"integrity": "sha512-4dPSRMRDqHvs0V4YDFCsaIZo4if5u0xM+llyxiM2fwuZFdKArUBAF3VtI2+n8NKg9P870WMdYk0UhqQNoWXbfQ==",
|
||||
"version": "3.4.11",
|
||||
"resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.4.11.tgz",
|
||||
"integrity": "sha512-zhlUV12GsaRzMsf9q5M254YhA4+VuF0fG+QFqu6aYpoGlKtz+w8//jBcGVYBgQkR5GHjUomejY84AV+/uPbWdw==",
|
||||
"license": "(MPL-2.0 OR Apache-2.0)",
|
||||
"optionalDependencies": {
|
||||
"@types/trusted-types": "^2.0.7"
|
||||
@ -9865,17 +9865,17 @@
|
||||
}
|
||||
},
|
||||
"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.6",
|
||||
"resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz",
|
||||
"integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==",
|
||||
"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"
|
||||
"hasown": "^2.0.4",
|
||||
"mime-types": "^2.1.35"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
@ -10907,9 +10907,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/hasown": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||
"integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz",
|
||||
"integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"function-bind": "^1.1.2"
|
||||
@ -15086,9 +15086,9 @@
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/protobufjs": {
|
||||
"version": "8.6.2",
|
||||
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-8.6.2.tgz",
|
||||
"integrity": "sha512-CCERJxzRvKMeEdJSLwdQf40TXWNPc8M4RkN7j/lxY6FQB+4do8rETWqj60AqxP9n0XIsxnSefZ8uhAaGKg2njw==",
|
||||
"version": "8.6.4",
|
||||
"resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-8.6.4.tgz",
|
||||
"integrity": "sha512-/+XMv9JalknuncEJSwsyEVlwcxVLKx2iaoSUXFZA86MJkdqyOdfrlB1sB7S6aKyUk9tl20YY+SgQe5J2sJHTcg==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"long": "^5.3.2"
|
||||
@ -18112,9 +18112,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/webpack-dev-server": {
|
||||
"version": "5.2.4",
|
||||
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.4.tgz",
|
||||
"integrity": "sha512-GqDPGZN9bRqKBTkp4aWkobDDHMsrXKoGSdOH56smIri8qR0JG8gfL8/v/f/OZR3/OKXjG8uwJbFVhKm/FNU/UA==",
|
||||
"version": "5.2.5",
|
||||
"resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-5.2.5.tgz",
|
||||
"integrity": "sha512-4wZtCquSuv9CKX8oybo+mqxtxZqWz47uM1Ch94lxowBztOhWCbhqvRbfC/mODOwxgV2brY+JGZpHq58/SuVFYg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
||||
10
package.json
10
package.json
@ -46,7 +46,7 @@
|
||||
"@babel/runtime": "^7.29.7",
|
||||
"@codemirror/commands": "^6.10.3",
|
||||
"@codemirror/language": "^6.12.3",
|
||||
"@codemirror/search": "^6.7.0",
|
||||
"@codemirror/search": "^6.7.1",
|
||||
"@codemirror/state": "^6.5.4",
|
||||
"@codemirror/view": "^6.43.1",
|
||||
"@puppeteer/browsers": "3.0.4",
|
||||
@ -89,7 +89,7 @@
|
||||
"terser": "^5.48.0",
|
||||
"webpack": "^5.107.2",
|
||||
"webpack-bundle-analyzer": "^5.3.0",
|
||||
"webpack-dev-server": "^5.2.4",
|
||||
"webpack-dev-server": "^5.2.5",
|
||||
"webpack-node-externals": "^3.0.0",
|
||||
"worker-loader": "^3.0.8"
|
||||
},
|
||||
@ -105,7 +105,7 @@
|
||||
"assert": "^2.1.0",
|
||||
"avsc": "^5.7.9",
|
||||
"bcryptjs": "^3.0.3",
|
||||
"bignumber.js": "^11.1.3",
|
||||
"bignumber.js": "^11.1.4",
|
||||
"blakejs": "^1.2.1",
|
||||
"bootstrap": "4.6.2",
|
||||
"bootstrap-colorpicker": "^3.4.0",
|
||||
@ -123,7 +123,7 @@
|
||||
"d3": "7.9.0",
|
||||
"d3-hexbin": "^0.2.2",
|
||||
"diff": "^9.0.0",
|
||||
"dompurify": "^3.4.9",
|
||||
"dompurify": "^3.4.11",
|
||||
"es6-promisify": "^7.0.0",
|
||||
"escodegen": "^2.1.0",
|
||||
"esprima": "^4.0.1",
|
||||
@ -169,7 +169,7 @@
|
||||
"path": "^0.12.7",
|
||||
"popper.js": "^1.16.1",
|
||||
"process": "^0.11.10",
|
||||
"protobufjs": "^8.6.2",
|
||||
"protobufjs": "^8.6.4",
|
||||
"punycode.js": "^2.3.1",
|
||||
"qr-image": "^3.2.0",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
|
||||
@ -32,6 +32,8 @@ class Ingredient {
|
||||
this.min = null;
|
||||
this.max = null;
|
||||
this.step = 1;
|
||||
this.integer = false;
|
||||
this.allowEmpty = true;
|
||||
|
||||
if (ingredientConfig) {
|
||||
this._parseConfig(ingredientConfig);
|
||||
@ -59,6 +61,70 @@ class Ingredient {
|
||||
this.min = ingredientConfig.min;
|
||||
this.max = ingredientConfig.max;
|
||||
this.step = ingredientConfig.step;
|
||||
this.integer = typeof ingredientConfig.integer !== "undefined" ? !!ingredientConfig.integer : false;
|
||||
this.allowEmpty = typeof ingredientConfig.allowEmpty !== "undefined" ? !!ingredientConfig.allowEmpty : true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validates the given value against the constraints of this ingredient.
|
||||
*
|
||||
* @param {*} val
|
||||
* @returns {boolean}
|
||||
*/
|
||||
validate(val) {
|
||||
if (this.disabled) return true;
|
||||
|
||||
let checkVal = val;
|
||||
if (this.type === "toggleString" && val && typeof val === "object" && "string" in val) {
|
||||
checkVal = val.string;
|
||||
}
|
||||
|
||||
// 1. check if empty
|
||||
let isEmpty = false;
|
||||
if (checkVal === null || checkVal === undefined || checkVal === "") {
|
||||
isEmpty = true;
|
||||
} else if (typeof checkVal.length === "number" && checkVal.length === 0) {
|
||||
isEmpty = true;
|
||||
}
|
||||
|
||||
if (isEmpty) {
|
||||
if (this.allowEmpty === false) {
|
||||
throw new OperationError(`${this.name} cannot be empty.`);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// 2. maxLength check
|
||||
if (typeof this.maxLength === "number" && checkVal !== null && checkVal !== undefined) {
|
||||
if (typeof checkVal === "string" && checkVal.length > this.maxLength) {
|
||||
throw new OperationError(`${this.name} length cannot exceed ${this.maxLength}.`);
|
||||
}
|
||||
if (Array.isArray(checkVal) && checkVal.length > this.maxLength) {
|
||||
throw new OperationError(`${this.name} length cannot exceed ${this.maxLength}.`);
|
||||
}
|
||||
if (checkVal instanceof Uint8Array && checkVal.length > this.maxLength) {
|
||||
throw new OperationError(`${this.name} length cannot exceed ${this.maxLength}.`);
|
||||
}
|
||||
}
|
||||
|
||||
// 3. number checks
|
||||
if (this.type === "number") {
|
||||
if (val === null || val === undefined || isNaN(val)) {
|
||||
throw new OperationError(`${this.name} must be a number.`);
|
||||
}
|
||||
if (this.integer && !Number.isInteger(val)) {
|
||||
throw new OperationError(`${this.name} must be an integer.`);
|
||||
}
|
||||
if (typeof this.min === "number" && val < this.min) {
|
||||
throw new OperationError(`${this.name} must be greater than or equal to ${this.min}.`);
|
||||
}
|
||||
if (typeof this.max === "number" && val > this.max) {
|
||||
throw new OperationError(`${this.name} must be less than or equal to ${this.max}.`);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -189,11 +189,30 @@ class Operation {
|
||||
if (typeof ing.min === "number") conf.min = ing.min;
|
||||
if (typeof ing.max === "number") conf.max = ing.max;
|
||||
if (ing.step) conf.step = ing.step;
|
||||
if (typeof ing.integer !== "undefined") conf.integer = ing.integer;
|
||||
if (typeof ing.allowEmpty !== "undefined") conf.allowEmpty = ing.allowEmpty;
|
||||
return conf;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Validates the operation's ingredients against their defined constraints.
|
||||
*
|
||||
* @param {Object[]} [args] - Optional list of argument values to validate. If not provided, validates the current ingredient values.
|
||||
* @returns {boolean} - True if valid, throws an OperationError if invalid.
|
||||
*/
|
||||
validateIngredients(args) {
|
||||
const values = args || this.ingValues;
|
||||
this._ingList.forEach((ing, i) => {
|
||||
if (i < values.length) {
|
||||
ing.validate(values[i]);
|
||||
}
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the value of the Operation as it should be displayed in a recipe config.
|
||||
*
|
||||
|
||||
@ -212,6 +212,8 @@ class Recipe {
|
||||
self.sendProgressMessage(i + 1, this.opList.length);
|
||||
}
|
||||
|
||||
op.validateIngredients(op.ingValues);
|
||||
|
||||
if (op.flowControl) {
|
||||
// Package up the current state
|
||||
let state = {
|
||||
|
||||
@ -585,7 +585,8 @@
|
||||
"HTML To Text",
|
||||
"Generate Lorem Ipsum",
|
||||
"Numberwang",
|
||||
"XKCD Random Number"
|
||||
"XKCD Random Number",
|
||||
"Automated Validation Test Op"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
78
src/core/operations/AutomatedValidationTestOp.mjs
Normal file
78
src/core/operations/AutomatedValidationTestOp.mjs
Normal file
@ -0,0 +1,78 @@
|
||||
/**
|
||||
* @author CyberChef
|
||||
* @copyright Crown Copyright 2026
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
|
||||
/**
|
||||
* Automated validation test operation
|
||||
*/
|
||||
class AutomatedValidationTestOp extends Operation {
|
||||
|
||||
/**
|
||||
* AutomatedValidationTestOp constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Automated Validation Test Op";
|
||||
this.module = "Default";
|
||||
this.description = "Operation used specifically to test automated parameter validation.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Integer Number",
|
||||
"type": "number",
|
||||
"value": 5,
|
||||
"min": 5,
|
||||
"max": 10,
|
||||
"integer": true
|
||||
},
|
||||
{
|
||||
"name": "Real Number",
|
||||
"type": "number",
|
||||
"value": 1.5,
|
||||
"min": 1.5,
|
||||
"max": 5.5
|
||||
},
|
||||
{
|
||||
"name": "Non Empty String",
|
||||
"type": "string",
|
||||
"value": "hello",
|
||||
"maxLength": 5,
|
||||
"allowEmpty": false
|
||||
},
|
||||
{
|
||||
"name": "Empty Allowed String",
|
||||
"type": "string",
|
||||
"value": "",
|
||||
"allowEmpty": true
|
||||
},
|
||||
{
|
||||
"name": "Non Empty Toggle String",
|
||||
"type": "toggleString",
|
||||
"value": {
|
||||
"option": "Option A",
|
||||
"string": "test"
|
||||
},
|
||||
"toggleValues": ["Option A", "Option B"],
|
||||
"allowEmpty": false
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
return "Success";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default AutomatedValidationTestOp;
|
||||
@ -21,7 +21,7 @@ class URLEncode extends Operation {
|
||||
this.module = "URL";
|
||||
this.description = "Encodes problematic characters into percent-encoding, a format supported by URIs/URLs.<br><br>e.g. <code>=</code> becomes <code>%3d</code>";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Percent-encoding";
|
||||
this.inputType = "string";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
@ -33,34 +33,38 @@ class URLEncode extends Operation {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const encodeAll = args[0];
|
||||
return encodeAll ? this.encodeAllChars(input) : encodeURI(input);
|
||||
return this.encodeBytes(input, encodeAll);
|
||||
}
|
||||
|
||||
/**
|
||||
* Encode characters in URL outside of encodeURI() function spec
|
||||
* Encode bytes in URL using percent encoding.
|
||||
*
|
||||
* @param {string} str
|
||||
* @param {byteArray} bytes
|
||||
* @param {boolean} encodeAll
|
||||
* @returns {string}
|
||||
*/
|
||||
encodeAllChars (str) {
|
||||
// TODO Do this programmatically
|
||||
return encodeURIComponent(str)
|
||||
.replace(/!/g, "%21")
|
||||
.replace(/#/g, "%23")
|
||||
.replace(/'/g, "%27")
|
||||
.replace(/\(/g, "%28")
|
||||
.replace(/\)/g, "%29")
|
||||
.replace(/\*/g, "%2A")
|
||||
.replace(/-/g, "%2D")
|
||||
.replace(/\./g, "%2E")
|
||||
.replace(/_/g, "%5F")
|
||||
.replace(/~/g, "%7E");
|
||||
encodeBytes(bytes, encodeAll) {
|
||||
const safeChars = encodeAll ?
|
||||
/^[A-Za-z0-9]$/ :
|
||||
/^[A-Za-z0-9:/?#[\]@!$&'()*+,;=%]$/;
|
||||
|
||||
let output = "";
|
||||
|
||||
for (const byte of bytes) {
|
||||
const char = String.fromCharCode(byte);
|
||||
|
||||
output += safeChars.test(char) ?
|
||||
char :
|
||||
"%" + byte.toString(16).toUpperCase().padStart(2, "0");
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -193,6 +193,8 @@ export function _wrap(OpClass) {
|
||||
wrapped = async (input, args=null) => {
|
||||
const {transformedInput, transformedArgs} = prepareOp(opInstance, input, args);
|
||||
|
||||
opInstance.validateIngredients(transformedArgs);
|
||||
|
||||
// SPECIAL CASE for Magic. Other flowControl operations will
|
||||
// not work because the opList is not passed in.
|
||||
if (isFlowControl) {
|
||||
@ -229,6 +231,7 @@ export function _wrap(OpClass) {
|
||||
*/
|
||||
wrapped = (input, args=null) => {
|
||||
const {transformedInput, transformedArgs} = prepareOp(opInstance, input, args);
|
||||
opInstance.validateIngredients(transformedArgs);
|
||||
const result = opInstance.run(transformedInput, transformedArgs);
|
||||
return new NodeDish({
|
||||
value: result,
|
||||
|
||||
@ -24,6 +24,14 @@
|
||||
height: 100%;
|
||||
user-select: auto;
|
||||
}
|
||||
|
||||
#output-html > img {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
margin: auto;
|
||||
}
|
||||
|
||||
#output-text.html-output .cm-line .cm-widgetBuffer,
|
||||
#output-text.html-output .cm-line>br {
|
||||
display: none;
|
||||
|
||||
@ -492,7 +492,22 @@ function testOpImage(browser, opName, filename, args=[]) {
|
||||
|
||||
browser
|
||||
.waitForElementVisible("#output-html img")
|
||||
.expect.element("#output-html img").to.have.css("width").which.matches(/^[^0]\d*px/);
|
||||
.expect.element("#output-html img").to.have.css("width").which.matches(/^(?!0+(?:\.0+)?px$)\d+(?:\.\d+)?px$/);
|
||||
|
||||
browser.execute(function() {
|
||||
const output = document.getElementById("output-html");
|
||||
const img = output.querySelector("img");
|
||||
const outputRect = output.getBoundingClientRect();
|
||||
const imgRect = img.getBoundingClientRect();
|
||||
|
||||
return {
|
||||
imageFitsWidth: imgRect.width <= outputRect.width,
|
||||
imageFitsHeight: imgRect.height <= outputRect.height,
|
||||
};
|
||||
}, [], function({value}) {
|
||||
browser.expect(value.imageFitsWidth).to.be.equal(true);
|
||||
browser.expect(value.imageFitsHeight).to.be.equal(true);
|
||||
});
|
||||
}
|
||||
|
||||
/** @function
|
||||
|
||||
121
tests/operations/tests/AutomatedValidation.mjs
Normal file
121
tests/operations/tests/AutomatedValidation.mjs
Normal file
@ -0,0 +1,121 @@
|
||||
/**
|
||||
* Automated Parameter Validation tests
|
||||
*
|
||||
* @author CyberChef
|
||||
* @copyright Crown Copyright 2026
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "Automated Validation: Valid values",
|
||||
input: "test",
|
||||
expectedOutput: "Success",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Automated Validation Test Op",
|
||||
args: [5, 1.5, "hello", "", { "option": "Option A", "string": "test" }]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Automated Validation: Integer Number under min limit",
|
||||
input: "test",
|
||||
expectedOutput: "Integer Number must be greater than or equal to 5.",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Automated Validation Test Op",
|
||||
args: [4, 1.5, "hello", "", { "option": "Option A", "string": "test" }]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Automated Validation: Integer Number over max limit",
|
||||
input: "test",
|
||||
expectedOutput: "Integer Number must be less than or equal to 10.",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Automated Validation Test Op",
|
||||
args: [11, 1.5, "hello", "", { "option": "Option A", "string": "test" }]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Automated Validation: Integer Number not an integer",
|
||||
input: "test",
|
||||
expectedOutput: "Integer Number must be an integer.",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Automated Validation Test Op",
|
||||
args: [5.5, 1.5, "hello", "", { "option": "Option A", "string": "test" }]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Automated Validation: Real Number under min limit",
|
||||
input: "test",
|
||||
expectedOutput: "Real Number must be greater than or equal to 1.5.",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Automated Validation Test Op",
|
||||
args: [5, 1.4, "hello", "", { "option": "Option A", "string": "test" }]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Automated Validation: Real Number over max limit",
|
||||
input: "test",
|
||||
expectedOutput: "Real Number must be less than or equal to 5.5.",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Automated Validation Test Op",
|
||||
args: [5, 5.6, "hello", "", { "option": "Option A", "string": "test" }]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Automated Validation: Non Empty String over maxLength limit",
|
||||
input: "test",
|
||||
expectedOutput: "Non Empty String length cannot exceed 5.",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Automated Validation Test Op",
|
||||
args: [5, 1.5, "helloooo", "", { "option": "Option A", "string": "test" }]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Automated Validation: Non Empty String is empty",
|
||||
input: "test",
|
||||
expectedOutput: "Non Empty String cannot be empty.",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Automated Validation Test Op",
|
||||
args: [5, 1.5, "", "", { "option": "Option A", "string": "test" }]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Automated Validation: Empty Allowed String is empty (allowed)",
|
||||
input: "test",
|
||||
expectedOutput: "Success",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Automated Validation Test Op",
|
||||
args: [5, 1.5, "hello", "", { "option": "Option A", "string": "test" }]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "Automated Validation: Non Empty Toggle String is empty",
|
||||
input: "test",
|
||||
expectedOutput: "Non Empty Toggle String cannot be empty.",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Automated Validation Test Op",
|
||||
args: [5, 1.5, "hello", "", { "option": "Option A", "string": "" }]
|
||||
}
|
||||
]
|
||||
}
|
||||
]);
|
||||
@ -129,7 +129,7 @@ TestRegister.addTests([
|
||||
{
|
||||
name: "To Hexdump: Width too large",
|
||||
input: "H",
|
||||
expectedOutput: "Width must be no more than 65536",
|
||||
expectedOutput: "Width must be less than or equal to 65536.",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "To Hexdump",
|
||||
|
||||
@ -89,4 +89,30 @@ TestRegister.addTests([
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "URLEncode: encodes UTF-8 text as UTF-8 bytes",
|
||||
input: "你好",
|
||||
expectedOutput: "%E4%BD%A0%E5%A5%BD",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "URL Encode",
|
||||
args: [false],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "URLEncode: preserves raw bytes from From Hex",
|
||||
input: "6c6567697466696c6580000000000000000000000000000000000000000000000000000000000000000000000000000000000000000090746869737761737375706f736564746f6265616e6578706c6f6974",
|
||||
expectedOutput: "legitfile%80%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%00%90thiswassuposedtobeanexploit",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "From Hex",
|
||||
args: ["None"],
|
||||
},
|
||||
{
|
||||
op: "URL Encode",
|
||||
args: [false],
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user