mirror of
https://github.com/gchq/CyberChef
synced 2026-01-06 18:43:23 +00:00
Compare commits
46 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
40b58aa144 | ||
|
|
d5bcdc8eed | ||
|
|
28ec56a27f | ||
|
|
8f710461da | ||
|
|
c2cf535f88 | ||
|
|
ced9ab68fa | ||
|
|
cdb197a9c3 | ||
|
|
c8eacb9942 | ||
|
|
1c8e37cb64 | ||
|
|
1b0ced9f9b | ||
|
|
7b245b084a | ||
|
|
b00f64518f | ||
|
|
c3434e894d | ||
|
|
dd66f728b3 | ||
|
|
e40142b8c5 | ||
|
|
1dd1b839b8 | ||
|
|
d90d845f27 | ||
|
|
8c9ad81039 | ||
|
|
cef7a7b27d | ||
|
|
3e715ef21a | ||
|
|
86b43b4ffa | ||
|
|
65d883496b | ||
|
|
69e59916e2 | ||
|
|
475282984b | ||
|
|
2f89130f41 | ||
|
|
e9dd7eceb8 | ||
|
|
037590f831 | ||
|
|
85496684d8 | ||
|
|
4200ed4eb9 | ||
|
|
6b16f11d3b | ||
|
|
683bd3e5db | ||
|
|
6a10e94bfd | ||
|
|
25086386c6 | ||
|
|
d99ee32cc4 | ||
|
|
f1d318f229 | ||
|
|
a7fc455e05 | ||
|
|
c02c4a72e4 | ||
|
|
f97ce18ff9 | ||
|
|
dfd9afc2c4 | ||
|
|
eb5663a1ed | ||
|
|
418a7962a5 | ||
|
|
2ffce23c67 | ||
|
|
e712af33b7 | ||
|
|
578a61d331 | ||
|
|
671ae6558f | ||
|
|
e8f91316ff |
2
.github/workflows/master.yml
vendored
2
.github/workflows/master.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
- name: Set node version
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: '17.x'
|
||||
node-version: '18.x'
|
||||
|
||||
- name: Install
|
||||
run: |
|
||||
|
||||
2
.github/workflows/pull_requests.yml
vendored
2
.github/workflows/pull_requests.yml
vendored
@@ -14,7 +14,7 @@ jobs:
|
||||
- name: Set node version
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: '17.x'
|
||||
node-version: '18.x'
|
||||
|
||||
- name: Install
|
||||
run: |
|
||||
|
||||
2
.github/workflows/releases.yml
vendored
2
.github/workflows/releases.yml
vendored
@@ -15,7 +15,7 @@ jobs:
|
||||
- name: Set node version
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: '17.x'
|
||||
node-version: '18.x'
|
||||
|
||||
- name: Install
|
||||
run: |
|
||||
|
||||
30
CHANGELOG.md
30
CHANGELOG.md
@@ -13,6 +13,21 @@ All major and minor version changes will be documented in this file. Details of
|
||||
|
||||
## Details
|
||||
|
||||
### [9.46.0] - 2022-07-08
|
||||
- Added 'Cetacean Cipher Encode' and 'Cetacean Cipher Decode' operations [@valdelaseras] | [#1308]
|
||||
|
||||
### [9.45.0] - 2022-07-08
|
||||
- Added 'ROT8000' operation [@thomasleplus] | [#1250]
|
||||
|
||||
### [9.44.0] - 2022-07-08
|
||||
- Added 'LZString Compress' and 'LZString Decompress' operations [@crespyl] | [#1266]
|
||||
|
||||
### [9.43.0] - 2022-07-08
|
||||
- Added 'ROT13 Brute Force' and 'ROT47 Brute Force' operations [@mikecat] | [#1264]
|
||||
|
||||
### [9.42.0] - 2022-07-08
|
||||
- Added 'LS47 Encrypt' and 'LS47 Decrypt' operations [@n1073645] | [#951]
|
||||
|
||||
### [9.41.0] - 2022-07-08
|
||||
- Added 'Caesar Box Cipher' operation [@n1073645] | [#1066]
|
||||
|
||||
@@ -300,6 +315,11 @@ All major and minor version changes will be documented in this file. Details of
|
||||
|
||||
|
||||
|
||||
[9.46.0]: https://github.com/gchq/CyberChef/releases/tag/v9.46.0
|
||||
[9.45.0]: https://github.com/gchq/CyberChef/releases/tag/v9.45.0
|
||||
[9.44.0]: https://github.com/gchq/CyberChef/releases/tag/v9.44.0
|
||||
[9.43.0]: https://github.com/gchq/CyberChef/releases/tag/v9.43.0
|
||||
[9.42.0]: https://github.com/gchq/CyberChef/releases/tag/v9.42.0
|
||||
[9.41.0]: https://github.com/gchq/CyberChef/releases/tag/v9.41.0
|
||||
[9.40.0]: https://github.com/gchq/CyberChef/releases/tag/v9.40.0
|
||||
[9.39.0]: https://github.com/gchq/CyberChef/releases/tag/v9.39.0
|
||||
@@ -426,6 +446,10 @@ All major and minor version changes will be documented in this file. Details of
|
||||
[@t-8ch]: https://github.com/t-8ch
|
||||
[@hettysymes]: https://github.com/hettysymes
|
||||
[@swesven]: https://github.com/swesven
|
||||
[@mikecat]: https://github.com/mikecat
|
||||
[@crespyl]: https://github.com/crespyl
|
||||
[@thomasleplus]: https://github.com/thomasleplus
|
||||
[@valdelaseras]: https://github.com/valdelaseras
|
||||
|
||||
[8ad18b]: https://github.com/gchq/CyberChef/commit/8ad18bc7db6d9ff184ba3518686293a7685bf7b7
|
||||
[9a33498]: https://github.com/gchq/CyberChef/commit/9a33498fed26a8df9c9f35f39a78a174bf50a513
|
||||
@@ -504,6 +528,7 @@ All major and minor version changes will be documented in this file. Details of
|
||||
[#917]: https://github.com/gchq/CyberChef/pull/917
|
||||
[#934]: https://github.com/gchq/CyberChef/pull/934
|
||||
[#948]: https://github.com/gchq/CyberChef/pull/948
|
||||
[#951]: https://github.com/gchq/CyberChef/pull/951
|
||||
[#952]: https://github.com/gchq/CyberChef/pull/952
|
||||
[#965]: https://github.com/gchq/CyberChef/pull/965
|
||||
[#966]: https://github.com/gchq/CyberChef/pull/966
|
||||
@@ -523,3 +548,8 @@ All major and minor version changes will be documented in this file. Details of
|
||||
[#1313]: https://github.com/gchq/CyberChef/pull/1313
|
||||
[#1326]: https://github.com/gchq/CyberChef/pull/1326
|
||||
[#1364]: https://github.com/gchq/CyberChef/pull/1364
|
||||
[#1264]: https://github.com/gchq/CyberChef/pull/1264
|
||||
[#1266]: https://github.com/gchq/CyberChef/pull/1266
|
||||
[#1250]: https://github.com/gchq/CyberChef/pull/1250
|
||||
[#1308]: https://github.com/gchq/CyberChef/pull/1308
|
||||
|
||||
|
||||
12
README.md
12
README.md
@@ -54,7 +54,7 @@ You can use as many operations as you like in simple or complex ways. Some examp
|
||||
- Whenever you modify the input or the recipe, CyberChef will automatically "bake" for you and produce the output immediately.
|
||||
- This can be turned off and operated manually if it is affecting performance (if the input is very large, for instance).
|
||||
- Automated encoding detection
|
||||
- CyberChef uses [a number of techniques](https://github.com/gchq/CyberChef/wiki/Automatic-detection-of-encoded-data-using-CyberChef-Magic) to attempt to automatically detect which encodings your data is under. If it finds a suitable operation which can make sense of your data, it displays the 'magic' icon in the Output field which you can click to decode your data.
|
||||
- CyberChef uses [a number of techniques](https://github.com/gchq/CyberChef/wiki/Automatic-detection-of-encoded-data-using-CyberChef-Magic) to attempt to automatically detect which encodings your data is under. If it finds a suitable operation that make sense of your data, it displays the 'magic' icon in the Output field which you can click to decode your data.
|
||||
- Breakpoints
|
||||
- You can set breakpoints on any operation in your recipe to pause execution before running it.
|
||||
- You can also step through the recipe one operation at a time to see what the data looks like at each stage.
|
||||
@@ -66,7 +66,7 @@ You can use as many operations as you like in simple or complex ways. Some examp
|
||||
- Highlighting
|
||||
- When you highlight text in the input or output, the offset and length values will be displayed and, if possible, the corresponding data will be highlighted in the output or input respectively (example: [highlight the word 'question' in the input to see where it appears in the output][11]).
|
||||
- Save to file and load from file
|
||||
- You can save the output to a file at any time or load a file by dragging and dropping it into the input field. Files up to around 2GB are supported (depending on your browser), however some operations may take a very long time to run over this much data.
|
||||
- You can save the output to a file at any time or load a file by dragging and dropping it into the input field. Files up to around 2GB are supported (depending on your browser), however, some operations may take a very long time to run over this much data.
|
||||
- CyberChef is entirely client-side
|
||||
- It should be noted that none of your recipe configuration or input (either text or files) is ever sent to the CyberChef web server - all processing is carried out within your browser, on your own computer.
|
||||
- Due to this feature, CyberChef can be downloaded and run locally. You can use the link in the top left corner of the app to download a full copy of CyberChef and drop it into a virtual machine, share it with other people, or host it in a closed network.
|
||||
@@ -74,10 +74,10 @@ You can use as many operations as you like in simple or complex ways. Some examp
|
||||
|
||||
## Deep linking
|
||||
|
||||
By manipulation of CyberChef's URL hash, you can change the initial settings with which the page opens.
|
||||
By manipulating CyberChef's URL hash, you can change the initial settings with which the page opens.
|
||||
The format is `https://gchq.github.io/CyberChef/#recipe=Operation()&input=...`
|
||||
|
||||
Supported arguments are `recipe`, `input` (encoded in Base64), and `theme`.
|
||||
Supported arguments are `recipe`, `input` (encoded in Base64), and `theme`.
|
||||
|
||||
|
||||
## Browser support
|
||||
@@ -90,12 +90,12 @@ CyberChef is built to support
|
||||
|
||||
## Node.js support
|
||||
|
||||
CyberChef is built to fully support Node.js `v10` and partially supports `v12`. Named imports using a deep import specifier does not work in `v12`. For more information, see the Node API page in the project [wiki pages](https://github.com/gchq/CyberChef/wiki)
|
||||
CyberChef is built to fully support Node.js `v16`. For more information, see the Node API page in the project [wiki pages](https://github.com/gchq/CyberChef/wiki)
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributing a new operation to CyberChef is super easy! There is a quickstart script which will walk you through the process. If you can write basic JavaScript, you can write a CyberChef operation.
|
||||
Contributing a new operation to CyberChef is super easy! The quickstart script will walk you through the process. If you can write basic JavaScript, you can write a CyberChef operation.
|
||||
|
||||
An installation walkthrough, how-to guides for adding new operations and themes, descriptions of the repository structure, available data types and coding conventions can all be found in the project [wiki pages](https://github.com/gchq/CyberChef/wiki).
|
||||
|
||||
|
||||
3566
package-lock.json
generated
3566
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
14
package.json
14
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cyberchef",
|
||||
"version": "9.42.0",
|
||||
"version": "9.46.6",
|
||||
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
|
||||
"author": "n1474335 <n1474335@gmail.com>",
|
||||
"homepage": "https://gchq.github.io/CyberChef",
|
||||
@@ -49,7 +49,7 @@
|
||||
"babel-loader": "^8.2.5",
|
||||
"babel-plugin-dynamic-import-node": "^2.3.3",
|
||||
"babel-plugin-transform-builtin-extend": "1.1.2",
|
||||
"chromedriver": "^101.0.0",
|
||||
"chromedriver": "^103.0.0",
|
||||
"cli-progress": "^3.11.1",
|
||||
"colors": "^1.4.0",
|
||||
"copy-webpack-plugin": "^11.0.0",
|
||||
@@ -77,7 +77,6 @@
|
||||
"postcss-import": "^14.1.0",
|
||||
"postcss-loader": "^7.0.0",
|
||||
"prompt": "^1.3.0",
|
||||
"sass-loader": "^13.0.0",
|
||||
"sitemap": "^7.1.1",
|
||||
"terser": "^5.14.0",
|
||||
"webpack": "^5.73.0",
|
||||
@@ -123,23 +122,23 @@
|
||||
"js-sha3": "^0.8.0",
|
||||
"jsesc": "^3.0.2",
|
||||
"json5": "^2.2.1",
|
||||
"jsonpath": "^1.1.1",
|
||||
"jsonpath-plus": "^7.2.0",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"jsqr": "^1.4.0",
|
||||
"jsrsasign": "^10.5.23",
|
||||
"kbpgp": "2.1.15",
|
||||
"libbzip2-wasm": "0.0.4",
|
||||
"libyara-wasm": "^1.1.0",
|
||||
"libyara-wasm": "^1.2.1",
|
||||
"lodash": "^4.17.21",
|
||||
"loglevel": "^1.8.0",
|
||||
"loglevel-message-prefix": "^3.0.0",
|
||||
"lz-string": "^1.4.4",
|
||||
"markdown-it": "^13.0.1",
|
||||
"moment": "^2.29.3",
|
||||
"moment-timezone": "^0.5.34",
|
||||
"ngeohash": "^0.6.3",
|
||||
"node-forge": "^1.3.1",
|
||||
"node-md6": "^0.1.0",
|
||||
"node-sass": "^7.0.1",
|
||||
"nodom": "^2.4.0",
|
||||
"notepack.io": "^3.0.1",
|
||||
"nwmatcher": "^1.4.4",
|
||||
@@ -155,7 +154,7 @@
|
||||
"split.js": "^1.6.5",
|
||||
"ssdeep.js": "0.0.3",
|
||||
"stream-browserify": "^3.0.0",
|
||||
"tesseract.js": "2.1.5",
|
||||
"tesseract.js": "3.0.2",
|
||||
"ua-parser-js": "^1.0.2",
|
||||
"unorm": "^1.6.0",
|
||||
"utf8": "^3.0.0",
|
||||
@@ -168,6 +167,7 @@
|
||||
"scripts": {
|
||||
"start": "npx grunt dev",
|
||||
"build": "npx grunt prod",
|
||||
"node": "npx grunt node",
|
||||
"repl": "node --experimental-modules --experimental-json-modules --experimental-specifier-resolution=node --no-warnings src/node/repl.mjs",
|
||||
"test": "npx grunt configTests && node --experimental-modules --experimental-json-modules --no-warnings --no-deprecation tests/node/index.mjs && node --experimental-modules --experimental-json-modules --no-warnings --no-deprecation tests/operations/index.mjs",
|
||||
"testnodeconsumer": "npx grunt testnodeconsumer",
|
||||
|
||||
@@ -88,7 +88,10 @@
|
||||
"SM4 Encrypt",
|
||||
"SM4 Decrypt",
|
||||
"ROT13",
|
||||
"ROT13 Brute Force",
|
||||
"ROT47",
|
||||
"ROT47 Brute Force",
|
||||
"ROT8000",
|
||||
"XOR",
|
||||
"XOR Brute Force",
|
||||
"Vigenère Encode",
|
||||
@@ -109,6 +112,8 @@
|
||||
"Atbash Cipher",
|
||||
"CipherSaber2 Encrypt",
|
||||
"CipherSaber2 Decrypt",
|
||||
"Cetacean Cipher Encode",
|
||||
"Cetacean Cipher Decode",
|
||||
"Substitute",
|
||||
"Derive PBKDF2 key",
|
||||
"Derive EVP key",
|
||||
@@ -179,7 +184,8 @@
|
||||
"Bit shift right",
|
||||
"Rotate left",
|
||||
"Rotate right",
|
||||
"ROT13"
|
||||
"ROT13",
|
||||
"ROT8000"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -323,7 +329,9 @@
|
||||
"Bzip2 Decompress",
|
||||
"Bzip2 Compress",
|
||||
"Tar",
|
||||
"Untar"
|
||||
"Untar",
|
||||
"LZString Compress",
|
||||
"LZString Decompress"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
21
src/core/lib/LZString.mjs
Normal file
21
src/core/lib/LZString.mjs
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* lz-string exports.
|
||||
*
|
||||
* @author crespyl [peter@crespyl.net]
|
||||
* @copyright Peter Jacobs 2021
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import LZString from "lz-string";
|
||||
|
||||
export const COMPRESSION_OUTPUT_FORMATS = ["default", "UTF16", "Base64"];
|
||||
export const COMPRESSION_FUNCTIONS = {
|
||||
"default": LZString.compress,
|
||||
"UTF16": LZString.compressToUTF16,
|
||||
"Base64": LZString.compressToBase64,
|
||||
};
|
||||
export const DECOMPRESSION_FUNCTIONS = {
|
||||
"default": LZString.decompress,
|
||||
"UTF16": LZString.decompressFromUTF16,
|
||||
"Base64": LZString.decompressFromBase64,
|
||||
};
|
||||
@@ -184,7 +184,7 @@ class Protobuf {
|
||||
bytes: String,
|
||||
longs: Number,
|
||||
enums: String,
|
||||
defualts: true
|
||||
defaults: true
|
||||
});
|
||||
const output = {};
|
||||
|
||||
|
||||
63
src/core/operations/CetaceanCipherDecode.mjs
Normal file
63
src/core/operations/CetaceanCipherDecode.mjs
Normal file
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* @author dolphinOnKeys [robin@weird.io]
|
||||
* @copyright Crown Copyright 2022
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
|
||||
/**
|
||||
* Cetacean Cipher Decode operation
|
||||
*/
|
||||
class CetaceanCipherDecode extends Operation {
|
||||
|
||||
/**
|
||||
* CetaceanCipherDecode constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Cetacean Cipher Decode";
|
||||
this.module = "Ciphers";
|
||||
this.description = "Decode Cetacean Cipher input. <br/><br/>e.g. <code>EEEEEEEEEeeEeEEEEEEEEEEEEeeEeEEe</code> becomes <code>hi</code>";
|
||||
this.infoURL = "https://hitchhikers.fandom.com/wiki/Dolphins";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
|
||||
this.checks = [
|
||||
{
|
||||
pattern: "^(?:[eE]{16,})(?: [eE]{16,})*$",
|
||||
flags: "",
|
||||
args: []
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const binaryArray = [];
|
||||
for (const char of input) {
|
||||
if (char === " ") {
|
||||
binaryArray.push(...[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0]);
|
||||
} else {
|
||||
binaryArray.push(char === "e" ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
const byteArray = [];
|
||||
|
||||
for (let i = 0; i < binaryArray.length; i += 16) {
|
||||
byteArray.push(binaryArray.slice(i, i + 16).join(""));
|
||||
}
|
||||
|
||||
return byteArray.map(byte =>
|
||||
String.fromCharCode(parseInt(byte, 2))
|
||||
).join("");
|
||||
}
|
||||
}
|
||||
|
||||
export default CetaceanCipherDecode;
|
||||
51
src/core/operations/CetaceanCipherEncode.mjs
Normal file
51
src/core/operations/CetaceanCipherEncode.mjs
Normal file
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* @author dolphinOnKeys [robin@weird.io]
|
||||
* @copyright Crown Copyright 2022
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import {toBinary} from "../lib/Binary.mjs";
|
||||
|
||||
/**
|
||||
* Cetacean Cipher Encode operation
|
||||
*/
|
||||
class CetaceanCipherEncode extends Operation {
|
||||
|
||||
/**
|
||||
* CetaceanCipherEncode constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Cetacean Cipher Encode";
|
||||
this.module = "Ciphers";
|
||||
this.description = "Converts any input into Cetacean Cipher. <br/><br/>e.g. <code>hi</code> becomes <code>EEEEEEEEEeeEeEEEEEEEEEEEEeeEeEEe</code>";
|
||||
this.infoURL = "https://hitchhikers.fandom.com/wiki/Dolphins";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const result = [];
|
||||
const charArray = input.split("");
|
||||
|
||||
charArray.map(character => {
|
||||
if (character === " ") {
|
||||
result.push(character);
|
||||
} else {
|
||||
const binaryArray = toBinary(character.charCodeAt(0), "None", 16).split("");
|
||||
result.push(binaryArray.map(str => str === "1" ? "e" : "E").join(""));
|
||||
}
|
||||
});
|
||||
|
||||
return result.join("");
|
||||
}
|
||||
}
|
||||
|
||||
export default CetaceanCipherEncode;
|
||||
@@ -4,7 +4,7 @@
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import jpath from "jsonpath";
|
||||
import {JSONPath} from "jsonpath-plus";
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
@@ -27,14 +27,20 @@ class JPathExpression extends Operation {
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Query",
|
||||
"type": "string",
|
||||
"value": ""
|
||||
name: "Query",
|
||||
type: "string",
|
||||
value: ""
|
||||
},
|
||||
{
|
||||
"name": "Result delimiter",
|
||||
"type": "binaryShortString",
|
||||
"value": "\\n"
|
||||
name: "Result delimiter",
|
||||
type: "binaryShortString",
|
||||
value: "\\n"
|
||||
},
|
||||
{
|
||||
name: "Prevent eval",
|
||||
type: "boolean",
|
||||
value: true,
|
||||
description: "Evaluated expressions are disabled by default for security reasons"
|
||||
}
|
||||
];
|
||||
}
|
||||
@@ -45,18 +51,21 @@ class JPathExpression extends Operation {
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [query, delimiter] = args;
|
||||
let results,
|
||||
obj;
|
||||
const [query, delimiter, preventEval] = args;
|
||||
let results, jsonObj;
|
||||
|
||||
try {
|
||||
obj = JSON.parse(input);
|
||||
jsonObj = JSON.parse(input);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Invalid input JSON: ${err.message}`);
|
||||
}
|
||||
|
||||
try {
|
||||
results = jpath.query(obj, query);
|
||||
results = JSONPath({
|
||||
path: query,
|
||||
json: jsonObj,
|
||||
preventEval: preventEval
|
||||
});
|
||||
} catch (err) {
|
||||
throw new OperationError(`Invalid JPath expression: ${err.message}`);
|
||||
}
|
||||
|
||||
@@ -114,8 +114,11 @@ class JSONToCSV extends Operation {
|
||||
* @returns {string}
|
||||
*/
|
||||
escapeCellContents(data, force=false) {
|
||||
if (typeof data === "number") data = data.toString();
|
||||
if (force && typeof data !== "string") data = JSON.stringify(data);
|
||||
if (data !== "string") {
|
||||
const isPrimitive = data == null || typeof data !== "object";
|
||||
if (isPrimitive) data = `${data}`;
|
||||
else if (force) data = JSON.stringify(data);
|
||||
}
|
||||
|
||||
// Double quotes should be doubled up
|
||||
data = data.replace(/"/g, '""');
|
||||
|
||||
55
src/core/operations/LZStringCompress.mjs
Normal file
55
src/core/operations/LZStringCompress.mjs
Normal file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* @author crespyl [peter@crespyl.net]
|
||||
* @copyright Peter Jacobs 2021
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
import {COMPRESSION_OUTPUT_FORMATS, COMPRESSION_FUNCTIONS} from "../lib/LZString.mjs";
|
||||
|
||||
/**
|
||||
* LZString Compress operation
|
||||
*/
|
||||
class LZStringCompress extends Operation {
|
||||
|
||||
/**
|
||||
* LZStringCompress constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "LZString Compress";
|
||||
this.module = "Compression";
|
||||
this.description = "Compress the input with lz-string.";
|
||||
this.infoURL = "https://pieroxy.net/blog/pages/lz-string/index.html";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "Compression Format",
|
||||
type: "option",
|
||||
defaultIndex: 0,
|
||||
value: COMPRESSION_OUTPUT_FORMATS
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const compress = COMPRESSION_FUNCTIONS[args[0]];
|
||||
if (compress) {
|
||||
return compress(input);
|
||||
} else {
|
||||
throw new OperationError("Unable to find compression function");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default LZStringCompress;
|
||||
56
src/core/operations/LZStringDecompress.mjs
Normal file
56
src/core/operations/LZStringDecompress.mjs
Normal file
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* @author crespyl [peter@crespyl.net]
|
||||
* @copyright Peter Jacobs 2021
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
import {COMPRESSION_OUTPUT_FORMATS, DECOMPRESSION_FUNCTIONS} from "../lib/LZString.mjs";
|
||||
|
||||
/**
|
||||
* LZString Decompress operation
|
||||
*/
|
||||
class LZStringDecompress extends Operation {
|
||||
|
||||
/**
|
||||
* LZStringDecompress constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "LZString Decompress";
|
||||
this.module = "Compression";
|
||||
this.description = "Decompresses data that was compressed with lz-string.";
|
||||
this.infoURL = "https://pieroxy.net/blog/pages/lz-string/index.html";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "Compression Format",
|
||||
type: "option",
|
||||
defaultIndex: 0,
|
||||
value: COMPRESSION_OUTPUT_FORMATS
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const decompress = DECOMPRESSION_FUNCTIONS[args[0]];
|
||||
if (decompress) {
|
||||
return decompress(input);
|
||||
} else {
|
||||
throw new OperationError("Unable to find decompression function");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
export default LZStringDecompress;
|
||||
@@ -12,10 +12,8 @@ import { isImage } from "../lib/FileType.mjs";
|
||||
import { toBase64 } from "../lib/Base64.mjs";
|
||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||
|
||||
import Tesseract from "tesseract.js";
|
||||
const { createWorker } = Tesseract;
|
||||
|
||||
import process from "process";
|
||||
import { createWorker } from "tesseract.js";
|
||||
|
||||
/**
|
||||
* Optical Character Recognition operation
|
||||
@@ -55,7 +53,7 @@ class OpticalCharacterRecognition extends Operation {
|
||||
|
||||
const type = isImage(input);
|
||||
if (!type) {
|
||||
throw new OperationError("Invalid File Type");
|
||||
throw new OperationError("Unsupported file type (supported: jpg,png,pbm,bmp) or no file provided");
|
||||
}
|
||||
|
||||
const assetDir = isWorkerEnvironment() ? `${self.docURL}/assets/` : `${process.cwd()}/src/core/vendor/`;
|
||||
@@ -74,7 +72,7 @@ class OpticalCharacterRecognition extends Operation {
|
||||
}
|
||||
});
|
||||
await worker.load();
|
||||
self.sendStatusMessage("Loading English language...");
|
||||
self.sendStatusMessage(`Loading English language pack...`);
|
||||
await worker.loadLanguage("eng");
|
||||
self.sendStatusMessage("Intialising Tesseract API...");
|
||||
await worker.initialize("eng");
|
||||
|
||||
102
src/core/operations/ROT13BruteForce.mjs
Normal file
102
src/core/operations/ROT13BruteForce.mjs
Normal file
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* @author MikeCAT
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
|
||||
/**
|
||||
* ROT13 Brute Force operation.
|
||||
*/
|
||||
class ROT13BruteForce extends Operation {
|
||||
|
||||
/**
|
||||
* ROT13BruteForce constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "ROT13 Brute Force";
|
||||
this.module = "Default";
|
||||
this.description = "Try all meaningful amounts for ROT13.<br><br>Optionally you can enter your known plaintext (crib) to filter the result.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/ROT13";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "Rotate lower case chars",
|
||||
type: "boolean",
|
||||
value: true
|
||||
},
|
||||
{
|
||||
name: "Rotate upper case chars",
|
||||
type: "boolean",
|
||||
value: true
|
||||
},
|
||||
{
|
||||
name: "Rotate numbers",
|
||||
type: "boolean",
|
||||
value: false
|
||||
},
|
||||
{
|
||||
name: "Sample length",
|
||||
type: "number",
|
||||
value: 100
|
||||
},
|
||||
{
|
||||
name: "Sample offset",
|
||||
type: "number",
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
name: "Print amount",
|
||||
type: "boolean",
|
||||
value: true
|
||||
},
|
||||
{
|
||||
name: "Crib (known plaintext string)",
|
||||
type: "string",
|
||||
value: ""
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [rotateLower, rotateUpper, rotateNum, sampleLength, sampleOffset, printAmount, crib] = args;
|
||||
const sample = input.slice(sampleOffset, sampleOffset + sampleLength);
|
||||
const cribLower = crib.toLowerCase();
|
||||
const lowerStart = "a".charCodeAt(0), upperStart = "A".charCodeAt(0), numStart = "0".charCodeAt(0);
|
||||
const result = [];
|
||||
for (let amount = 1; amount < 26; amount++) {
|
||||
const rotated = sample.slice();
|
||||
for (let i = 0; i < rotated.length; i++) {
|
||||
if (rotateLower && lowerStart <= rotated[i] && rotated[i] < lowerStart + 26) {
|
||||
rotated[i] = (rotated[i] - lowerStart + amount) % 26 + lowerStart;
|
||||
} else if (rotateUpper && upperStart <= rotated[i] && rotated[i] < upperStart + 26) {
|
||||
rotated[i] = (rotated[i] - upperStart + amount) % 26 + upperStart;
|
||||
} else if (rotateNum && numStart <= rotated[i] && rotated[i] < numStart + 10) {
|
||||
rotated[i] = (rotated[i] - numStart + amount) % 10 + numStart;
|
||||
}
|
||||
}
|
||||
const rotatedString = Utils.byteArrayToUtf8(rotated);
|
||||
if (rotatedString.toLowerCase().indexOf(cribLower) >= 0) {
|
||||
const rotatedStringPrintable = Utils.printable(rotatedString, false);
|
||||
if (printAmount) {
|
||||
const amountStr = "Amount = " + (" " + amount).slice(-2) + ": ";
|
||||
result.push(amountStr + rotatedStringPrintable);
|
||||
} else {
|
||||
result.push(rotatedStringPrintable);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.join("\n");
|
||||
}
|
||||
}
|
||||
|
||||
export default ROT13BruteForce;
|
||||
82
src/core/operations/ROT47BruteForce.mjs
Normal file
82
src/core/operations/ROT47BruteForce.mjs
Normal file
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* @author MikeCAT
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import Utils from "../Utils.mjs";
|
||||
|
||||
/**
|
||||
* ROT47 Brute Force operation.
|
||||
*/
|
||||
class ROT47BruteForce extends Operation {
|
||||
|
||||
/**
|
||||
* ROT47BruteForce constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "ROT47 Brute Force";
|
||||
this.module = "Default";
|
||||
this.description = "Try all meaningful amounts for ROT47.<br><br>Optionally you can enter your known plaintext (crib) to filter the result.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/ROT13#Variants";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "Sample length",
|
||||
type: "number",
|
||||
value: 100
|
||||
},
|
||||
{
|
||||
name: "Sample offset",
|
||||
type: "number",
|
||||
value: 0
|
||||
},
|
||||
{
|
||||
name: "Print amount",
|
||||
type: "boolean",
|
||||
value: true
|
||||
},
|
||||
{
|
||||
name: "Crib (known plaintext string)",
|
||||
type: "string",
|
||||
value: ""
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [sampleLength, sampleOffset, printAmount, crib] = args;
|
||||
const sample = input.slice(sampleOffset, sampleOffset + sampleLength);
|
||||
const cribLower = crib.toLowerCase();
|
||||
const result = [];
|
||||
for (let amount = 1; amount < 94; amount++) {
|
||||
const rotated = sample.slice();
|
||||
for (let i = 0; i < rotated.length; i++) {
|
||||
if (33 <= rotated[i] && rotated[i] <= 126) {
|
||||
rotated[i] = (rotated[i] - 33 + amount) % 94 + 33;
|
||||
}
|
||||
}
|
||||
const rotatedString = Utils.byteArrayToUtf8(rotated);
|
||||
if (rotatedString.toLowerCase().indexOf(cribLower) >= 0) {
|
||||
const rotatedStringPrintable = Utils.printable(rotatedString, false);
|
||||
if (printAmount) {
|
||||
const amountStr = "Amount = " + (" " + amount).slice(-2) + ": ";
|
||||
result.push(amountStr + rotatedStringPrintable);
|
||||
} else {
|
||||
result.push(rotatedStringPrintable);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result.join("\n");
|
||||
}
|
||||
}
|
||||
|
||||
export default ROT47BruteForce;
|
||||
123
src/core/operations/ROT8000.mjs
Normal file
123
src/core/operations/ROT8000.mjs
Normal file
@@ -0,0 +1,123 @@
|
||||
/**
|
||||
* @author Daniel Temkin [http://danieltemkin.com]
|
||||
* @author Thomas Leplus [https://www.leplus.org]
|
||||
* @copyright Crown Copyright 2021
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
|
||||
/**
|
||||
* ROT8000 operation.
|
||||
*/
|
||||
class ROT8000 extends Operation {
|
||||
|
||||
/**
|
||||
* ROT8000 constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
this.name = "ROT8000";
|
||||
this.module = "Default";
|
||||
this.description = "The simple Caesar-cypher encryption that replaces each Unicode character with the one 0x8000 places forward or back along the alphabet.";
|
||||
this.infoURL = "https://rot8000.com/info";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
run(input, args) {
|
||||
// Inspired from https://github.com/rottytooth/rot8000/blob/main/rot8000.js
|
||||
// these come from the valid-code-point-transitions.json file generated from the c# proj
|
||||
// this is done bc: 1) don't trust JS's understanging of surrogate pairs and 2) consistency with original rot8000
|
||||
const validCodePoints = {
|
||||
"33": true,
|
||||
"127": false,
|
||||
"161": true,
|
||||
"5760": false,
|
||||
"5761": true,
|
||||
"8192": false,
|
||||
"8203": true,
|
||||
"8232": false,
|
||||
"8234": true,
|
||||
"8239": false,
|
||||
"8240": true,
|
||||
"8287": false,
|
||||
"8288": true,
|
||||
"12288": false,
|
||||
"12289": true,
|
||||
"55296": false,
|
||||
"57344": true
|
||||
};
|
||||
const bmpSize = 0x10000;
|
||||
const rotList = {}; // the mapping of char to rotated char
|
||||
const hiddenBlocks = [];
|
||||
let startBlock = 0;
|
||||
for (const key in validCodePoints) {
|
||||
if (Object.prototype.hasOwnProperty.call(validCodePoints, key)) {
|
||||
if (validCodePoints[key] === true)
|
||||
hiddenBlocks.push({ start: startBlock, end: parseInt(key, 10) - 1 });
|
||||
else
|
||||
startBlock = parseInt(key, 10);
|
||||
}
|
||||
}
|
||||
const validIntList = []; // list of all valid chars
|
||||
let currValid = false;
|
||||
for (let i = 0; i < bmpSize; i++) {
|
||||
if (validCodePoints[i] !== undefined) {
|
||||
currValid = validCodePoints[i];
|
||||
}
|
||||
if (currValid) validIntList.push(i);
|
||||
}
|
||||
const rotateNum = Object.keys(validIntList).length / 2;
|
||||
// go through every valid char and find its match
|
||||
for (let i = 0; i < validIntList.length; i++) {
|
||||
rotList[String.fromCharCode(validIntList[i])] =
|
||||
String.fromCharCode(validIntList[(i + rotateNum) % (rotateNum * 2)]);
|
||||
}
|
||||
let output = "";
|
||||
for (let count = 0; count < input.length; count++) {
|
||||
// if it is not in the mappings list, just add it directly (no rotation)
|
||||
if (rotList[input[count]] === undefined) {
|
||||
output += input[count];
|
||||
continue;
|
||||
}
|
||||
// otherwise, rotate it and add it to the string
|
||||
output += rotList[input[count]];
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight ROT8000
|
||||
*
|
||||
* @param {Object[]} pos
|
||||
* @param {number} pos[].start
|
||||
* @param {number} pos[].end
|
||||
* @param {Object[]} args
|
||||
* @returns {Object[]} pos
|
||||
*/
|
||||
highlight(pos, args) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight ROT8000 in reverse
|
||||
*
|
||||
* @param {Object[]} pos
|
||||
* @param {number} pos[].start
|
||||
* @param {number} pos[].end
|
||||
* @param {Object[]} args
|
||||
* @returns {Object[]} pos
|
||||
*/
|
||||
highlightReverse(pos, args) {
|
||||
return pos;
|
||||
}
|
||||
}
|
||||
|
||||
export default ROT8000;
|
||||
@@ -52,7 +52,17 @@ class YARARules extends Operation {
|
||||
name: "Show counts",
|
||||
type: "boolean",
|
||||
value: true
|
||||
}
|
||||
},
|
||||
{
|
||||
name: "Show rule warnings",
|
||||
type: "boolean",
|
||||
value: true
|
||||
},
|
||||
{
|
||||
name: "Show console module messages",
|
||||
type: "boolean",
|
||||
value: true
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
@@ -64,7 +74,7 @@ class YARARules extends Operation {
|
||||
async run(input, args) {
|
||||
if (isWorkerEnvironment())
|
||||
self.sendStatusMessage("Instantiating YARA...");
|
||||
const [rules, showStrings, showLengths, showMeta, showCounts] = args;
|
||||
const [rules, showStrings, showLengths, showMeta, showCounts, showRuleWarns, showConsole] = args;
|
||||
return new Promise((resolve, reject) => {
|
||||
Yara().then(yara => {
|
||||
if (isWorkerEnvironment()) self.sendStatusMessage("Converting data for YARA.");
|
||||
@@ -83,11 +93,19 @@ class YARARules extends Operation {
|
||||
const compileError = resp.compileErrors.get(i);
|
||||
if (!compileError.warning) {
|
||||
reject(new OperationError(`Error on line ${compileError.lineNumber}: ${compileError.message}`));
|
||||
} else {
|
||||
matchString += `Warning on line ${compileError.lineNumber}: ${compileError.message}`;
|
||||
} else if (showRuleWarns) {
|
||||
matchString += `Warning on line ${compileError.lineNumber}: ${compileError.message}\n`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (showConsole) {
|
||||
const consoleLogs = resp.consoleLogs;
|
||||
for (let i = 0; i < consoleLogs.size(); i++) {
|
||||
matchString += consoleLogs.get(i) + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
const matchedRules = resp.matchedRules;
|
||||
for (let i = 0; i < matchedRules.size(); i++) {
|
||||
const rule = matchedRules.get(i);
|
||||
@@ -100,11 +118,11 @@ class YARARules extends Operation {
|
||||
}
|
||||
meta = meta.slice(0, -2) + "]";
|
||||
}
|
||||
const countString = showCounts ? `${matches.size()} time${matches.size() > 1 ? "s" : ""}` : "";
|
||||
const countString = matches.size() === 0 ? "" : (showCounts ? ` (${matches.size()} time${matches.size() > 1 ? "s" : ""})` : "");
|
||||
if (matches.size() === 0 || !(showStrings || showLengths)) {
|
||||
matchString += `Input matches rule "${rule.ruleName}"${meta}${countString.length > 0 ? ` ${countString}`: ""}.\n`;
|
||||
} else {
|
||||
matchString += `Rule "${rule.ruleName}"${meta} matches (${countString}):\n`;
|
||||
matchString += `Rule "${rule.ruleName}"${meta} matches${countString}:\n`;
|
||||
for (let j = 0; j < matches.size(); j++) {
|
||||
const match = matches.get(j);
|
||||
if (showStrings || showLengths) {
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
import "highlight.js/styles/vs.css";
|
||||
|
||||
/* Frameworks */
|
||||
import "./vendors/bootstrap.scss";
|
||||
import "bootstrap-material-design/dist/css/bootstrap-material-design.css";
|
||||
import "bootstrap-colorpicker/dist/css/bootstrap-colorpicker.css";
|
||||
|
||||
/* CyberChef styles */
|
||||
|
||||
@@ -82,7 +82,17 @@ a:focus {
|
||||
border-color: var(--btn-success-hover-border-colour);
|
||||
}
|
||||
|
||||
select.form-control:not([size]):not([multiple]), select.custom-file-control:not([size]):not([multiple]) {
|
||||
select.form-control,
|
||||
select.form-control:focus {
|
||||
background-color: var(--primary-background-colour) !important;
|
||||
}
|
||||
|
||||
select.form-control:focus {
|
||||
transition: none !important;
|
||||
}
|
||||
|
||||
select.form-control:not([size]):not([multiple]),
|
||||
select.custom-file-control:not([size]):not([multiple]) {
|
||||
height: unset !important;
|
||||
}
|
||||
|
||||
@@ -145,7 +155,8 @@ optgroup {
|
||||
color: var(--primary-font-colour);
|
||||
}
|
||||
|
||||
.table-bordered th, .table-bordered td {
|
||||
.table-bordered th,
|
||||
.table-bordered td {
|
||||
border: 1px solid var(--table-border-colour);
|
||||
}
|
||||
|
||||
@@ -172,7 +183,9 @@ optgroup {
|
||||
color: var(--subtext-font-colour);
|
||||
}
|
||||
|
||||
.nav-tabs>li>a.nav-link.active, .nav-tabs>li>a.nav-link.active:focus, .nav-tabs>li>a.nav-link.active:hover {
|
||||
.nav-tabs>li>a.nav-link.active,
|
||||
.nav-tabs>li>a.nav-link.active:focus,
|
||||
.nav-tabs>li>a.nav-link.active:hover {
|
||||
background-color: var(--secondary-background-colour);
|
||||
border-color: var(--secondary-border-colour);
|
||||
border-bottom-color: transparent;
|
||||
@@ -183,7 +196,8 @@ optgroup {
|
||||
border-color: var(--primary-border-colour);
|
||||
}
|
||||
|
||||
.nav a.nav-link:focus, .nav a.nav-link:hover {
|
||||
.nav a.nav-link:focus,
|
||||
.nav a.nav-link:hover {
|
||||
background-color: var(--secondary-border-colour);
|
||||
}
|
||||
|
||||
@@ -199,7 +213,8 @@ optgroup {
|
||||
color: var(--primary-font-colour);
|
||||
}
|
||||
|
||||
.dropdown-menu a:focus, .dropdown-menu a:hover {
|
||||
.dropdown-menu a:focus,
|
||||
.dropdown-menu a:hover {
|
||||
background-color: var(--secondary-background-colour);
|
||||
color: var(--primary-font-colour);
|
||||
}
|
||||
|
||||
23
src/web/stylesheets/vendors/bootstrap.scss
vendored
23
src/web/stylesheets/vendors/bootstrap.scss
vendored
@@ -1,23 +0,0 @@
|
||||
/**
|
||||
* Bootstrap Material Design with overrides
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
@import "~bootstrap-material-design/scss/variables/colors";
|
||||
|
||||
$theme-colors: (
|
||||
primary: $blue-700,
|
||||
success: $green,
|
||||
info: $light-blue,
|
||||
warning: $deep-orange,
|
||||
danger: $red,
|
||||
light: $grey-100,
|
||||
dark: $grey-800
|
||||
);
|
||||
|
||||
$bmd-form-line-height: 1.25;
|
||||
|
||||
@import "~bootstrap-material-design/scss/core";
|
||||
@@ -249,6 +249,7 @@ module.exports = {
|
||||
// testOp(browser, "RIPEMD", "test input", "test_output");
|
||||
// testOp(browser, "ROT13", "test input", "test_output");
|
||||
// testOp(browser, "ROT47", "test input", "test_output");
|
||||
// testOp(browser, "ROT8000", "test input", "test_output");
|
||||
// testOp(browser, "Rail Fence Cipher Decode", "test input", "test_output");
|
||||
// testOp(browser, "Rail Fence Cipher Encode", "test input", "test_output");
|
||||
// testOp(browser, "Randomize Colour Palette", "test input", "test_output");
|
||||
|
||||
@@ -28,6 +28,8 @@ import "./tests/Base85.mjs";
|
||||
import "./tests/BitwiseOp.mjs";
|
||||
import "./tests/ByteRepr.mjs";
|
||||
import "./tests/CartesianProduct.mjs";
|
||||
import "./tests/CetaceanCipherEncode.mjs";
|
||||
import "./tests/CetaceanCipherDecode.mjs";
|
||||
import "./tests/CharEnc.mjs";
|
||||
import "./tests/ChangeIPFormat.mjs";
|
||||
import "./tests/Charts.mjs";
|
||||
@@ -118,6 +120,7 @@ import "./tests/ELFInfo.mjs";
|
||||
import "./tests/Subsection.mjs";
|
||||
import "./tests/CaesarBoxCipher.mjs";
|
||||
import "./tests/LS47.mjs";
|
||||
import "./tests/LZString.mjs";
|
||||
|
||||
|
||||
// Cannot test operations that use the File type yet
|
||||
|
||||
22
tests/operations/tests/CetaceanCipherDecode.mjs
Normal file
22
tests/operations/tests/CetaceanCipherDecode.mjs
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* CetaceanCipher Encode tests
|
||||
*
|
||||
* @author dolphinOnKeys
|
||||
* @copyright Crown Copyright 2022
|
||||
* @licence Apache-2.0
|
||||
*/
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "Cetacean Cipher Decode",
|
||||
input: "EEEEEEEEEeeEEEEe EEEEEEEEEeeEEEeE EEEEEEEEEeeEEEee EEeeEEEEEeeEEeee",
|
||||
expectedOutput: "a b c で",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Cetacean Cipher Decode",
|
||||
args: []
|
||||
},
|
||||
],
|
||||
}
|
||||
]);
|
||||
22
tests/operations/tests/CetaceanCipherEncode.mjs
Normal file
22
tests/operations/tests/CetaceanCipherEncode.mjs
Normal file
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* CetaceanCipher Encode tests
|
||||
*
|
||||
* @author dolphinOnKeys
|
||||
* @copyright Crown Copyright 2022
|
||||
* @licence Apache-2.0
|
||||
*/
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "Cetacean Cipher Encode",
|
||||
input: "a b c で",
|
||||
expectedOutput: "EEEEEEEEEeeEEEEe EEEEEEEEEeeEEEeE EEEEEEEEEeeEEEee EEeeEEEEEeeEEeee",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Cetacean Cipher Encode",
|
||||
args: []
|
||||
},
|
||||
],
|
||||
}
|
||||
]);
|
||||
@@ -185,11 +185,11 @@ TestRegister.addTests([
|
||||
{
|
||||
name: "JPath Expression: Empty expression",
|
||||
input: JSON.stringify(JSON_TEST_DATA),
|
||||
expectedOutput: "Invalid JPath expression: we need a path",
|
||||
expectedOutput: "",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "JPath expression",
|
||||
"args": ["", "\n"]
|
||||
"args": ["", "\n", true]
|
||||
}
|
||||
],
|
||||
},
|
||||
@@ -205,7 +205,7 @@ TestRegister.addTests([
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "JPath expression",
|
||||
"args": ["$.store.book[*].author", "\n"]
|
||||
"args": ["$.store.book[*].author", "\n", true]
|
||||
}
|
||||
],
|
||||
},
|
||||
@@ -223,7 +223,7 @@ TestRegister.addTests([
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "JPath expression",
|
||||
"args": ["$..title", "\n"]
|
||||
"args": ["$..title", "\n", true]
|
||||
}
|
||||
],
|
||||
},
|
||||
@@ -238,7 +238,7 @@ TestRegister.addTests([
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "JPath expression",
|
||||
"args": ["$.store.*", "\n"]
|
||||
"args": ["$.store.*", "\n", true]
|
||||
}
|
||||
],
|
||||
},
|
||||
@@ -249,7 +249,7 @@ TestRegister.addTests([
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "JPath expression",
|
||||
"args": ["$..book[-1:]", "\n"]
|
||||
"args": ["$..book[-1:]", "\n", true]
|
||||
}
|
||||
],
|
||||
},
|
||||
@@ -263,7 +263,7 @@ TestRegister.addTests([
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "JPath expression",
|
||||
"args": ["$..book[:2]", "\n"]
|
||||
"args": ["$..book[:2]", "\n", true]
|
||||
}
|
||||
],
|
||||
},
|
||||
@@ -277,7 +277,7 @@ TestRegister.addTests([
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "JPath expression",
|
||||
"args": ["$..book[?(@.isbn)]", "\n"]
|
||||
"args": ["$..book[?(@.isbn)]", "\n", false]
|
||||
}
|
||||
],
|
||||
},
|
||||
@@ -292,7 +292,7 @@ TestRegister.addTests([
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "JPath expression",
|
||||
"args": ["$..book[?(@.price<30 && @.category==\"fiction\")]", "\n"]
|
||||
"args": ["$..book[?(@.price<30 && @.category==\"fiction\")]", "\n", false]
|
||||
}
|
||||
],
|
||||
},
|
||||
@@ -306,10 +306,25 @@ TestRegister.addTests([
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "JPath expression",
|
||||
"args": ["$..book[?(@.price<10)]", "\n"]
|
||||
"args": ["$..book[?(@.price<10)]", "\n", false]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JPath Expression: Script-based expression",
|
||||
input: "[{}]",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "JPath expression",
|
||||
"args": [
|
||||
"$..[?(({__proto__:[].constructor}).constructor(\"self.postMessage({action:'bakeComplete',data:{bakeId:1,dish:{type:1,value:''},duration:1,error:false,id:undefined,inputNum:2,progress:1,result:'<iframe/onload=debugger>',type: 'html'}});\")();)]",
|
||||
"\n",
|
||||
true
|
||||
]
|
||||
}
|
||||
],
|
||||
expectedOutput: "Invalid JPath expression: Eval [?(expr)] prevented in JSONPath expression."
|
||||
},
|
||||
{
|
||||
name: "CSS selector",
|
||||
input: '<div id="test">\n<p class="a">hello</p>\n<p>world</p>\n<p class="a">again</p>\n</div>',
|
||||
|
||||
@@ -46,6 +46,17 @@ TestRegister.addTests([
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JSON to CSV: boolean and null as values",
|
||||
input: JSON.stringify({a: false, b: null, c: 3}),
|
||||
expectedOutput: "a,b,c\r\nfalse,null,3\r\n",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JSON to CSV",
|
||||
args: [",", "\\r\\n"]
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JSON to CSV: JSON as an array",
|
||||
input: JSON.stringify([{a: 1, b: "2", c: 3}]),
|
||||
|
||||
33
tests/operations/tests/LZString.mjs
Normal file
33
tests/operations/tests/LZString.mjs
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* LZString tests.
|
||||
*
|
||||
* @author crespyl [peter@crespyl.net]
|
||||
* @copyright Peter Jacobs 2021
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "LZString Compress To Base64",
|
||||
input: "hello world",
|
||||
expectedOutput: "BYUwNmD2AEDukCcwBMg=",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "LZString Compress",
|
||||
"args": ["Base64"]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "LZString Decompress From Base64",
|
||||
input: "BYUwNmD2AEDukCcwBMg=",
|
||||
expectedOutput: "hello world",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "LZString Decompress",
|
||||
"args": ["Base64"]
|
||||
}
|
||||
],
|
||||
}
|
||||
]);
|
||||
@@ -40,10 +40,10 @@ TestRegister.addTests([
|
||||
"Apple": [
|
||||
28
|
||||
],
|
||||
"Banana": "You",
|
||||
"Carrot": [
|
||||
"Me"
|
||||
]
|
||||
],
|
||||
"Banana": "You"
|
||||
}, null, 4),
|
||||
recipeConfig: [
|
||||
{
|
||||
@@ -72,10 +72,10 @@ TestRegister.addTests([
|
||||
"Apple": [
|
||||
28
|
||||
],
|
||||
"Banana": "You",
|
||||
"Carrot": [
|
||||
"Me"
|
||||
]
|
||||
],
|
||||
"Banana": "You"
|
||||
},
|
||||
"Unknown Fields": {
|
||||
"4": 43,
|
||||
@@ -111,10 +111,10 @@ TestRegister.addTests([
|
||||
"Apple": [
|
||||
28
|
||||
],
|
||||
"Banana": "You",
|
||||
"Carrot": [
|
||||
"Me"
|
||||
],
|
||||
"Banana": "You",
|
||||
"Date": 43,
|
||||
"Elderberry": {
|
||||
"Fig": "abc123",
|
||||
@@ -154,10 +154,10 @@ TestRegister.addTests([
|
||||
input: "0d1c0000001203596f751a024d65202b2a0a0a06616263313233120031ba32a96cc10200003801",
|
||||
expectedOutput: JSON.stringify({
|
||||
"Test": {
|
||||
"Banana (string)": "You",
|
||||
"Carrot (string)": [
|
||||
"Me"
|
||||
],
|
||||
"Banana (string)": "You",
|
||||
"Date (int32)": 43,
|
||||
"Imbe (Options)": "Option1"
|
||||
},
|
||||
|
||||
@@ -212,4 +212,37 @@ TestRegister.addTests([
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "ROT8000: nothing",
|
||||
input: "",
|
||||
expectedOutput: "",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "ROT8000",
|
||||
args: []
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "ROT8000: normal",
|
||||
input: "The Quick Brown Fox Jumped Over The Lazy Dog.",
|
||||
expectedOutput: "籝籱籮 籚籾籲籬籴 籋类籸粀籷 籏籸粁 籓籾籶籹籮籭 籘籿籮类 籝籱籮 籕籪粃粂 籍籸籰簷",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "ROT8000",
|
||||
args: []
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "ROT8000: backward",
|
||||
input: "籝籱籮 籚籾籲籬籴 籋类籸粀籷 籏籸粁 籓籾籶籹籮籭 籘籿籮类 籝籱籮 籕籪粃粂 籍籸籰簷",
|
||||
expectedOutput: "The Quick Brown Fox Jumped Over The Lazy Dog.",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "ROT8000",
|
||||
args: []
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
@@ -8,6 +8,22 @@
|
||||
*/
|
||||
import TestRegister from "../../lib/TestRegister.mjs";
|
||||
|
||||
const CONSOLE_COMPILE_WARNING_RULE = `import "console"
|
||||
rule a
|
||||
{
|
||||
strings:
|
||||
$s=" "
|
||||
condition:
|
||||
$s and console.log("log rule a")
|
||||
}
|
||||
rule b
|
||||
{
|
||||
strings:
|
||||
$s=" "
|
||||
condition:
|
||||
$s and console.hex("log rule b: int8(0)=", int8(0))
|
||||
}`;
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "YARA Match: simple foobar",
|
||||
@@ -20,5 +36,56 @@ TestRegister.addTests([
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "YARA Match: hashing rules",
|
||||
input: "Hello World!",
|
||||
expectedOutput: "Input matches rule \"HelloWorldMD5\".\nInput matches rule \"HelloWorldSHA256\".\n",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "YARA Rules",
|
||||
"args": [
|
||||
`import "hash"
|
||||
rule HelloWorldMD5 {
|
||||
condition:
|
||||
hash.md5(0,filesize) == "ed076287532e86365e841e92bfc50d8c"
|
||||
}
|
||||
|
||||
rule HelloWorldSHA256 {
|
||||
condition:
|
||||
hash.sha256(0,filesize) == "7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069"
|
||||
}`,
|
||||
true, true, true, true, false, false
|
||||
],
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "YARA Match: compile warnings",
|
||||
input: "CyberChef Yara",
|
||||
expectedOutput: "Warning on line 5: string \"$s\" may slow down scanning\n" +
|
||||
"Warning on line 12: string \"$s\" may slow down scanning\n" +
|
||||
"Input matches rule \"a\".\n" +
|
||||
"Input matches rule \"b\".\n",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "YARA Rules",
|
||||
"args": [CONSOLE_COMPILE_WARNING_RULE, false, false, false, false, true, false],
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "YARA Match: console messages",
|
||||
input: "CyberChef Yara",
|
||||
expectedOutput: "log rule a\n" +
|
||||
"log rule b: int8(0)=0x43\n" +
|
||||
"Input matches rule \"a\".\n" +
|
||||
"Input matches rule \"b\".\n",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "YARA Rules",
|
||||
"args": [CONSOLE_COMPILE_WARNING_RULE, false, false, false, false, false, true],
|
||||
}
|
||||
],
|
||||
},
|
||||
]);
|
||||
|
||||
|
||||
@@ -109,7 +109,8 @@ module.exports = {
|
||||
"buffer": require.resolve("buffer/"),
|
||||
"crypto": require.resolve("crypto-browserify"),
|
||||
"stream": require.resolve("stream-browserify"),
|
||||
"zlib": require.resolve("browserify-zlib")
|
||||
"zlib": require.resolve("browserify-zlib"),
|
||||
"process": false
|
||||
}
|
||||
},
|
||||
module: {
|
||||
@@ -164,19 +165,6 @@ module.exports = {
|
||||
"postcss-loader",
|
||||
]
|
||||
},
|
||||
{
|
||||
test: /\.scss$/,
|
||||
use: [
|
||||
{
|
||||
loader: MiniCssExtractPlugin.loader,
|
||||
options: {
|
||||
publicPath: "../"
|
||||
}
|
||||
},
|
||||
"css-loader",
|
||||
"sass-loader",
|
||||
]
|
||||
},
|
||||
{
|
||||
test: /\.(ico|eot|ttf|woff|woff2)$/,
|
||||
type: "asset/resource",
|
||||
|
||||
Reference in New Issue
Block a user