mirror of
https://github.com/gchq/CyberChef
synced 2026-02-04 10:44:01 +00:00
Compare commits
40 Commits
ipv6-addre
...
fix/docker
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
188b25d7a3 | ||
|
|
967f93aa63 | ||
|
|
c57556f49f | ||
|
|
18e5b9f6ec | ||
|
|
411f78d27a | ||
|
|
7ed7fca3ad | ||
|
|
5d3353189b | ||
|
|
f92238bf04 | ||
|
|
2b1ceef6a3 | ||
|
|
f4e73eef54 | ||
|
|
d751117219 | ||
|
|
a55075fdb6 | ||
|
|
a7443778b8 | ||
|
|
06f1982acf | ||
|
|
761173bce7 | ||
|
|
3a55b34214 | ||
|
|
95d5fd1789 | ||
|
|
f24bd92e34 | ||
|
|
e4f4d9c1c5 | ||
|
|
0a94c4a7c9 | ||
|
|
64355c9dde | ||
|
|
bd8906f46b | ||
|
|
26d8fa51b0 | ||
|
|
ad91099d5e | ||
|
|
361a3b2929 | ||
|
|
b9ed1fde62 | ||
|
|
a0ade26505 | ||
|
|
575eade84d | ||
|
|
2cf3642493 | ||
|
|
de5b03f854 | ||
|
|
457d28fc55 | ||
|
|
e0bdde89c4 | ||
|
|
68db8e93b7 | ||
|
|
9069d8e3ec | ||
|
|
e146636250 | ||
|
|
c0af2a9eb5 | ||
|
|
ae5648ede1 | ||
|
|
197d6735d2 | ||
|
|
75b52bef6d | ||
|
|
2c32a64bfe |
16
.github/workflows/pull_requests.yml
vendored
16
.github/workflows/pull_requests.yml
vendored
@@ -34,20 +34,20 @@ jobs:
|
||||
if: success()
|
||||
run: npx grunt prod
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Production Image Build
|
||||
if: success()
|
||||
id: build-image
|
||||
uses: redhat-actions/buildah-build@v2
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
# Not being uploaded to any registry, use a simple name to allow Buildah to build correctly.
|
||||
image: cyberchef
|
||||
containerfiles: ./Dockerfile
|
||||
platforms: linux/amd64
|
||||
oci: true
|
||||
# Webpack seems to use a lot of open files, increase the max open file limit to accomodate.
|
||||
extra-args: |
|
||||
--ulimit nofile=10000
|
||||
|
||||
platforms: linux/amd64,linux/arm64
|
||||
- name: UI Tests
|
||||
if: success()
|
||||
run: |
|
||||
|
||||
36
.github/workflows/releases.yml
vendored
36
.github/workflows/releases.yml
vendored
@@ -45,6 +45,12 @@ jobs:
|
||||
sudo apt-get install xvfb
|
||||
xvfb-run --server-args="-screen 0 1200x800x24" npx grunt testui
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
|
||||
- name: Image Metadata
|
||||
id: image-metadata
|
||||
uses: docker/metadata-action@v4
|
||||
@@ -55,30 +61,22 @@ jobs:
|
||||
type=semver,pattern={{major}}.{{minor}}
|
||||
type=semver,pattern={{version}}
|
||||
|
||||
- name: Production Image Build
|
||||
id: build-image
|
||||
uses: redhat-actions/buildah-build@v2
|
||||
- name: Log in to GHCR
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
tags: ${{ steps.image-metadata.outputs.tags }}
|
||||
labels: ${{ steps.image-metadata.outputs.labels }}
|
||||
containerfiles: ./Dockerfile
|
||||
platforms: linux/amd64,linux/arm64
|
||||
oci: true
|
||||
# enable build layer caching between platforms
|
||||
layers: true
|
||||
# Webpack seems to use a lot of open files, increase the max open file limit to accomodate.
|
||||
extra-args: |
|
||||
--ulimit nofile=10000
|
||||
|
||||
- name: Publish to GHCR
|
||||
uses: redhat-actions/push-to-registry@v2
|
||||
with:
|
||||
image: ${{ steps.build-image.outputs.image }}
|
||||
tags: ${{ steps.build-image.outputs.tags }}
|
||||
registry: ${{ env.REGISTRY }}
|
||||
username: ${{ env.REGISTRY_USER }}
|
||||
password: ${{ env.REGISTRY_PASSWORD }}
|
||||
|
||||
- name: Publish to GHCR
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
context: .
|
||||
push: true
|
||||
tags: ${{ steps.image-metadata.outputs.tags }}
|
||||
labels: ${{ steps.image-metadata.outputs.labels }}
|
||||
platforms: linux/amd64,linux/arm64
|
||||
|
||||
- name: Upload Release Assets
|
||||
id: upload-release-assets
|
||||
uses: svenstaro/upload-release-action@v2
|
||||
|
||||
@@ -27,10 +27,6 @@ RUN npm run build
|
||||
#########################################
|
||||
# Package static build files into nginx #
|
||||
#########################################
|
||||
# We are using Github Actions: redhat-actions/buildah-build@v2 which needs manual selection of arch in base image
|
||||
# Remove TARGETARCH if docker buildx is supported in the CI release as --platform=$TARGETPLATFORM will be automatically set
|
||||
ARG TARGETARCH
|
||||
ARG TARGETPLATFORM
|
||||
FROM ${TARGETARCH}/nginx:stable-alpine AS cyberchef
|
||||
FROM nginx:stable-alpine AS cyberchef
|
||||
|
||||
COPY --from=builder /app/build/prod /usr/share/nginx/html/
|
||||
|
||||
69
package-lock.json
generated
69
package-lock.json
generated
@@ -46,6 +46,8 @@
|
||||
"file-saver": "^2.0.5",
|
||||
"flat": "^6.0.1",
|
||||
"geodesy": "1.1.3",
|
||||
"handlebars": "^4.7.8",
|
||||
"hash-wasm": "^4.12.0",
|
||||
"highlight.js": "^11.9.0",
|
||||
"ieee754": "^1.2.1",
|
||||
"jimp": "^0.22.12",
|
||||
@@ -95,6 +97,7 @@
|
||||
"ua-parser-js": "^1.0.38",
|
||||
"unorm": "^1.6.0",
|
||||
"utf8": "^3.0.0",
|
||||
"uuid": "^11.1.0",
|
||||
"vkbeautify": "^0.99.3",
|
||||
"xpath": "0.0.34",
|
||||
"xregexp": "^5.1.1",
|
||||
@@ -10843,6 +10846,27 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/handlebars": {
|
||||
"version": "4.7.8",
|
||||
"resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz",
|
||||
"integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"minimist": "^1.2.5",
|
||||
"neo-async": "^2.6.2",
|
||||
"source-map": "^0.6.1",
|
||||
"wordwrap": "^1.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"handlebars": "bin/handlebars"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.4.7"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"uglify-js": "^3.1.4"
|
||||
}
|
||||
},
|
||||
"node_modules/has-ansi": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
|
||||
@@ -10941,6 +10965,11 @@
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/hash-wasm": {
|
||||
"version": "4.12.0",
|
||||
"resolved": "https://registry.npmjs.org/hash-wasm/-/hash-wasm-4.12.0.tgz",
|
||||
"integrity": "sha512-+/2B2rYLb48I/evdOIhP+K/DD2ca2fgBjp6O+GBEnCDk2e4rpeXIK8GvIyRPjTezgmWn9gmKwkQjjx6BtqDHVQ=="
|
||||
},
|
||||
"node_modules/hash.js": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
|
||||
@@ -13663,7 +13692,6 @@
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz",
|
||||
"integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/netmask": {
|
||||
@@ -13885,6 +13913,15 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/nightwatch/node_modules/uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/nightwatch/node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
@@ -16828,6 +16865,15 @@
|
||||
"node": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sockjs/node_modules/uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/socks": {
|
||||
"version": "2.8.3",
|
||||
"resolved": "https://registry.npmjs.org/socks/-/socks-2.8.3.tgz",
|
||||
@@ -16868,7 +16914,6 @@
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
|
||||
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
|
||||
"devOptional": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
@@ -18115,13 +18160,15 @@
|
||||
}
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"version": "11.1.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.0.tgz",
|
||||
"integrity": "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==",
|
||||
"funding": [
|
||||
"https://github.com/sponsors/broofa",
|
||||
"https://github.com/sponsors/ctavan"
|
||||
],
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
"uuid": "dist/esm/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/v8flags": {
|
||||
@@ -18886,6 +18933,12 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/wordwrap": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
|
||||
"integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/worker-loader": {
|
||||
"version": "3.0.8",
|
||||
"resolved": "https://registry.npmjs.org/worker-loader/-/worker-loader-3.0.8.tgz",
|
||||
|
||||
@@ -132,6 +132,8 @@
|
||||
"file-saver": "^2.0.5",
|
||||
"flat": "^6.0.1",
|
||||
"geodesy": "1.1.3",
|
||||
"handlebars": "^4.7.8",
|
||||
"hash-wasm": "^4.12.0",
|
||||
"highlight.js": "^11.9.0",
|
||||
"ieee754": "^1.2.1",
|
||||
"jimp": "^0.22.12",
|
||||
@@ -181,6 +183,7 @@
|
||||
"ua-parser-js": "^1.0.38",
|
||||
"unorm": "^1.6.0",
|
||||
"utf8": "^3.0.0",
|
||||
"uuid": "^11.1.0",
|
||||
"vkbeautify": "^0.99.3",
|
||||
"xpath": "0.0.34",
|
||||
"xregexp": "^5.1.1",
|
||||
|
||||
@@ -375,7 +375,8 @@
|
||||
"Extract EXIF",
|
||||
"Extract ID3",
|
||||
"Extract Files",
|
||||
"RAKE"
|
||||
"RAKE",
|
||||
"Template"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -425,6 +426,7 @@
|
||||
"Snefru",
|
||||
"BLAKE2b",
|
||||
"BLAKE2s",
|
||||
"BLAKE3",
|
||||
"GOST Hash",
|
||||
"Streebog",
|
||||
"SSDEEP",
|
||||
@@ -549,6 +551,7 @@
|
||||
"Pseudo-Random Number Generator",
|
||||
"Generate De Bruijn Sequence",
|
||||
"Generate UUID",
|
||||
"Analyse UUID",
|
||||
"Generate TOTP",
|
||||
"Generate HOTP",
|
||||
"Generate QR Code",
|
||||
|
||||
48
src/core/operations/AnalyseUUID.mjs
Normal file
48
src/core/operations/AnalyseUUID.mjs
Normal file
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2023
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import * as uuid from "uuid";
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
/**
|
||||
* Analyse UUID operation
|
||||
*/
|
||||
class AnalyseUUID extends Operation {
|
||||
|
||||
/**
|
||||
* AnalyseUUID constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Analyse UUID";
|
||||
this.module = "Crypto";
|
||||
this.description = "Tries to determine information about a given UUID and suggests which version may have been used to generate it";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Universally_unique_identifier";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
try {
|
||||
const uuidVersion = uuid.version(input);
|
||||
return "UUID version: " + uuidVersion;
|
||||
} catch (error) {
|
||||
throw new OperationError("Invalid UUID");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default AnalyseUUID;
|
||||
58
src/core/operations/BLAKE3.mjs
Normal file
58
src/core/operations/BLAKE3.mjs
Normal file
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* @author xumptex [xumptex@outlook.fr]
|
||||
* @copyright Crown Copyright 2025
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import { blake3 } from "hash-wasm";
|
||||
/**
|
||||
* BLAKE3 operation
|
||||
*/
|
||||
class BLAKE3 extends Operation {
|
||||
|
||||
/**
|
||||
* BLAKE3 constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "BLAKE3";
|
||||
this.module = "Hashing";
|
||||
this.description = "Hashes the input using BLAKE3 (UTF-8 encoded), with an optional key (also UTF-8), and outputs the result in hexadecimal format.";
|
||||
this.infoURL = "https://en.wikipedia.org/wiki/BLAKE_(hash_function)#BLAKE3";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Size (bytes)",
|
||||
"type": "number"
|
||||
}, {
|
||||
"name": "Key",
|
||||
"type": "string",
|
||||
"value": ""
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const key = args[1];
|
||||
const size = args[0];
|
||||
// Check if the user want a key hash or not
|
||||
if (key === "") {
|
||||
return blake3(input, size*8);
|
||||
} if (key.length !== 32) {
|
||||
throw new OperationError("The key must be exactly 32 bytes long");
|
||||
}
|
||||
return blake3(input, size*8, key);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default BLAKE3;
|
||||
@@ -51,7 +51,7 @@ class ExtractEmailAddresses extends Operation {
|
||||
run(input, args) {
|
||||
const [displayTotal, sort, unique] = args,
|
||||
// email regex from: https://www.regextester.com/98066
|
||||
regex = /(?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9](?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9-]*[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9])?\.)+[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9](?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9-]*[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}\])/ig;
|
||||
regex = /(?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9](?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9-]*[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9])?\.)+[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9](?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9-]*[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\])/ig;
|
||||
|
||||
const results = search(
|
||||
input,
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import crypto from "crypto";
|
||||
|
||||
import * as uuid from "uuid";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
/**
|
||||
* Generate UUID operation
|
||||
*/
|
||||
@@ -20,11 +20,38 @@ class GenerateUUID extends Operation {
|
||||
|
||||
this.name = "Generate UUID";
|
||||
this.module = "Crypto";
|
||||
this.description = "Generates an RFC 4122 version 4 compliant Universally Unique Identifier (UUID), also known as a Globally Unique Identifier (GUID).<br><br>A version 4 UUID relies on random numbers, in this case generated using <code>window.crypto</code> if available and falling back to <code>Math.random</code> if not.";
|
||||
this.description =
|
||||
"Generates an RFC 9562 (formerly RFC 4122) compliant Universally Unique Identifier (UUID), " +
|
||||
"also known as a Globally Unique Identifier (GUID).<br>" +
|
||||
"<br>" +
|
||||
"We currently support generating the following UUID versions:<br>" +
|
||||
"<ul>" +
|
||||
"<li><strong>v1</strong>: Timestamp-based</li>" +
|
||||
"<li><strong>v3</strong>: Namespace w/ MD5</li>" +
|
||||
"<li><strong>v4</strong>: Random (default)</li>" +
|
||||
"<li><strong>v5</strong>: Namespace w/ SHA-1</li>" +
|
||||
"<li><strong>v6</strong>: Timestamp, reordered</li>" +
|
||||
"<li><strong>v7</strong>: Unix Epoch time-based</li>" +
|
||||
"</ul>" +
|
||||
"UUIDs are generated using the <a href='https://npmjs.org/uuid/'><code>uuid</code><a> package.<br>";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Universally_unique_identifier";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
this.args = [
|
||||
{
|
||||
name: "Version",
|
||||
hint: "UUID version",
|
||||
type: "option",
|
||||
value: ["v1", "v3", "v4", "v5", "v6", "v7"],
|
||||
defaultIndex: 2,
|
||||
},
|
||||
{
|
||||
name: "Namespace",
|
||||
hint: "UUID namespace (UUID; valid for v3 and v5)",
|
||||
type: "string",
|
||||
value: "1b671a64-40d5-491e-99b0-da01ff1f3341"
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -33,16 +60,17 @@ class GenerateUUID extends Operation {
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const buf = new Uint32Array(4).map(() => {
|
||||
return crypto.randomBytes(4).readUInt32BE(0, true);
|
||||
});
|
||||
let i = 0;
|
||||
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
|
||||
const r = (buf[i >> 3] >> ((i % 8) * 4)) & 0xf,
|
||||
v = c === "x" ? r : (r & 0x3 | 0x8);
|
||||
i++;
|
||||
return v.toString(16);
|
||||
});
|
||||
const [version, namespace] = args;
|
||||
const hasDesiredVersion = typeof uuid[version] === "function";
|
||||
if (!hasDesiredVersion) throw new OperationError("Invalid UUID version");
|
||||
|
||||
const requiresNamespace = ["v3", "v5"].includes(version);
|
||||
if (!requiresNamespace) return uuid[version]();
|
||||
|
||||
const hasValidNamespace = typeof namespace === "string" && uuid.validate(namespace);
|
||||
if (!hasValidNamespace) throw new OperationError("Invalid UUID namespace");
|
||||
|
||||
return uuid[version](input, namespace);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ class RailFenceCipherDecode extends Operation {
|
||||
}
|
||||
}
|
||||
|
||||
return plaintext.join("").trim();
|
||||
return plaintext.join("");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -66,7 +66,7 @@ class RailFenceCipherEncode extends Operation {
|
||||
rows[rowIdx] += plaintext[pos];
|
||||
}
|
||||
|
||||
return rows.join("").trim();
|
||||
return rows.join("");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
53
src/core/operations/Template.mjs
Normal file
53
src/core/operations/Template.mjs
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* @author kendallgoto [k@kgo.to]
|
||||
* @copyright Crown Copyright 2025
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import Handlebars from "handlebars";
|
||||
|
||||
/**
|
||||
* Template operation
|
||||
*/
|
||||
class Template extends Operation {
|
||||
|
||||
/**
|
||||
* Template constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Template";
|
||||
this.module = "Handlebars";
|
||||
this.description = "Render a template with Handlebars/Mustache substituting variables using JSON input. Templates will be rendered to plain-text only, to prevent XSS.";
|
||||
this.infoURL = "https://handlebarsjs.com/";
|
||||
this.inputType = "JSON";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "Template definition (.handlebars)",
|
||||
type: "text",
|
||||
value: ""
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {JSON} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [templateStr] = args;
|
||||
try {
|
||||
const template = Handlebars.compile(templateStr);
|
||||
return template(input);
|
||||
} catch (e) {
|
||||
throw new OperationError(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default Template;
|
||||
@@ -23,7 +23,13 @@ class URLDecode extends Operation {
|
||||
this.infoURL = "https://wikipedia.org/wiki/Percent-encoding";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
this.args = [
|
||||
{
|
||||
"name": "Treat \"+\" as space",
|
||||
"type": "boolean",
|
||||
"value": true
|
||||
},
|
||||
];
|
||||
this.checks = [
|
||||
{
|
||||
pattern: ".*(?:%[\\da-f]{2}.*){4}",
|
||||
@@ -39,7 +45,8 @@ class URLDecode extends Operation {
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const data = input.replace(/\+/g, "%20");
|
||||
const plusIsSpace = args[0];
|
||||
const data = plusIsSpace ? input.replace(/\+/g, "%20") : input;
|
||||
try {
|
||||
return decodeURIComponent(data);
|
||||
} catch (err) {
|
||||
|
||||
@@ -74,11 +74,11 @@ function transformArgs(opArgsList, newArgs) {
|
||||
return opArgs.map((arg) => {
|
||||
if (arg.type === "option") {
|
||||
// pick default option if not already chosen
|
||||
return typeof arg.value === "string" ? arg.value : arg.value[0];
|
||||
return typeof arg.value === "string" ? arg.value : arg.value[arg.defaultIndex ?? 0];
|
||||
}
|
||||
|
||||
if (arg.type === "editableOption") {
|
||||
return typeof arg.value === "string" ? arg.value : arg.value[0].value;
|
||||
return typeof arg.value === "string" ? arg.value : arg.value[arg.defaultIndex ?? 0].value;
|
||||
}
|
||||
|
||||
if (arg.type === "toggleString") {
|
||||
|
||||
@@ -1,23 +1,26 @@
|
||||
[
|
||||
{
|
||||
"@context": "http://schema.org",
|
||||
"@type": "Organization",
|
||||
"url": "https://gchq.github.io/CyberChef/",
|
||||
"logo": "https://gchq.github.io/CyberChef/images/cyberchef-128x128.png",
|
||||
"sameAs": [
|
||||
"https://github.com/gchq/CyberChef",
|
||||
"https://www.npmjs.com/package/cyberchef"
|
||||
"@graph": [
|
||||
{
|
||||
"@type": "Organization",
|
||||
"url": "https://gchq.github.io/CyberChef/",
|
||||
"logo": "https://gchq.github.io/CyberChef/images/cyberchef-128x128.png",
|
||||
"sameAs": [
|
||||
"https://github.com/gchq/CyberChef",
|
||||
"https://www.npmjs.com/package/cyberchef"
|
||||
]
|
||||
},
|
||||
{
|
||||
"@type": "WebSite",
|
||||
"url": "https://gchq.github.io/CyberChef/",
|
||||
"name": "CyberChef",
|
||||
"potentialAction": {
|
||||
"@type": "SearchAction",
|
||||
"target": "https://gchq.github.io/CyberChef/?op={operation_search_term}",
|
||||
"query-input": "required name=operation_search_term"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"@context": "http://schema.org",
|
||||
"@type": "WebSite",
|
||||
"url": "https://gchq.github.io/CyberChef/",
|
||||
"name": "CyberChef",
|
||||
"potentialAction": {
|
||||
"@type": "SearchAction",
|
||||
"target": "https://gchq.github.io/CyberChef/?op={operation_search_term}",
|
||||
"query-input": "required name=operation_search_term"
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
@@ -580,10 +580,25 @@ Password: 282760`;
|
||||
assert.strictEqual(result.toString().substr(0, 37), "-----BEGIN PGP PRIVATE KEY BLOCK-----");
|
||||
}),
|
||||
|
||||
it("Generate UUID", () => {
|
||||
const result = chef.generateUUID();
|
||||
assert.ok(result.toString());
|
||||
assert.strictEqual(result.toString().length, 36);
|
||||
...[1, 3, 4, 5, 6, 7].map(version => it(`Generate UUID v${version}`, () => {
|
||||
const result = chef.generateUUID("", { "version": `v${version}` }).toString();
|
||||
assert.ok(result);
|
||||
assert.strictEqual(result.length, 36);
|
||||
})),
|
||||
|
||||
...[1, 3, 4, 5, 6, 7].map(version => it(`Analyze UUID v${version}`, () => {
|
||||
const uuid = chef.generateUUID("", { "version": `v${version}` }).toString();
|
||||
const result = chef.analyseUUID(uuid).toString();
|
||||
const expected = `UUID version: ${version}`;
|
||||
assert.strictEqual(result, expected);
|
||||
})),
|
||||
|
||||
it("Generate UUID using defaults", () => {
|
||||
const uuid = chef.generateUUID();
|
||||
assert.ok(uuid);
|
||||
|
||||
const analysis = chef.analyseUUID(uuid).toString();
|
||||
assert.strictEqual(analysis, "UUID version: 4");
|
||||
}),
|
||||
|
||||
it("Gzip, Gunzip", () => {
|
||||
|
||||
@@ -29,6 +29,7 @@ import "./tests/BCD.mjs";
|
||||
import "./tests/BitwiseOp.mjs";
|
||||
import "./tests/BLAKE2b.mjs";
|
||||
import "./tests/BLAKE2s.mjs";
|
||||
import "./tests/BLAKE3.mjs";
|
||||
import "./tests/Bombe.mjs";
|
||||
import "./tests/BSON.mjs";
|
||||
import "./tests/ByteRepr.mjs";
|
||||
@@ -158,12 +159,14 @@ import "./tests/Subsection.mjs";
|
||||
import "./tests/SwapCase.mjs";
|
||||
import "./tests/SymmetricDifference.mjs";
|
||||
import "./tests/TakeNthBytes.mjs";
|
||||
import "./tests/Template.mjs";
|
||||
import "./tests/TextEncodingBruteForce.mjs";
|
||||
import "./tests/ToFromInsensitiveRegex.mjs";
|
||||
import "./tests/TranslateDateTimeFormat.mjs";
|
||||
import "./tests/Typex.mjs";
|
||||
import "./tests/UnescapeString.mjs";
|
||||
import "./tests/Unicode.mjs";
|
||||
import "./tests/URLEncodeDecode.mjs";
|
||||
import "./tests/RSA.mjs";
|
||||
import "./tests/CBOREncode.mjs";
|
||||
import "./tests/CBORDecode.mjs";
|
||||
|
||||
55
tests/operations/tests/BLAKE3.mjs
Normal file
55
tests/operations/tests/BLAKE3.mjs
Normal file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* BLAKE3 tests.
|
||||
* @author xumptex [xumptex@outlook.fr]
|
||||
* @copyright Crown Copyright 2025
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "BLAKE3: 8 - Hello world",
|
||||
input: "Hello world",
|
||||
expectedOutput: "e7e6fb7d2869d109",
|
||||
recipeConfig: [
|
||||
{ "op": "BLAKE3",
|
||||
"args": [8, ""] }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "BLAKE3: 16 - Hello world 2",
|
||||
input: "Hello world 2",
|
||||
expectedOutput: "2a3df5fe5f0d3fcdd995fc203c7f7c52",
|
||||
recipeConfig: [
|
||||
{ "op": "BLAKE3",
|
||||
"args": [16, ""] }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "BLAKE3: 32 - Hello world",
|
||||
input: "Hello world",
|
||||
expectedOutput: "e7e6fb7d2869d109b62cdb1227208d4016cdaa0af6603d95223c6a698137d945",
|
||||
recipeConfig: [
|
||||
{ "op": "BLAKE3",
|
||||
"args": [32, ""] }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "BLAKE3: Key Test",
|
||||
input: "Hello world",
|
||||
expectedOutput: "59dd23ac9d025690",
|
||||
recipeConfig: [
|
||||
{ "op": "BLAKE3",
|
||||
"args": [8, "ThiskeyisexactlythirtytwoBytesLo"] }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "BLAKE3: Key Test 2",
|
||||
input: "Hello world",
|
||||
expectedOutput: "c8302c9634c1da42",
|
||||
recipeConfig: [
|
||||
{ "op": "BLAKE3",
|
||||
"args": [8, "ThiskeyisexactlythirtytwoByteslo"] }
|
||||
]
|
||||
}
|
||||
]);
|
||||
@@ -528,4 +528,15 @@ TestRegister.addTests([
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Rail Fence Cipher Encode: Normal with Offset with Spaces",
|
||||
input: "No one expects the spanish Inquisition.",
|
||||
expectedOutput: " e n ut.ooeepcstesaihIqiiinNnxthpsnso",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Rail Fence Cipher Encode",
|
||||
"args": [3, 2]
|
||||
}
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -129,38 +129,5 @@ TestRegister.addTests([
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "ExtractIPAddress IPv6 full form",
|
||||
input: "This 2001:0db8:0001:0000:0000:0ab9:C0A8:0102 is a valid address.",
|
||||
expectedOutput: "2001:0db8:0001:0000:0000:0ab9:C0A8:0102",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Extract IP addresses",
|
||||
"args": [true, true, false, false, false, false]
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "ExtractIPAddress IPv6 short form",
|
||||
input: "Another valid style is the short form 2001:db8:1::ab9:C0A8:102 is a valid address.",
|
||||
expectedOutput: "2001:db8:1::ab9:C0A8:102",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Extract IP addresses",
|
||||
"args": [true, true, false, false, false, false]
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "ExtractIPAddress IPv6 both forms",
|
||||
input: "2001:0db8:0001:0000:0000:0ab9:C0A8:0102 can be compressed as follows: 2001:db8:1::ab9:C0A8:102.",
|
||||
expectedOutput: "2001:0db8:0001:0000:0000:0ab9:C0A8:0102\n2001:db8:1::ab9:C0A8:102",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Extract IP addresses",
|
||||
"args": [true, true, false, false, false, false]
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
|
||||
53
tests/operations/tests/Template.mjs
Normal file
53
tests/operations/tests/Template.mjs
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* @author kendallgoto [k@kgo.to]
|
||||
* @copyright Crown Copyright 2025
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
TestRegister.addTests([
|
||||
{
|
||||
"name": "Template: Simple Print",
|
||||
"input": "{}",
|
||||
"expectedOutput": "Hello, world!",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "Template",
|
||||
"args": ["Hello, world!"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Template: Print Basic Variables",
|
||||
"input": "{\"one\": 1, \"two\": 2}",
|
||||
"expectedOutput": "1 2",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "Template",
|
||||
"args": ["{{ one }} {{ two }}"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Template: Partials",
|
||||
"input": "{\"users\":[{\"name\":\"Someone\",\"age\":25},{\"name\":\"Someone Else\",\"age\":32}]}",
|
||||
"expectedOutput": "Name: Someone\nAge: 25\n\nName: Someone Else\nAge: 32\n\n",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "Template",
|
||||
"args": ["{{#*inline \"user\"}}\nName: {{ name }}\nAge: {{ age }}\n{{/inline}}\n{{#each users}}\n{{> user}}\n\n{{/each}}"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Template: Disallow XSS",
|
||||
"input": "{\"test\": \"<script></script>\"}",
|
||||
"expectedOutput": "<script></script><script></script>",
|
||||
"recipeConfig": [
|
||||
{
|
||||
"op": "Template",
|
||||
"args": ["<script></script>{{ test }}"]
|
||||
}
|
||||
]
|
||||
}
|
||||
]);
|
||||
92
tests/operations/tests/URLEncodeDecode.mjs
Normal file
92
tests/operations/tests/URLEncodeDecode.mjs
Normal file
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* URLEncode and URLDecode tests.
|
||||
*
|
||||
* @author es45411 [135977478+es45411@users.noreply.github.com]
|
||||
*
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
TestRegister.addTests([
|
||||
// URL Decode
|
||||
{
|
||||
name: "URLDecode: nothing",
|
||||
input: "",
|
||||
expectedOutput: "",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "URL Decode",
|
||||
args: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "URLDecode: spaces without special chars",
|
||||
input: "Hello%20world%21",
|
||||
expectedOutput: "Hello world!",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "URL Decode",
|
||||
args: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "URLDecode: spaces with special chars",
|
||||
input: "Hello%20world!",
|
||||
expectedOutput: "Hello world!",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "URL Decode",
|
||||
args: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "URLDecode: decode plus as space",
|
||||
input: "Hello%20world!",
|
||||
expectedOutput: "Hello world!",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "URL Decode",
|
||||
args: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
// URL Encode
|
||||
{
|
||||
name: "URLEncode: nothing",
|
||||
input: "",
|
||||
expectedOutput: "",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "URL Encode",
|
||||
args: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "URLEncode: spaces without special chars",
|
||||
input: "Hello world!",
|
||||
expectedOutput: "Hello%20world!",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "URL Encode",
|
||||
args: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "URLEncode: spaces with special chars",
|
||||
input: "Hello world!",
|
||||
expectedOutput: "Hello%20world%21",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "URL Encode",
|
||||
args: [true],
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
Reference in New Issue
Block a user