Compare commits

...
29 Commits
Author SHA1 Message Date
n1474335 a5a89efc06 9.38.2 2022-06-03 12:58:50 +01:00
n1474335 1078c37043 Merge branch 'master' of https://github.com/LukeSerne/CyberChef 2022-06-03 12:55:56 +01:00
n1474335 535c7188a8 9.38.1 2022-06-03 12:53:22 +01:00
n1474335 d6f9e216a6 Merge branch 'fix-to-base45' of https://github.com/mikecat/CyberChef 2022-06-03 12:50:45 +01:00
n1474335 7d6a879a67 Added script for updating the CHANGELOG 2022-05-31 00:20:19 +01:00
n1474335 668eac1f9e Fixed Split.js issues when resizing to around 1000px wide 2022-05-30 22:53:17 +01:00
n1474335 ff99436ce6 Fixed 'To Hex' highlighting 2022-05-30 19:43:59 +01:00
n1474335 ec577fc075 Fixed CSS for maximising output pane 2022-05-30 19:25:41 +01:00
n1474335 cc9d51b7be 9.38.0 2022-05-30 18:14:46 +01:00
n1474335 cf2b54e8c0 Update CHANGELOG 2022-05-30 18:14:41 +01:00
n1474335 a895d1d82a Added 'Parse TCP' operation 2022-05-30 18:06:15 +01:00
MikeCAT 11da4188ee fix "To Base45" ( #1351 ) 2022-05-20 11:59:04 +00:00
Luke Serné 5b68bad185 Support UTF8 encoded characters in Substitution operation
This adds support for UTF8-encoded characters in the input and the parameters.
2022-05-13 17:35:50 +02:00
n1474335 477e4a7421 9.37.3 2022-04-14 18:08:23 +01:00
n1474335 9a982f05ac Extract operations now offer built-in Sort and Unique options. Unique operation offers option to count occurances. Closes #1334. 2022-04-14 18:08:16 +01:00
n1474335 6959e2cf01 9.37.2 2022-04-14 16:57:51 +01:00
n1474335 f5fe79326a CodeQL fixes 2022-04-14 16:57:46 +01:00
n1474335 f77633cee9 9.37.1 2022-04-14 13:17:43 +01:00
n1474335 c858970573 Merge branch 'john19696-testui' 2022-04-14 13:17:32 +01:00
n1474335 fb3eceaee0 Tidied up UI tests 2022-04-14 13:16:36 +01:00
n1474335 8e37fec8f8 Merge branch 'testui' of https://github.com/john19696/CyberChef into john19696-testui 2022-04-14 11:55:56 +01:00
n1474335 ccaabfaee8 Fixed incorrect wording for RC4 Drop argument. 2022-04-14 11:55:34 +01:00
John L c431fb30c5 added logging & jsdoc 2022-04-06 10:54:20 +01:00
John L 1c04848480 added log_path 2022-04-06 10:51:52 +01:00
John L ca1a0797fb Merge branch 'master' into testui 2022-04-04 17:54:02 +01:00
John L 7b497181fd refactor samples, and more tests 2022-04-04 17:40:58 +01:00
John L 92767b1078 Try import 2022-03-31 19:32:41 +01:00
John L add745551b WIP 2022-02-11 16:56:58 +00:00
john19696 7b8213e1f6 Merge pull request #3 from john19696/nodejs16
Nodejs16 upgrade
2022-02-11 13:04:49 +00:00
52 changed files with 1206 additions and 360 deletions

No files matched your search

+7 -2
View File
@@ -13,6 +13,9 @@ All major and minor version changes will be documented in this file. Details of
## Details
### [9.38.0] - 2022-05-30
- Added 'Parse TCP' operation [@n1474335] | [a895d1d]
### [9.37.0] - 2022-03-29
- 'SM4 Encrypt' and 'SM4 Decrypt' operations added [@swesven] | [#1189]
- NoPadding options added for CBC and ECB modes in AES, DES and Triple DES Decrypt operations [@swesven] | [#1189]
@@ -135,7 +138,7 @@ All major and minor version changes will be documented in this file. Details of
<details>
<summary>Click to expand v8 minor versions</summary>
### [8.38.0] - 2019-07-03
- 'Streebog' and 'GOST hash' operations added [@MShwed] [@n1474335] | [#530]
@@ -288,6 +291,7 @@ All major and minor version changes will be documented in this file. Details of
[9.38.0]: https://github.com/gchq/CyberChef/releases/tag/v9.38.0
[9.37.0]: https://github.com/gchq/CyberChef/releases/tag/v9.37.0
[9.36.0]: https://github.com/gchq/CyberChef/releases/tag/v9.36.0
[9.35.0]: https://github.com/gchq/CyberChef/releases/tag/v9.35.0
@@ -416,6 +420,7 @@ All major and minor version changes will be documented in this file. Details of
[289a417]: https://github.com/gchq/CyberChef/commit/289a417dfb5923de5e1694354ec42a08d9395bfe
[e9ca4dc]: https://github.com/gchq/CyberChef/commit/e9ca4dc9caf98f33fd986431cd400c88082a42b8
[dd18e52]: https://github.com/gchq/CyberChef/commit/dd18e529939078b89867297b181a584e8b2cc7da
[a895d1d]: https://github.com/gchq/CyberChef/commit/a895d1d82a2f92d440a0c5eca2bc7c898107b737
[#95]: https://github.com/gchq/CyberChef/pull/299
[#173]: https://github.com/gchq/CyberChef/pull/173
@@ -502,4 +507,4 @@ All major and minor version changes will be documented in this file. Details of
[#1242]: https://github.com/gchq/CyberChef/pull/1242
[#1244]: https://github.com/gchq/CyberChef/pull/1244
[#1313]: https://github.com/gchq/CyberChef/pull/1313
[#1326]: https://github.com/gchq/CyberChef/pull/1326
[#1326]: https://github.com/gchq/CyberChef/pull/1326
+2 -1
View File
@@ -217,7 +217,8 @@ module.exports = function (grunt) {
client: {
logging: "error",
overlay: true
}
},
hot: "only"
},
plugins: [
new webpack.DefinePlugin(BUILD_CONSTANTS),
+3 -2
View File
@@ -10,11 +10,12 @@
"start_process": true,
"server_path": "./node_modules/.bin/chromedriver",
"port": 9515,
"log_path": false
"log_path": "tests/browser/output"
},
"desiredCapabilities": {
"browserName": "chrome"
}
},
"enable_fail_fast": true
},
"dev": {
+64 -9
View File
@@ -1,12 +1,12 @@
{
"name": "cyberchef",
"version": "9.37.0",
"version": "9.38.2",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "cyberchef",
"version": "9.37.0",
"version": "9.38.2",
"hasInstallScript": true,
"license": "Apache-2.0",
"dependencies": {
@@ -98,7 +98,7 @@
"autoprefixer": "^10.4.4",
"babel-loader": "^8.2.4",
"babel-plugin-dynamic-import-node": "^2.3.3",
"chromedriver": "^99.0.0",
"chromedriver": "^101.0.0",
"cli-progress": "^3.10.0",
"colors": "^1.4.0",
"copy-webpack-plugin": "^10.2.4",
@@ -119,6 +119,7 @@
"html-webpack-plugin": "^5.5.0",
"imports-loader": "^3.1.1",
"mini-css-extract-plugin": "2.6.0",
"modify-source-webpack-plugin": "^3.0.0",
"nightwatch": "^2.0.10",
"postcss": "^8.4.12",
"postcss-css-variables": "^0.18.0",
@@ -4467,9 +4468,9 @@
}
},
"node_modules/chromedriver": {
"version": "99.0.0",
"resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-99.0.0.tgz",
"integrity": "sha512-pyB+5LuyZdb7EBPL3i5D5yucZUD+SlkdiUtmpjaEnLd9zAXp+SvD/hP5xF4l/ZmWvUo/1ZLxAI1YBdhazGTpgA==",
"version": "101.0.0",
"resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-101.0.0.tgz",
"integrity": "sha512-LkkWxy6KM/0YdJS8qBeg5vfkTZTRamhBfOttb4oic4echDgWvCU1E8QcBbUBOHqZpSrYMyi7WMKmKMhXFUaZ+w==",
"dev": true,
"hasInstallScript": true,
"dependencies": {
@@ -10740,6 +10741,37 @@
"url": "https://github.com/chalk/supports-color?sponsor=1"
}
},
"node_modules/modify-source-webpack-plugin": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/modify-source-webpack-plugin/-/modify-source-webpack-plugin-3.0.0.tgz",
"integrity": "sha512-m2g6QEittzzcde0PhgQtOwRywjqo8Q+vMLHbNoH2JDEFE/AlTBWvtNQrp17xbqDUXIueLljm4bhE5OninatHYw==",
"dev": true,
"dependencies": {
"loader-utils": "^2.0.0",
"schema-utils": "^3.0.0"
},
"peerDependencies": {
"webpack": "^4.37.0 || ^5.0.0"
}
},
"node_modules/modify-source-webpack-plugin/node_modules/schema-utils": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
"integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
"dev": true,
"dependencies": {
"@types/json-schema": "^7.0.8",
"ajv": "^6.12.5",
"ajv-keywords": "^3.5.2"
},
"engines": {
"node": ">= 10.13.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/webpack"
}
},
"node_modules/moment": {
"version": "2.29.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
@@ -19171,9 +19203,9 @@
"dev": true
},
"chromedriver": {
"version": "99.0.0",
"resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-99.0.0.tgz",
"integrity": "sha512-pyB+5LuyZdb7EBPL3i5D5yucZUD+SlkdiUtmpjaEnLd9zAXp+SvD/hP5xF4l/ZmWvUo/1ZLxAI1YBdhazGTpgA==",
"version": "101.0.0",
"resolved": "https://registry.npmjs.org/chromedriver/-/chromedriver-101.0.0.tgz",
"integrity": "sha512-LkkWxy6KM/0YdJS8qBeg5vfkTZTRamhBfOttb4oic4echDgWvCU1E8QcBbUBOHqZpSrYMyi7WMKmKMhXFUaZ+w==",
"dev": true,
"requires": {
"@testim/chrome-version": "^1.1.2",
@@ -24019,6 +24051,29 @@
}
}
},
"modify-source-webpack-plugin": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/modify-source-webpack-plugin/-/modify-source-webpack-plugin-3.0.0.tgz",
"integrity": "sha512-m2g6QEittzzcde0PhgQtOwRywjqo8Q+vMLHbNoH2JDEFE/AlTBWvtNQrp17xbqDUXIueLljm4bhE5OninatHYw==",
"dev": true,
"requires": {
"loader-utils": "^2.0.0",
"schema-utils": "^3.0.0"
},
"dependencies": {
"schema-utils": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz",
"integrity": "sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==",
"dev": true,
"requires": {
"@types/json-schema": "^7.0.8",
"ajv": "^6.12.5",
"ajv-keywords": "^3.5.2"
}
}
}
},
"moment": {
"version": "2.29.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz",
+4 -2
View File
@@ -1,6 +1,6 @@
{
"name": "cyberchef",
"version": "9.37.0",
"version": "9.38.2",
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
"author": "n1474335 <n1474335@gmail.com>",
"homepage": "https://gchq.github.io/CyberChef",
@@ -48,7 +48,7 @@
"autoprefixer": "^10.4.4",
"babel-loader": "^8.2.4",
"babel-plugin-dynamic-import-node": "^2.3.3",
"chromedriver": "^99.0.0",
"chromedriver": "^101.0.0",
"cli-progress": "^3.10.0",
"colors": "^1.4.0",
"copy-webpack-plugin": "^10.2.4",
@@ -69,6 +69,7 @@
"html-webpack-plugin": "^5.5.0",
"imports-loader": "^3.1.1",
"mini-css-extract-plugin": "2.6.0",
"modify-source-webpack-plugin": "^3.0.0",
"nightwatch": "^2.0.10",
"postcss": "^8.4.12",
"postcss-css-variables": "^0.18.0",
@@ -174,6 +175,7 @@
"lint": "npx grunt lint",
"postinstall": "npx grunt exec:fixCryptoApiImports",
"newop": "node --experimental-modules --experimental-json-modules src/core/config/scripts/newOperation.mjs",
"minor": "node --experimental-modules --experimental-json-modules src/core/config/scripts/newMinorVersion.mjs",
"getheapsize": "node -e 'console.log(`node heap limit = ${require(\"v8\").getHeapStatistics().heap_size_limit / (1024 * 1024)} Mb`)'",
"setheapsize": "export NODE_OPTIONS=--max_old_space_size=2048"
}
+2 -2
View File
@@ -723,8 +723,8 @@ class Utils {
}
if (removeScriptAndStyle) {
htmlStr = recursiveRemove(/<script[^>]*>.*?<\/script>/gi, htmlStr);
htmlStr = recursiveRemove(/<style[^>]*>.*?<\/style>/gi, htmlStr);
htmlStr = recursiveRemove(/<script[^>]*>.*?<\/script[^>]*>/gi, htmlStr);
htmlStr = recursiveRemove(/<style[^>]*>.*?<\/style[^>]*>/gi, htmlStr);
}
return htmlStr.replace(/<[^>]+>/g, "");
}
+1
View File
@@ -190,6 +190,7 @@
"Parse IP range",
"Parse IPv6 address",
"Parse IPv4 header",
"Parse TCP",
"Parse UDP",
"Parse SSH Host Key",
"Parse URI",
+144
View File
@@ -0,0 +1,144 @@
/**
* This script updates the CHANGELOG when a new minor version is created.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2022
* @license Apache-2.0
*/
/* eslint no-console: ["off"] */
import prompt from "prompt";
import colors from "colors";
import path from "path";
import fs from "fs";
import process from "process";
const dir = path.join(process.cwd() + "/src/core/config/");
if (!fs.existsSync(dir)) {
console.log("\nCWD: " + process.cwd());
console.log("Error: newMinorVersion.mjs should be run from the project root");
console.log("Example> node --experimental-modules src/core/config/scripts/newMinorVersion.mjs");
process.exit(1);
}
let changelogData = fs.readFileSync(path.join(process.cwd(), "CHANGELOG.md"), "utf8");
const lastVersion = changelogData.match(/## Details\s+### \[(\d+)\.(\d+)\.(\d+)\]/);
const newVersion = [
parseInt(lastVersion[1], 10),
parseInt(lastVersion[2], 10) + 1,
0
];
let knownContributors = changelogData.match(/^\[@([^\]]+)\]/gm);
knownContributors = knownContributors.map(c => c.slice(2, -1));
const date = (new Date()).toISOString().split("T")[0];
const schema = {
properties: {
message: {
description: "A short but descriptive summary of a feature in this version",
example: "Added 'Op name' operation",
prompt: "Feature description",
type: "string",
required: true,
},
author: {
description: "The author of the feature (only one supported, edit manually to add more)",
example: "n1474335",
prompt: "Author",
type: "string",
default: "n1474335"
},
id: {
description: "The PR number or full commit hash for this feature.",
example: "1200",
prompt: "Pull request or commit ID",
type: "string"
},
another: {
description: "y/n",
example: "y",
prompt: "Add another feature?",
type: "string",
pattern: /^[yn]$/,
}
}
};
// Build schema
for (const prop in schema.properties) {
const p = schema.properties[prop];
p.description = "\n" + colors.white(p.description) + colors.cyan("\nExample: " + p.example) + "\n" + colors.green(p.prompt);
}
prompt.message = "";
prompt.delimiter = ":".green;
const features = [];
const authors = [];
const prIDs = [];
const commitIDs = [];
prompt.start();
const getFeature = function() {
prompt.get(schema, (err, result) => {
if (err) {
console.log("\nExiting script.");
process.exit(0);
}
features.push(result);
if (result.another === "y") {
getFeature();
} else {
let message = `### [${newVersion[0]}.${newVersion[1]}.${newVersion[2]}] - ${date}\n`;
features.forEach(feature => {
const id = feature.id.length > 10 ? feature.id.slice(0, 7) : "#" + feature.id;
message += `- ${feature.message} [@${feature.author}] | [${id}]\n`;
if (!knownContributors.includes(feature.author)) {
authors.push(`[@${feature.author}]: https://github.com/${feature.author}`);
}
if (feature.id.length > 10) {
commitIDs.push(`[${id}]: https://github.com/gchq/CyberChef/commit/${feature.id}`);
} else {
prIDs.push(`[#${feature.id}]: https://github.com/gchq/CyberChef/pull/${feature.id}`);
}
});
// Message
changelogData = changelogData.replace(/## Details\n\n/, "## Details\n\n" + message + "\n");
// Tag
const newTag = `[${newVersion[0]}.${newVersion[1]}.${newVersion[2]}]: https://github.com/gchq/CyberChef/releases/tag/v${newVersion[0]}.${newVersion[1]}.${newVersion[2]}\n`;
changelogData = changelogData.replace(/\n\n(\[\d+\.\d+\.\d+\]: https)/, "\n\n" + newTag + "$1");
// Author
authors.forEach(author => {
changelogData = changelogData.replace(/(\n\[@[^\]]+\]: https:\/\/github\.com\/[^\n]+\n)\n/, "$1" + author + "\n\n");
});
// Commit IDs
commitIDs.forEach(commitID => {
changelogData = changelogData.replace(/(\n\[[^\].]+\]: https:\/\/github.com\/gchq\/CyberChef\/commit\/[^\n]+\n)\n/, "$1" + commitID + "\n\n");
});
// PR IDs
prIDs.forEach(prID => {
changelogData = changelogData.replace(/(\n\[#[^\]]+\]: https:\/\/github.com\/gchq\/CyberChef\/pull\/[^\n]+\n)\n/, "$1" + prID + "\n\n");
});
fs.writeFileSync(path.join(process.cwd(), "CHANGELOG.md"), changelogData);
console.log("Written CHANGELOG.md");
}
});
};
getFeature();
+9 -5
View File
@@ -13,7 +13,7 @@ import OperationError from "../errors/OperationError.mjs";
/**
* Convert a byte array into a binary string.
*
* @param {Uint8Array|byteArray} data
* @param {Uint8Array|byteArray|number} data
* @param {string} [delim="Space"]
* @param {number} [padding=8]
* @returns {string}
@@ -26,13 +26,17 @@ import OperationError from "../errors/OperationError.mjs";
* toBinary([10,20,30], ":");
*/
export function toBinary(data, delim="Space", padding=8) {
if (!data) return "";
delim = Utils.charRep(delim);
let output = "";
for (let i = 0; i < data.length; i++) {
output += data[i].toString(2).padStart(padding, "0") + delim;
if (data.length) { // array
for (let i = 0; i < data.length; i++) {
output += data[i].toString(2).padStart(padding, "0") + delim;
}
} else if (typeof data === "number") { // Single value
return data.toString(2).padStart(padding, "0");
} else {
return "";
}
if (delim.length) {
+16 -11
View File
@@ -12,15 +12,15 @@
*
* @param {string} input
* @param {RegExp} searchRegex
* @param {RegExp} removeRegex - A regular expression defining results to remove from the
* @param {RegExp} [removeRegex=null] - A regular expression defining results to remove from the
* final list
* @param {boolean} includeTotal - Whether or not to include the total number of results
* @param {Function} [sortBy=null] - The sorting comparison function to apply
* @param {boolean} [unique=false] - Whether to unique the results
* @returns {string}
*/
export function search (input, searchRegex, removeRegex, includeTotal) {
let output = "",
total = 0,
match;
export function search(input, searchRegex, removeRegex=null, sortBy=null, unique=false) {
let results = [];
let match;
while ((match = searchRegex.exec(input))) {
// Moves pointer when an empty string is matched (prevents infinite loop)
@@ -30,14 +30,19 @@ export function search (input, searchRegex, removeRegex, includeTotal) {
if (removeRegex && removeRegex.test(match[0]))
continue;
total++;
output += match[0] + "\n";
results.push(match[0]);
}
if (includeTotal)
output = "Total found: " + total + "\n\n" + output;
if (sortBy) {
results = results.sort(sortBy);
}
return output;
if (unique) {
results = results.unique();
}
return results;
}
+12 -12
View File
@@ -3778,8 +3778,8 @@ function parseDEFLATE(stream) {
while (!finalBlock) {
// Read header
finalBlock = stream.readBits(1);
const blockType = stream.readBits(2);
finalBlock = stream.readBits(1, "le");
const blockType = stream.readBits(2, "le");
if (blockType === 0) {
/* No compression */
@@ -3798,16 +3798,16 @@ function parseDEFLATE(stream) {
/* Dynamic Huffman */
// Read the number of liternal and length codes
const hlit = stream.readBits(5) + 257;
const hlit = stream.readBits(5, "le") + 257;
// Read the number of distance codes
const hdist = stream.readBits(5) + 1;
const hdist = stream.readBits(5, "le") + 1;
// Read the number of code lengths
const hclen = stream.readBits(4) + 4;
const hclen = stream.readBits(4, "le") + 4;
// Parse code lengths
const codeLengths = new Uint8Array(huffmanOrder.length);
for (let i = 0; i < hclen; i++) {
codeLengths[huffmanOrder[i]] = stream.readBits(3);
codeLengths[huffmanOrder[i]] = stream.readBits(3, "le");
}
// Parse length table
@@ -3819,16 +3819,16 @@ function parseDEFLATE(stream) {
code = readHuffmanCode(stream, codeLengthsTable);
switch (code) {
case 16:
repeat = 3 + stream.readBits(2);
repeat = 3 + stream.readBits(2, "le");
while (repeat--) lengthTable[i++] = prev;
break;
case 17:
repeat = 3 + stream.readBits(3);
repeat = 3 + stream.readBits(3, "le");
while (repeat--) lengthTable[i++] = 0;
prev = 0;
break;
case 18:
repeat = 11 + stream.readBits(7);
repeat = 11 + stream.readBits(7, "le");
while (repeat--) lengthTable[i++] = 0;
prev = 0;
break;
@@ -3886,11 +3886,11 @@ function parseHuffmanBlock(stream, litTab, distTab) {
if (code < 256) continue;
// Length code
stream.readBits(lengthExtraTable[code - 257]);
stream.readBits(lengthExtraTable[code - 257], "le");
// Dist code
code = readHuffmanCode(stream, distTab);
stream.readBits(distanceExtraTable[code]);
stream.readBits(distanceExtraTable[code], "le");
}
}
@@ -3948,7 +3948,7 @@ function readHuffmanCode(stream, table) {
const [codeTable, maxCodeLength] = table;
// Read max length
const bitsBuf = stream.readBits(maxCodeLength);
const bitsBuf = stream.readBits(maxCodeLength, "le");
const codeWithLength = codeTable[bitsBuf & ((1 << maxCodeLength) - 1)];
const codeLength = codeWithLength >>> 16;
+47
View File
@@ -0,0 +1,47 @@
/**
* Protocol parsing functions.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2022
* @license Apache-2.0
*/
import BigNumber from "bignumber.js";
import {toHexFast} from "../lib/Hex.mjs";
/**
* Recursively displays a JSON object as an HTML table
*
* @param {Object} obj
* @returns string
*/
export function objToTable(obj, nested=false) {
let html = `<table
class='table table-sm table-nonfluid ${nested ? "mb-0 table-borderless" : "table-bordered"}'
style='table-layout: fixed; ${nested ? "margin: -1px !important;" : ""}'>`;
if (!nested)
html += `<tr>
<th>Field</th>
<th>Value</th>
</tr>`;
for (const key in obj) {
html += `<tr><td style='word-wrap: break-word'>${key}</td>`;
if (typeof obj[key] === "object")
html += `<td style='padding: 0'>${objToTable(obj[key], true)}</td>`;
else
html += `<td>${obj[key]}</td>`;
html += "</tr>";
}
html += "</table>";
return html;
}
/**
* Converts bytes into a BigNumber string
* @param {Uint8Array} bs
* @returns {string}
*/
export function bytesToLargeNumber(bs) {
return BigNumber(toHexFast(bs), 16).toString();
}
+105
View File
@@ -0,0 +1,105 @@
/**
* Sorting functions
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2022
* @license Apache-2.0
*
*/
/**
* Comparison operation for sorting of strings ignoring case.
*
* @param {string} a
* @param {string} b
* @returns {number}
*/
export function caseInsensitiveSort(a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
}
/**
* Comparison operation for sorting of IPv4 addresses.
*
* @param {string} a
* @param {string} b
* @returns {number}
*/
export function ipSort(a, b) {
let a_ = a.split("."),
b_ = b.split(".");
a_ = a_[0] * 0x1000000 + a_[1] * 0x10000 + a_[2] * 0x100 + a_[3] * 1;
b_ = b_[0] * 0x1000000 + b_[1] * 0x10000 + b_[2] * 0x100 + b_[3] * 1;
if (isNaN(a_) && !isNaN(b_)) return 1;
if (!isNaN(a_) && isNaN(b_)) return -1;
if (isNaN(a_) && isNaN(b_)) return a.localeCompare(b);
return a_ - b_;
}
/**
* Comparison operation for sorting of numeric values.
*
* @author Chris van Marle
* @param {string} a
* @param {string} b
* @returns {number}
*/
export function numericSort(a, b) {
const a_ = a.split(/([^\d]+)/),
b_ = b.split(/([^\d]+)/);
for (let i = 0; i < a_.length && i < b.length; ++i) {
if (isNaN(a_[i]) && !isNaN(b_[i])) return 1; // Numbers after non-numbers
if (!isNaN(a_[i]) && isNaN(b_[i])) return -1;
if (isNaN(a_[i]) && isNaN(b_[i])) {
const ret = a_[i].localeCompare(b_[i]); // Compare strings
if (ret !== 0) return ret;
}
if (!isNaN(a_[i]) && !isNaN(b_[i])) { // Compare numbers
if (a_[i] - b_[i] !== 0) return a_[i] - b_[i];
}
}
return a.localeCompare(b);
}
/**
* Comparison operation for sorting of hexadecimal values.
*
* @author Chris van Marle
* @param {string} a
* @param {string} b
* @returns {number}
*/
export function hexadecimalSort(a, b) {
let a_ = a.split(/([^\da-f]+)/i),
b_ = b.split(/([^\da-f]+)/i);
a_ = a_.map(v => {
const t = parseInt(v, 16);
return isNaN(t) ? v : t;
});
b_ = b_.map(v => {
const t = parseInt(v, 16);
return isNaN(t) ? v : t;
});
for (let i = 0; i < a_.length && i < b.length; ++i) {
if (isNaN(a_[i]) && !isNaN(b_[i])) return 1; // Numbers after non-numbers
if (!isNaN(a_[i]) && isNaN(b_[i])) return -1;
if (isNaN(a_[i]) && isNaN(b_[i])) {
const ret = a_[i].localeCompare(b_[i]); // Compare strings
if (ret !== 0) return ret;
}
if (!isNaN(a_[i]) && !isNaN(b_[i])) { // Compare numbers
if (a_[i] - b_[i] !== 0) return a_[i] - b_[i];
}
}
return a.localeCompare(b);
}
+22 -12
View File
@@ -27,15 +27,17 @@ export default class Stream {
}
/**
* Get a number of bytes from the current position.
* Get a number of bytes from the current position, or all remaining bytes.
*
* @param {number} numBytes
* @param {number} [numBytes=null]
* @returns {Uint8Array}
*/
getBytes(numBytes) {
getBytes(numBytes=null) {
if (this.position > this.length) return undefined;
const newPosition = this.position + numBytes;
const newPosition = numBytes !== null ?
this.position + numBytes :
this.length;
const bytes = this.bytes.slice(this.position, newPosition);
this.position = newPosition;
this.bitPos = 0;
@@ -91,34 +93,40 @@ export default class Stream {
}
/**
* Reads a number of bits from the buffer.
*
* @TODO Add endianness
* Reads a number of bits from the buffer in big or little endian.
*
* @param {number} numBits
* @param {string} [endianness="be"]
* @returns {number}
*/
readBits(numBits) {
readBits(numBits, endianness="be") {
if (this.position > this.length) return undefined;
let bitBuf = 0,
bitBufLen = 0;
// Add remaining bits from current byte
bitBuf = (this.bytes[this.position++] & bitMask(this.bitPos)) >>> this.bitPos;
bitBuf = this.bytes[this.position++] & bitMask(this.bitPos);
if (endianness !== "be") bitBuf >>>= this.bitPos;
bitBufLen = 8 - this.bitPos;
this.bitPos = 0;
// Not enough bits yet
while (bitBufLen < numBits) {
bitBuf |= this.bytes[this.position++] << bitBufLen;
if (endianness === "be")
bitBuf = (bitBuf << bitBufLen) | this.bytes[this.position++];
else
bitBuf |= this.bytes[this.position++] << bitBufLen;
bitBufLen += 8;
}
// Reverse back to numBits
if (bitBufLen > numBits) {
const excess = bitBufLen - numBits;
bitBuf &= (1 << numBits) - 1;
if (endianness === "be")
bitBuf >>>= excess;
else
bitBuf &= (1 << numBits) - 1;
bitBufLen -= excess;
this.position--;
this.bitPos = 8 - excess;
@@ -133,7 +141,9 @@ export default class Stream {
* @returns {number} The bit mask
*/
function bitMask(bitPos) {
return 256 - (1 << bitPos);
return endianness === "be" ?
(1 << (8 - bitPos)) - 1 :
256 - (1 << bitPos);
}
}
+7 -1
View File
@@ -44,7 +44,13 @@ class ExtractDates extends Operation {
date3 = "(?:0[1-9]|1[012])[- /.](?:0[1-9]|[12][0-9]|3[01])[- /.](?:19|20)\\d\\d", // mm/dd/yyyy
regex = new RegExp(date1 + "|" + date2 + "|" + date3, "ig");
return search(input, regex, null, displayTotal);
const results = search(input, regex);
if (displayTotal) {
return `Total found: ${results.length}\n\n${results.join("\n")}`;
} else {
return results.join("\n");
}
}
}
+29 -5
View File
@@ -6,6 +6,7 @@
import Operation from "../Operation.mjs";
import { search, DOMAIN_REGEX } from "../lib/Extract.mjs";
import { caseInsensitiveSort } from "../lib/Sort.mjs";
/**
* Extract domains operation
@@ -25,9 +26,19 @@ class ExtractDomains extends Operation {
this.outputType = "string";
this.args = [
{
"name": "Display total",
"type": "boolean",
"value": true
name: "Display total",
type: "boolean",
value: false
},
{
name: "Sort",
type: "boolean",
value: false
},
{
name: "Unique",
type: "boolean",
value: false
}
];
}
@@ -38,8 +49,21 @@ class ExtractDomains extends Operation {
* @returns {string}
*/
run(input, args) {
const displayTotal = args[0];
return search(input, DOMAIN_REGEX, null, displayTotal);
const [displayTotal, sort, unique] = args;
const results = search(
input,
DOMAIN_REGEX,
null,
sort ? caseInsensitiveSort : null,
unique
);
if (displayTotal) {
return `Total found: ${results.length}\n\n${results.join("\n")}`;
} else {
return results.join("\n");
}
}
}
+29 -5
View File
@@ -6,6 +6,7 @@
import Operation from "../Operation.mjs";
import { search } from "../lib/Extract.mjs";
import { caseInsensitiveSort } from "../lib/Sort.mjs";
/**
* Extract email addresses operation
@@ -25,9 +26,19 @@ class ExtractEmailAddresses extends Operation {
this.outputType = "string";
this.args = [
{
"name": "Display total",
"type": "boolean",
"value": false
name: "Display total",
type: "boolean",
value: false
},
{
name: "Sort",
type: "boolean",
value: false
},
{
name: "Unique",
type: "boolean",
value: false
}
];
}
@@ -38,10 +49,23 @@ class ExtractEmailAddresses extends Operation {
* @returns {string}
*/
run(input, args) {
const displayTotal = args[0],
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;
return search(input, regex, null, displayTotal);
const results = search(
input,
regex,
null,
sort ? caseInsensitiveSort : null,
unique
);
if (displayTotal) {
return `Total found: ${results.length}\n\n${results.join("\n")}`;
} else {
return results.join("\n");
}
}
}
+38 -14
View File
@@ -6,6 +6,7 @@
import Operation from "../Operation.mjs";
import { search } from "../lib/Extract.mjs";
import { caseInsensitiveSort } from "../lib/Sort.mjs";
/**
* Extract file paths operation
@@ -25,19 +26,29 @@ class ExtractFilePaths extends Operation {
this.outputType = "string";
this.args = [
{
"name": "Windows",
"type": "boolean",
"value": true
name: "Windows",
type: "boolean",
value: true
},
{
"name": "UNIX",
"type": "boolean",
"value": true
name: "UNIX",
type: "boolean",
value: true
},
{
"name": "Display total",
"type": "boolean",
"value": false
name: "Display total",
type: "boolean",
value: false
},
{
name: "Sort",
type: "boolean",
value: false
},
{
name: "Unique",
type: "boolean",
value: false
}
];
}
@@ -48,7 +59,7 @@ class ExtractFilePaths extends Operation {
* @returns {string}
*/
run(input, args) {
const [includeWinPath, includeUnixPath, displayTotal] = args,
const [includeWinPath, includeUnixPath, displayTotal, sort, unique] = args,
winDrive = "[A-Z]:\\\\",
winName = "[A-Z\\d][A-Z\\d\\- '_\\(\\)~]{0,61}",
winExt = "[A-Z\\d]{1,6}",
@@ -65,12 +76,25 @@ class ExtractFilePaths extends Operation {
filePaths = unixPath;
}
if (filePaths) {
const regex = new RegExp(filePaths, "ig");
return search(input, regex, null, displayTotal);
} else {
if (!filePaths) {
return "";
}
const regex = new RegExp(filePaths, "ig");
const results = search(
input,
regex,
null,
sort ? caseInsensitiveSort : null,
unique
);
if (displayTotal) {
return `Total found: ${results.length}\n\n${results.join("\n")}`;
} else {
return results.join("\n");
}
}
}
+44 -27
View File
@@ -6,6 +6,7 @@
import Operation from "../Operation.mjs";
import { search } from "../lib/Extract.mjs";
import { ipSort } from "../lib/Sort.mjs";
/**
* Extract IP addresses operation
@@ -25,24 +26,34 @@ class ExtractIPAddresses extends Operation {
this.outputType = "string";
this.args = [
{
"name": "IPv4",
"type": "boolean",
"value": true
name: "IPv4",
type: "boolean",
value: true
},
{
"name": "IPv6",
"type": "boolean",
"value": false
name: "IPv6",
type: "boolean",
value: false
},
{
"name": "Remove local IPv4 addresses",
"type": "boolean",
"value": false
name: "Remove local IPv4 addresses",
type: "boolean",
value: false
},
{
"name": "Display total",
"type": "boolean",
"value": false
name: "Display total",
type: "boolean",
value: false
},
{
name: "Sort",
type: "boolean",
value: false
},
{
name: "Unique",
type: "boolean",
value: false
}
];
}
@@ -53,7 +64,7 @@ class ExtractIPAddresses extends Operation {
* @returns {string}
*/
run(input, args) {
const [includeIpv4, includeIpv6, removeLocal, displayTotal] = args,
const [includeIpv4, includeIpv6, removeLocal, displayTotal, sort, unique] = args,
ipv4 = "(?:(?:\\d|[01]?\\d\\d|2[0-4]\\d|25[0-5])\\.){3}(?:25[0-5]|2[0-4]\\d|[01]?\\d\\d|\\d)(?:\\/\\d{1,2})?",
ipv6 = "((?=.*::)(?!.*::.+::)(::)?([\\dA-F]{1,4}:(:|\\b)|){5}|([\\dA-F]{1,4}:){6})((([\\dA-F]{1,4}((?!\\3)::|:\\b|(?![\\dA-F])))|(?!\\2\\3)){2}|(((2[0-4]|1\\d|[1-9])?\\d|25[0-5])\\.?\\b){4})";
let ips = "";
@@ -66,23 +77,29 @@ class ExtractIPAddresses extends Operation {
ips = ipv6;
}
if (ips) {
const regex = new RegExp(ips, "ig");
if (!ips) return "";
if (removeLocal) {
const ten = "10\\..+",
oneninetwo = "192\\.168\\..+",
oneseventwo = "172\\.(?:1[6-9]|2\\d|3[01])\\..+",
onetwoseven = "127\\..+",
removeRegex = new RegExp("^(?:" + ten + "|" + oneninetwo +
"|" + oneseventwo + "|" + onetwoseven + ")");
const regex = new RegExp(ips, "ig");
return search(input, regex, removeRegex, displayTotal);
} else {
return search(input, regex, null, displayTotal);
}
const ten = "10\\..+",
oneninetwo = "192\\.168\\..+",
oneseventwo = "172\\.(?:1[6-9]|2\\d|3[01])\\..+",
onetwoseven = "127\\..+",
removeRegex = new RegExp("^(?:" + ten + "|" + oneninetwo +
"|" + oneseventwo + "|" + onetwoseven + ")");
const results = search(
input,
regex,
removeLocal ? removeRegex : null,
sort ? ipSort : null,
unique
);
if (displayTotal) {
return `Total found: ${results.length}\n\n${results.join("\n")}`;
} else {
return "";
return results.join("\n");
}
}
+28 -6
View File
@@ -6,6 +6,7 @@
import Operation from "../Operation.mjs";
import { search } from "../lib/Extract.mjs";
import { hexadecimalSort } from "../lib/Sort.mjs";
/**
* Extract MAC addresses operation
@@ -25,9 +26,19 @@ class ExtractMACAddresses extends Operation {
this.outputType = "string";
this.args = [
{
"name": "Display total",
"type": "boolean",
"value": false
name: "Display total",
type: "boolean",
value: false
},
{
name: "Sort",
type: "boolean",
value: false
},
{
name: "Unique",
type: "boolean",
value: false
}
];
}
@@ -38,10 +49,21 @@ class ExtractMACAddresses extends Operation {
* @returns {string}
*/
run(input, args) {
const displayTotal = args[0],
regex = /[A-F\d]{2}(?:[:-][A-F\d]{2}){5}/ig;
const [displayTotal, sort, unique] = args,
regex = /[A-F\d]{2}(?:[:-][A-F\d]{2}){5}/ig,
results = search(
input,
regex,
null,
sort ? hexadecimalSort : null,
unique
);
return search(input, regex, null, displayTotal);
if (displayTotal) {
return `Total found: ${results.length}\n\n${results.join("\n")}`;
} else {
return results.join("\n");
}
}
}
+28 -5
View File
@@ -6,6 +6,7 @@
import Operation from "../Operation.mjs";
import { search, URL_REGEX } from "../lib/Extract.mjs";
import { caseInsensitiveSort } from "../lib/Sort.mjs";
/**
* Extract URLs operation
@@ -25,9 +26,19 @@ class ExtractURLs extends Operation {
this.outputType = "string";
this.args = [
{
"name": "Display total",
"type": "boolean",
"value": false
name: "Display total",
type: "boolean",
value: false
},
{
name: "Sort",
type: "boolean",
value: false
},
{
name: "Unique",
type: "boolean",
value: false
}
];
}
@@ -38,8 +49,20 @@ class ExtractURLs extends Operation {
* @returns {string}
*/
run(input, args) {
const displayTotal = args[0];
return search(input, URL_REGEX, null, displayTotal);
const [displayTotal, sort, unique] = args;
const results = search(
input,
URL_REGEX,
null,
sort ? caseInsensitiveSort : null,
unique
);
if (displayTotal) {
return `Total found: ${results.length}\n\n${results.join("\n")}`;
} else {
return results.join("\n");
}
}
}
+245
View File
@@ -0,0 +1,245 @@
/**
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2022
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import Stream from "../lib/Stream.mjs";
import {toHexFast, fromHex} from "../lib/Hex.mjs";
import {toBinary} from "../lib/Binary.mjs";
import {objToTable, bytesToLargeNumber} from "../lib/Protocol.mjs";
import Utils from "../Utils.mjs";
import OperationError from "../errors/OperationError.mjs";
import BigNumber from "bignumber.js";
/**
* Parse TCP operation
*/
class ParseTCP extends Operation {
/**
* ParseTCP constructor
*/
constructor() {
super();
this.name = "Parse TCP";
this.module = "Default";
this.description = "Parses a TCP header and payload (if present).";
this.infoURL = "https://wikipedia.org/wiki/Transmission_Control_Protocol";
this.inputType = "string";
this.outputType = "json";
this.presentType = "html";
this.args = [
{
name: "Input format",
type: "option",
value: ["Hex", "Raw"]
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {html}
*/
run(input, args) {
const format = args[0];
if (format === "Hex") {
input = fromHex(input);
} else if (format === "Raw") {
input = Utils.strToArrayBuffer(input);
} else {
throw new OperationError("Unrecognised input format.");
}
const s = new Stream(new Uint8Array(input));
if (s.length < 20) {
throw new OperationError("Need at least 20 bytes for a TCP Header");
}
// Parse Header
const TCPPacket = {
"Source port": s.readInt(2),
"Destination port": s.readInt(2),
"Sequence number": bytesToLargeNumber(s.getBytes(4)),
"Acknowledgement number": s.readInt(4),
"Data offset": s.readBits(4),
"Flags": {
"Reserved": toBinary(s.readBits(3), "", 3),
"NS": s.readBits(1),
"CWR": s.readBits(1),
"ECE": s.readBits(1),
"URG": s.readBits(1),
"ACK": s.readBits(1),
"PSH": s.readBits(1),
"RST": s.readBits(1),
"SYN": s.readBits(1),
"FIN": s.readBits(1),
},
"Window size": s.readInt(2),
"Checksum": "0x" + toHexFast(s.getBytes(2)),
"Urgent pointer": "0x" + toHexFast(s.getBytes(2))
};
// Parse options if present
let windowScaleShift = 0;
if (TCPPacket["Data offset"] > 5) {
let remainingLength = TCPPacket["Data offset"] * 4 - 20;
const options = {};
while (remainingLength > 0) {
const option = {
"Kind": s.readInt(1)
};
let opt = { name: "Reserved", length: true };
if (Object.prototype.hasOwnProperty.call(TCP_OPTION_KIND_LOOKUP, option.Kind)) {
opt = TCP_OPTION_KIND_LOOKUP[option.Kind];
}
// Add Length and Value fields
if (opt.length) {
option.Length = s.readInt(1);
if (option.Length > 2) {
if (Object.prototype.hasOwnProperty.call(opt, "parser")) {
option.Value = opt.parser(s.getBytes(option.Length - 2));
} else {
option.Value = option.Length <= 6 ?
s.readInt(option.Length - 2):
"0x" + toHexFast(s.getBytes(option.Length - 2));
}
// Store Window Scale shift for later
if (option.Kind === 3 && option.Value) {
windowScaleShift = option.Value["Shift count"];
}
}
}
options[opt.name] = option;
const length = option.Length || 1;
remainingLength -= length;
}
TCPPacket.Options = options;
}
if (s.hasMore()) {
TCPPacket.Data = "0x" + toHexFast(s.getBytes());
}
// Improve values
TCPPacket["Data offset"] = `${TCPPacket["Data offset"]} (${TCPPacket["Data offset"] * 4} bytes)`;
const trueWndSize = BigNumber(TCPPacket["Window size"]).multipliedBy(BigNumber(2).pow(BigNumber(windowScaleShift)));
TCPPacket["Window size"] = `${TCPPacket["Window size"]} (Scaled: ${trueWndSize})`;
return TCPPacket;
}
/**
* Displays the TCP Packet in a tabular style
* @param {Object} data
* @returns {html}
*/
present(data) {
return objToTable(data);
}
}
// Taken from https://www.iana.org/assignments/tcp-parameters/tcp-parameters.xhtml
// on 2022-05-30
const TCP_OPTION_KIND_LOOKUP = {
0: { name: "End of Option List", length: false },
1: { name: "No-Operation", length: false },
2: { name: "Maximum Segment Size", length: true },
3: { name: "Window Scale", length: true, parser: windowScaleParser },
4: { name: "SACK Permitted", length: true },
5: { name: "SACK", length: true },
6: { name: "Echo (obsoleted by option 8)", length: true },
7: { name: "Echo Reply (obsoleted by option 8)", length: true },
8: { name: "Timestamps", length: true, parser: tcpTimestampParser },
9: { name: "Partial Order Connection Permitted (obsolete)", length: true },
10: { name: "Partial Order Service Profile (obsolete)", length: true },
11: { name: "CC (obsolete)", length: true },
12: { name: "CC.NEW (obsolete)", length: true },
13: { name: "CC.ECHO (obsolete)", length: true },
14: { name: "TCP Alternate Checksum Request (obsolete)", length: true, parser: tcpAlternateChecksumParser },
15: { name: "TCP Alternate Checksum Data (obsolete)", length: true },
16: { name: "Skeeter", length: true },
17: { name: "Bubba", length: true },
18: { name: "Trailer Checksum Option", length: true },
19: { name: "MD5 Signature Option (obsoleted by option 29)", length: true },
20: { name: "SCPS Capabilities", length: true },
21: { name: "Selective Negative Acknowledgements", length: true },
22: { name: "Record Boundaries", length: true },
23: { name: "Corruption experienced", length: true },
24: { name: "SNAP", length: true },
25: { name: "Unassigned (released 2000-12-18)", length: true },
26: { name: "TCP Compression Filter", length: true },
27: { name: "Quick-Start Response", length: true },
28: { name: "User Timeout Option (also, other known unauthorized use)", length: true },
29: { name: "TCP Authentication Option (TCP-AO)", length: true },
30: { name: "Multipath TCP (MPTCP)", length: true },
69: { name: "Encryption Negotiation (TCP-ENO)", length: true },
70: { name: "Reserved (known unauthorized use without proper IANA assignment)", length: true },
76: { name: "Reserved (known unauthorized use without proper IANA assignment)", length: true },
77: { name: "Reserved (known unauthorized use without proper IANA assignment)", length: true },
78: { name: "Reserved (known unauthorized use without proper IANA assignment)", length: true },
253: { name: "RFC3692-style Experiment 1 (also improperly used for shipping products) ", length: true },
254: { name: "RFC3692-style Experiment 2 (also improperly used for shipping products) ", length: true }
};
/**
* Parses the TCP Alternate Checksum Request field
* @param {Uint8Array} data
*/
function tcpAlternateChecksumParser(data) {
const lookup = {
0: "TCP Checksum",
1: "8-bit Fletchers's algorithm",
2: "16-bit Fletchers's algorithm",
3: "Redundant Checksum Avoidance"
}[data[0]];
return `${lookup} (0x${toHexFast(data)})`;
}
/**
* Parses the TCP Timestamp field
* @param {Uint8Array} data
*/
function tcpTimestampParser(data) {
const s = new Stream(data);
if (s.length !== 8)
return `Error: Timestamp field should be 8 bytes long (received 0x${toHexFast(data)})`;
const tsval = bytesToLargeNumber(s.getBytes(4)),
tsecr = bytesToLargeNumber(s.getBytes(4));
return {
"Current Timestamp": tsval,
"Echo Reply": tsecr
};
}
/**
* Parses the Window Scale field
* @param {Uint8Array} data
*/
function windowScaleParser(data) {
if (data.length !== 1)
return `Error: Window Scale should be one byte long (received 0x${toHexFast(data)})`;
return {
"Shift count": data[0],
"Multiplier": 1 << data[0]
};
}
export default ParseTCP;
+29 -24
View File
@@ -6,7 +6,9 @@
import Operation from "../Operation.mjs";
import Stream from "../lib/Stream.mjs";
import {toHex} from "../lib/Hex.mjs";
import {toHexFast, fromHex} from "../lib/Hex.mjs";
import {objToTable} from "../lib/Protocol.mjs";
import Utils from "../Utils.mjs";
import OperationError from "../errors/OperationError.mjs";
/**
@@ -24,58 +26,61 @@ class ParseUDP extends Operation {
this.module = "Default";
this.description = "Parses a UDP header and payload (if present).";
this.infoURL = "https://wikipedia.org/wiki/User_Datagram_Protocol";
this.inputType = "ArrayBuffer";
this.inputType = "string";
this.outputType = "json";
this.presentType = "html";
this.args = [];
this.args = [
{
name: "Input format",
type: "option",
value: ["Hex", "Raw"]
}
];
}
/**
* @param {ArrayBuffer} input
* @param {string} input
* @param {Object[]} args
* @returns {Object}
*/
run(input, args) {
if (input.byteLength < 8) {
throw new OperationError("Need 8 bytes for a UDP Header");
const format = args[0];
if (format === "Hex") {
input = fromHex(input);
} else if (format === "Raw") {
input = Utils.strToArrayBuffer(input);
} else {
throw new OperationError("Unrecognised input format.");
}
const s = new Stream(new Uint8Array(input));
if (s.length < 8) {
throw new OperationError("Need 8 bytes for a UDP Header");
}
// Parse Header
const UDPPacket = {
"Source port": s.readInt(2),
"Destination port": s.readInt(2),
"Length": s.readInt(2),
"Checksum": toHex(s.getBytes(2), "")
"Checksum": "0x" + toHexFast(s.getBytes(2))
};
// Parse data if present
if (s.hasMore()) {
UDPPacket.Data = toHex(s.getBytes(UDPPacket.Length - 8), "");
UDPPacket.Data = "0x" + toHexFast(s.getBytes(UDPPacket.Length - 8));
}
return UDPPacket;
}
/**
* Displays the UDP Packet in a table style
* Displays the UDP Packet in a tabular style
* @param {Object} data
* @returns {html}
*/
present(data) {
const html = [];
html.push("<table class='table table-hover table-sm table-bordered table-nonfluid' style='table-layout: fixed'>");
html.push("<tr>");
html.push("<th>Field</th>");
html.push("<th>Value</th>");
html.push("</tr>");
for (const key in data) {
html.push("<tr>");
html.push("<td style=\"word-wrap:break-word\">" + key + "</td>");
html.push("<td>" + data[key] + "</td>");
html.push("</tr>");
}
html.push("</table>");
return html.join("");
return objToTable(data);
}
}
+2 -2
View File
@@ -43,9 +43,9 @@ class RC4Drop extends Operation {
"value": ["Latin1", "UTF8", "UTF16", "UTF16LE", "UTF16BE", "Hex", "Base64"]
},
{
"name": "Number of bytes to drop",
"name": "Number of dwords to drop",
"type": "number",
"value": 768
"value": 192
}
];
}
+5 -105
View File
@@ -7,6 +7,7 @@
import Operation from "../Operation.mjs";
import Utils from "../Utils.mjs";
import {INPUT_DELIM_OPTIONS} from "../lib/Delim.mjs";
import {caseInsensitiveSort, ipSort, numericSort, hexadecimalSort} from "../lib/Sort.mjs";
/**
* Sort operation
@@ -57,120 +58,19 @@ class Sort extends Operation {
if (order === "Alphabetical (case sensitive)") {
sorted = sorted.sort();
} else if (order === "Alphabetical (case insensitive)") {
sorted = sorted.sort(Sort._caseInsensitiveSort);
sorted = sorted.sort(caseInsensitiveSort);
} else if (order === "IP address") {
sorted = sorted.sort(Sort._ipSort);
sorted = sorted.sort(ipSort);
} else if (order === "Numeric") {
sorted = sorted.sort(Sort._numericSort);
sorted = sorted.sort(numericSort);
} else if (order === "Numeric (hexadecimal)") {
sorted = sorted.sort(Sort._hexadecimalSort);
sorted = sorted.sort(hexadecimalSort);
}
if (sortReverse) sorted.reverse();
return sorted.join(delim);
}
/**
* Comparison operation for sorting of strings ignoring case.
*
* @private
* @param {string} a
* @param {string} b
* @returns {number}
*/
static _caseInsensitiveSort(a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
}
/**
* Comparison operation for sorting of IPv4 addresses.
*
* @private
* @param {string} a
* @param {string} b
* @returns {number}
*/
static _ipSort(a, b) {
let a_ = a.split("."),
b_ = b.split(".");
a_ = a_[0] * 0x1000000 + a_[1] * 0x10000 + a_[2] * 0x100 + a_[3] * 1;
b_ = b_[0] * 0x1000000 + b_[1] * 0x10000 + b_[2] * 0x100 + b_[3] * 1;
if (isNaN(a_) && !isNaN(b_)) return 1;
if (!isNaN(a_) && isNaN(b_)) return -1;
if (isNaN(a_) && isNaN(b_)) return a.localeCompare(b);
return a_ - b_;
}
/**
* Comparison operation for sorting of numeric values.
*
* @author Chris van Marle
* @private
* @param {string} a
* @param {string} b
* @returns {number}
*/
static _numericSort(a, b) {
const a_ = a.split(/([^\d]+)/),
b_ = b.split(/([^\d]+)/);
for (let i = 0; i < a_.length && i < b.length; ++i) {
if (isNaN(a_[i]) && !isNaN(b_[i])) return 1; // Numbers after non-numbers
if (!isNaN(a_[i]) && isNaN(b_[i])) return -1;
if (isNaN(a_[i]) && isNaN(b_[i])) {
const ret = a_[i].localeCompare(b_[i]); // Compare strings
if (ret !== 0) return ret;
}
if (!isNaN(a_[i]) && !isNaN(b_[i])) { // Compare numbers
if (a_[i] - b_[i] !== 0) return a_[i] - b_[i];
}
}
return a.localeCompare(b);
}
/**
* Comparison operation for sorting of hexadecimal values.
*
* @author Chris van Marle
* @private
* @param {string} a
* @param {string} b
* @returns {number}
*/
static _hexadecimalSort(a, b) {
let a_ = a.split(/([^\da-f]+)/i),
b_ = b.split(/([^\da-f]+)/i);
a_ = a_.map(v => {
const t = parseInt(v, 16);
return isNaN(t) ? v : t;
});
b_ = b_.map(v => {
const t = parseInt(v, 16);
return isNaN(t) ? v : t;
});
for (let i = 0; i < a_.length && i < b.length; ++i) {
if (isNaN(a_[i]) && !isNaN(b_[i])) return 1; // Numbers after non-numbers
if (!isNaN(a_[i]) && isNaN(b_[i])) return -1;
if (isNaN(a_[i]) && isNaN(b_[i])) {
const ret = a_[i].localeCompare(b_[i]); // Compare strings
if (ret !== 0) return ret;
}
if (!isNaN(a_[i]) && !isNaN(b_[i])) { // Compare numbers
if (a_[i] - b_[i] !== 0) return a_[i] - b_[i];
}
}
return a.localeCompare(b);
}
}
export default Sort;
+36 -14
View File
@@ -7,6 +7,7 @@
import Operation from "../Operation.mjs";
import XRegExp from "xregexp";
import { search } from "../lib/Extract.mjs";
import { caseInsensitiveSort } from "../lib/Sort.mjs";
/**
* Strings operation
@@ -27,27 +28,37 @@ class Strings extends Operation {
this.outputType = "string";
this.args = [
{
"name": "Encoding",
"type": "option",
"value": ["Single byte", "16-bit littleendian", "16-bit bigendian", "All"]
name: "Encoding",
type: "option",
value: ["Single byte", "16-bit littleendian", "16-bit bigendian", "All"]
},
{
"name": "Minimum length",
"type": "number",
"value": 4
name: "Minimum length",
type: "number",
value: 4
},
{
"name": "Match",
"type": "option",
"value": [
name: "Match",
type: "option",
value: [
"[ASCII]", "Alphanumeric + punctuation (A)", "All printable chars (A)", "Null-terminated strings (A)",
"[Unicode]", "Alphanumeric + punctuation (U)", "All printable chars (U)", "Null-terminated strings (U)"
]
},
{
"name": "Display total",
"type": "boolean",
"value": false
name: "Display total",
type: "boolean",
value: false
},
{
name: "Sort",
type: "boolean",
value: false
},
{
name: "Unique",
type: "boolean",
value: false
}
];
}
@@ -58,7 +69,7 @@ class Strings extends Operation {
* @returns {string}
*/
run(input, args) {
const [encoding, minLen, matchType, displayTotal] = args,
const [encoding, minLen, matchType, displayTotal, sort, unique] = args,
alphanumeric = "A-Z\\d",
punctuation = "/\\-:.,_$%'\"()<>= !\\[\\]{}@",
printable = "\x20-\x7e",
@@ -108,8 +119,19 @@ class Strings extends Operation {
}
const regex = new XRegExp(strings, "ig");
const results = search(
input,
regex,
null,
sort ? caseInsensitiveSort : null,
unique
);
return search(input, regex, null, displayTotal);
if (displayTotal) {
return `Total found: ${results.length}\n\n${results.join("\n")}`;
} else {
return results.join("\n");
}
}
}
+5 -5
View File
@@ -44,8 +44,8 @@ class Substitute extends Operation {
* @returns {string}
*/
run(input, args) {
const plaintext = Utils.expandAlphRange(args[0]).join(""),
ciphertext = Utils.expandAlphRange(args[1]).join("");
const plaintext = Utils.expandAlphRange([...args[0]]),
ciphertext = Utils.expandAlphRange([...args[1]]);
let output = "",
index = -1;
@@ -53,9 +53,9 @@ class Substitute extends Operation {
output = "Warning: Plaintext and Ciphertext lengths differ\n\n";
}
for (let i = 0; i < input.length; i++) {
index = plaintext.indexOf(input[i]);
output += index > -1 && index < ciphertext.length ? ciphertext[index] : input[i];
for (const character of input) {
index = plaintext.indexOf(character);
output += index > -1 && index < ciphertext.length ? ciphertext[index] : character;
}
return output;
+5 -1
View File
@@ -43,9 +43,9 @@ class ToBase45 extends Operation {
* @returns {string}
*/
run(input, args) {
if (!input) return "";
input = new Uint8Array(input);
const alphabet = Utils.expandAlphRange(args[0]);
if (!input) return "";
const res = [];
@@ -65,6 +65,10 @@ class ToBase45 extends Operation {
if (chars < 2) {
res.push("0");
chars++;
}
if (pair.length > 1 && chars < 3) {
res.push("0");
}
}
+2 -2
View File
@@ -67,7 +67,7 @@ class ToHex extends Operation {
* @returns {Object[]} pos
*/
highlight(pos, args) {
let delim, commaLen;
let delim, commaLen = 0;
if (args[0] === "0x with comma") {
delim = "0x";
commaLen = 1;
@@ -86,7 +86,7 @@ class ToHex extends Operation {
pos[0].start = pos[0].start * (2 + len) + countLF(pos[0].start);
pos[0].end = pos[0].end * (2 + len) + countLF(pos[0].end);
// if the deliminators are not prepended, trim the trailing deliminator
// if the delimiters are not prepended, trim the trailing delimiter
if (!(delim === "0x" || delim === "\\x")) {
pos[0].end -= delim.length;
}
+25 -5
View File
@@ -26,9 +26,14 @@ class Unique extends Operation {
this.outputType = "string";
this.args = [
{
"name": "Delimiter",
"type": "option",
"value": INPUT_DELIM_OPTIONS
name: "Delimiter",
type: "option",
value: INPUT_DELIM_OPTIONS
},
{
name: "Display count",
type: "boolean",
value: false
}
];
}
@@ -39,8 +44,23 @@ class Unique extends Operation {
* @returns {string}
*/
run(input, args) {
const delim = Utils.charRep(args[0]);
return input.split(delim).unique().join(delim);
const delim = Utils.charRep(args[0]),
count = args[1];
if (count) {
const valMap = input.split(delim).reduce((acc, curr) => {
if (Object.prototype.hasOwnProperty.call(acc, curr)) {
acc[curr]++;
} else {
acc[curr] = 1;
}
return acc;
}, {});
return Object.keys(valMap).map(val => `${valMap[val]} ${val}`).join(delim);
} else {
return input.split(delim).unique().join(delim);
}
}
}
+10 -5
View File
@@ -57,7 +57,7 @@ class App {
this.populateOperationsList();
this.manager.setup();
this.manager.output.saveBombe();
this.resetLayout();
this.adjustComponentSizes();
this.setCompileMessage();
log.debug("App loaded");
@@ -295,9 +295,7 @@ class App {
gutterSize: 4,
expandToMin: true,
onDrag: debounce(function() {
this.manager.recipe.adjustWidth();
this.manager.input.calcMaxTabs();
this.manager.output.calcMaxTabs();
this.adjustComponentSizes();
}, 50, "dragSplitter", this, [])
});
@@ -307,7 +305,7 @@ class App {
minSize: minimise ? [0, 0] : [100, 100]
});
this.resetLayout();
this.adjustComponentSizes();
}
@@ -581,6 +579,13 @@ class App {
resetLayout() {
this.columnSplitter.setSizes([20, 30, 50]);
this.ioSplitter.setSizes([50, 50]);
this.adjustComponentSizes();
}
/**
* Adjust components to fit their containers.
*/
adjustComponentSizes() {
this.manager.recipe.adjustWidth();
this.manager.input.calcMaxTabs();
this.manager.output.calcMaxTabs();
+12 -10
View File
@@ -176,7 +176,7 @@
<div id="recipe" class="split split-horizontal no-select">
<div class="title no-select">
Recipe
<span class="float-right">
<span class="pane-controls hide-on-maximised-output">
<button type="button" class="btn btn-primary bmd-btn-icon" id="save" data-toggle="tooltip" title="Save recipe">
<i class="material-icons">save</i>
</button>
@@ -190,7 +190,7 @@
</div>
<ul id="rec-list" class="list-area no-select"></ul>
<div id="controls" class="no-select">
<div id="controls" class="no-select hide-on-maximised-output">
<div id="controls-content" class="d-flex align-items-center">
<button type="button" class="mx-2 btn btn-lg btn-secondary" id="step" data-toggle="tooltip" title="Step through the recipe">
Step
@@ -217,7 +217,10 @@
<div id="input" class="split no-select">
<div class="title no-select">
<label for="input-text">Input</label>
<span class="float-right">
<span class="pane-controls">
<div class="io-info" id="input-files-info"></div>
<div class="io-info" id="input-selection-info"></div>
<div class="io-info" id="input-info"></div>
<button type="button" class="btn btn-primary bmd-btn-icon" id="btn-new-tab" data-toggle="tooltip" title="Add a new input tab">
<i class="material-icons">add</i>
</button>
@@ -236,9 +239,7 @@
<i class="material-icons">view_compact</i>
</button>
</span>
<div class="io-info" id="input-files-info"></div>
<div class="io-info" id="input-info"></div>
<div class="io-info" id="input-selection-info"></div>
</div>
<div id="input-tabs-wrapper" style="display: none;" class="no-select">
<span id="btn-previous-input-tab" class="input-tab-buttons">
@@ -288,7 +289,10 @@
<div id="output" class="split">
<div class="title no-select">
<label for="output-text">Output</label>
<span class="float-right">
<span class="pane-controls">
<div class="io-info" id="bake-info"></div>
<div class="io-info" id="output-selection-info"></div>
<div class="io-info" id="output-info"></div>
<button type="button" class="btn btn-primary bmd-btn-icon" id="save-all-to-file" data-toggle="tooltip" title="Save all outputs to a zip file" style="display: none">
<i class="material-icons">archive</i>
</button>
@@ -308,9 +312,7 @@
<i class="material-icons">fullscreen</i>
</button>
</span>
<div class="io-info" id="bake-info"></div>
<div class="io-info" id="output-info"></div>
<div class="io-info" id="output-selection-info"></div>
<button type="button" class="btn btn-primary bmd-btn-icon hidden" id="magic" data-toggle="tooltip" title="Magic!" data-html="true">
<svg width="22" height="22" viewBox="0 0 24 24">
<path d="M7.5,5.6L5,7L6.4,4.5L5,2L7.5,3.4L10,2L8.6,4.5L10,7L7.5,5.6M19.5,15.4L22,14L20.6,16.5L22,19L19.5,17.6L17,19L18.4,16.5L17,14L19.5,15.4M22,2L20.6,4.5L22,7L19.5,5.6L17,7L18.4,4.5L17,2L19.5,3.4L22,2M13.34,12.78L15.78,10.34L13.66,8.22L11.22,10.66L13.34,12.78M14.37,7.29L16.71,9.63C17.1,10 17.1,10.65 16.71,11.04L5.04,22.71C4.65,23.1 4,23.1 3.63,22.71L1.29,20.37C0.9,20 0.9,19.35 1.29,18.96L12.96,7.29C13.35,6.9 14,6.9 14.37,7.29Z" />
+11 -4
View File
@@ -24,9 +24,16 @@
line-height: calc(var(--title-height) - 14px);
}
.title>span,
.title>.btn {
margin-top: -4px;
.pane-controls {
position: absolute;
right: 8px;
top: 8px;
display: flex;
flex-direction: row;
}
.pane-controls .btn {
margin-left: 2px;
}
.list-area {
@@ -107,4 +114,4 @@
#files .card-header .float-right a:hover {
text-decoration: none;
}
}
+4
View File
@@ -58,6 +58,10 @@
border-radius: 30px;
}
.output-maximised .hide-on-maximised-output {
display: none !important;
}
.spin {
animation-name: spin;
animation-duration: 3s;
+1 -2
View File
@@ -280,9 +280,8 @@
}
.io-info {
margin-right: 20px;
margin-right: 18px;
margin-top: 1px;
float: right;
height: 30px;
text-align: right;
line-height: 12px;
+2 -2
View File
@@ -39,8 +39,8 @@ div#output {
.split {
box-sizing: border-box;
/* overflow: auto;
Removed to enable Background Magic button pulse to overflow.
/* overflow: auto; */
/* Removed to enable Background Magic button pulse to overflow.
Replace this rule if it seems to be causing problems. */
position: relative;
}
+5 -1
View File
@@ -109,11 +109,15 @@ class OperationsWaiter {
const matchedOps = [];
const matchedDescs = [];
// Create version with no whitespace for the fuzzy match
// Helps avoid missing matches e.g. query "TCP " would not find "Parse TCP"
const inStrNWS = inStr.replace(/\s/g, "");
for (const opName in this.app.operations) {
const op = this.app.operations[opName];
// Match op name using fuzzy match
const [nameMatch, score, idxs] = fuzzyMatch(inStr, opName);
const [nameMatch, score, idxs] = fuzzyMatch(inStrNWS, opName);
// Match description based on exact match
const descPos = op.description.toLowerCase().indexOf(inStr.toLowerCase());
+2
View File
@@ -1373,6 +1373,7 @@ class OutputWaiter {
const el = e.target.id === "maximise-output" ? e.target : e.target.parentNode;
if (el.getAttribute("data-original-title").indexOf("Maximise") === 0) {
document.body.classList.add("output-maximised");
this.app.initialiseSplitter(true);
this.app.columnSplitter.collapse(0);
this.app.columnSplitter.collapse(1);
@@ -1381,6 +1382,7 @@ class OutputWaiter {
$(el).attr("data-original-title", "Restore output pane");
el.querySelector("i").innerHTML = "fullscreen_exit";
} else {
document.body.classList.remove("output-maximised");
$(el).attr("data-original-title", "Maximise output pane");
el.querySelector("i").innerHTML = "fullscreen";
this.app.initialiseSplitter(false);
+2 -2
View File
@@ -23,11 +23,11 @@ class WindowWaiter {
/**
* Handler for window resize events.
* Resets the layout of CyberChef's panes after 200ms (so that continuous resizing doesn't cause
* Resets adjustable component sizes after 200ms (so that continuous resizing doesn't cause
* continuous resetting).
*/
windowResize() {
debounce(this.app.resetLayout, 200, "windowResize", this.app, [])();
debounce(this.app.adjustComponentSizes, 200, "windowResize", this.app, [])();
}
+77 -24
View File
@@ -16,7 +16,8 @@ module.exports = {
.click("#auto-bake-label");
},
"Sanity check operations": browser => {
"Sanity check operations": async browser => {
const Images = await import("../samples/Images.mjs");
testOp(browser, "A1Z26 Cipher Decode", "20 5 19 20 15 21 20 16 21 20", "testoutput");
testOp(browser, "A1Z26 Cipher Encode", "test input", "20 5 19 20 9 14 16 21 20");
testOp(browser, "ADD", "test input", "Ê»ÉÊv¿ÄÆËÊ", [{ "option": "Hex", "string": "56" }]);
@@ -24,7 +25,7 @@ module.exports = {
testOp(browser, "AES Encrypt", "test input", "e42eb8fbfb7a98fff061cd2c1a794d92", [{"option": "Hex", "string": "00112233445566778899aabbccddeeff"}, {"option": "Hex", "string": "00000000000000000000000000000000"}, "CBC", "Raw", "Hex"]);
testOp(browser, "AND", "test input", "4$04 $044", [{ "option": "Hex", "string": "34" }]);
testOp(browser, "Add line numbers", "test input", "1 test input");
// testOp(browser, "Add Text To Image", "test input", "test_output");
testOp(browser, ["From Hex", "Add Text To Image", "To Base64"], Images.PNG_HEX, Images.PNG_CHEF_B64, [[], ["Chef", "Center", "Middle", 0, 0, 16], []]);
testOp(browser, "Adler-32 Checksum", "test input", "16160411");
testOp(browser, "Affine Cipher Decode", "test input", "rcqr glnsr", [1, 2]);
testOp(browser, "Affine Cipher Encode", "test input", "njln rbfpn", [2, 1]);
@@ -44,12 +45,12 @@ module.exports = {
// testOp(browser, "Bifid Cipher Encode", "test input", "test_output");
// testOp(browser, "Bit shift left", "test input", "test_output");
// testOp(browser, "Bit shift right", "test input", "test_output");
// testOp(browser, "Blowfish Decrypt", "test input", "test_output");
// testOp(browser, "Blowfish Encrypt", "test input", "test_output");
// testOp(browser, "Blur Image", "test input", "test_output");
testOp(browser, "Blowfish Decrypt", "10884e15427dd84ec35204e9c8e921ae", "test_output", [{"option": "Hex", "string": "1234567801234567"}, {"option": "Hex", "string": "0011223344556677"}, "CBC", "Hex", "Raw"]);
testOp(browser, "Blowfish Encrypt", "test input", "f0fadbd1d90d774f714248cf26b96410", [{"option": "Hex", "string": "1234567801234567"}, {"option": "Hex", "string": "0011223344556677"}, "CBC", "Raw", "Hex"]);
testOp(browser, ["From Hex", "Blur Image", "To Base64"], Images.PNG_HEX, Images.PNG_BLUR_B64);
// testOp(browser, "Bombe", "test input", "test_output");
// testOp(browser, "Bzip2 Compress", "test input", "test_output");
// testOp(browser, "Bzip2 Decompress", "test input", "test_output");
testOp(browser, ["Bzip2 Compress", "To Hex"], "test input", "42 5a 68 39 31 41 59 26 53 59 cf 96 82 1d 00 00 03 91 80 40 00 02 21 4e 00 20 00 21 90 c2 10 c0 88 33 92 8e df 17 72 45 38 50 90 cf 96 82 1d");
testOp(browser, ["From Hex", "Bzip2 Decompress"], "425a68393141592653597b0884b7000003038000008200ce00200021a647a4218013709517c5dc914e14241ec2212dc0", "test_output", [[], [true]]);
// testOp(browser, "CRC-16 Checksum", "test input", "test_output");
// testOp(browser, "CRC-32 Checksum", "test input", "test_output");
// testOp(browser, "CRC-8 Checksum", "test input", "test_output");
@@ -69,10 +70,10 @@ module.exports = {
// testOp(browser, "Comment", "test input", "test_output");
// testOp(browser, "Compare CTPH hashes", "test input", "test_output");
// testOp(browser, "Compare SSDEEP hashes", "test input", "test_output");
// testOp(browser, "Conditional Jump", "test input", "test_output");
// /testOp(browser, "Conditional Jump", "test input", "test_output");
// testOp(browser, "Contain Image", "test input", "test_output");
// testOp(browser, "Convert area", "test input", "test_output");
// testOp(browser, "Convert co-ordinate format", "test input", "test_output");
// /testOp(browser, "Convert co-ordinate format", "test input", "test_output");
// testOp(browser, "Convert data units", "test input", "test_output");
// testOp(browser, "Convert distance", "test input", "test_output");
// testOp(browser, "Convert Image Format", "test input", "test_output");
@@ -197,10 +198,12 @@ module.exports = {
// testOp(browser, "MD4", "test input", "test_output");
// testOp(browser, "MD5", "test input", "test_output");
// testOp(browser, "MD6", "test input", "test_output");
// testOp(browser, "Magic", "test input", "test_output");
testOpHtml(browser, "Magic", "dGVzdF9vdXRwdXQ=", "tr:nth-of-type(1) th:nth-of-type(2)", "Result snippet");
testOpHtml(browser, "Magic", "dGVzdF9vdXRwdXQ=", "tr:nth-of-type(2) td:nth-of-type(2)", "test_output");
testOpHtml(browser, "Magic", "dGVzdF9vdXRwdXQ=", "tr:nth-of-type(2) td:nth-of-type(1)", /Base64/);
// testOp(browser, "Mean", "test input", "test_output");
// testOp(browser, "Median", "test input", "test_output");
// testOp(browser, "Merge", "test input", "test_output");
// testOp(browser, "Median", "test input", "test_output");`
// testOp(browser, "Merge", "test input", "test_output");`
// testOp(browser, "Microsoft Script Decoder", "test input", "test_output");
// testOp(browser, "Multiple Bombe", "test input", "test_output");
// testOp(browser, "Multiply", "test input", "test_output");
@@ -372,23 +375,36 @@ module.exports = {
}
};
/**
* Clears the current recipe and tests a new operation.
/** @function
* Clears the current recipe and bakes a new operation.
*
* @param {string} opName
* @param {Browser} browser
* @param {Browser} browser - Nightwatch client
* @param {string|Array<string>} opName - name of operation to be tested, array for multiple ops
* @param {string} input - input text for test
* @param {Array<string>|Array<Array<string>>} args - aarguments, nested if multiple ops
*/
function testOp(browser, opName, input, output, args=[]) {
function bakeOp(browser, opName, input, args=[]) {
let recipeConfig;
const recipeConfig = JSON.stringify([{
"op": opName,
"args": args
}]);
if (typeof(opName) === "string") {
recipeConfig = JSON.stringify([{
"op": opName,
"args": args
}]);
} else if (opName instanceof Array) {
recipeConfig = JSON.stringify(
opName.map((op, i) => {
return {
op: op,
args: args.length ? args[i] : []
};
})
);
} else {
throw new Error("Invalid operation type. Must be string or array of strings. Received: " + typeof(opName));
}
browser
.perform(function() {
console.log(opName);
})
.useCss()
.click("#clr-recipe")
.click("#clr-io")
@@ -396,6 +412,9 @@ function testOp(browser, opName, input, output, args=[]) {
.expect.element("#input-text").to.have.property("value").that.equals("");
browser
.perform(function() {
console.log(`Current test: ${opName}`);
})
.urlHash("recipe=" + recipeConfig)
.setValue("#input-text", input)
.waitForElementPresent("#rec-list li.operation")
@@ -408,6 +427,20 @@ function testOp(browser, opName, input, output, args=[]) {
.pause(100)
.waitForElementPresent("#stale-indicator.hidden", 5000)
.waitForElementNotVisible("#output-loader", 5000);
}
/** @function
* Clears the current recipe and tests a new operation.
*
* @param {Browser} browser - Nightwatch client
* @param {string|Array<string>} opName - name of operation to be tested, array for multiple ops
* @param {string} input - input text
* @param {string} output - expected output
* @param {Array<string>|Array<Array<string>>} args - arguments, nested if multiple ops
*/
function testOp(browser, opName, input, output, args=[]) {
bakeOp(browser, opName, input, args);
if (typeof output === "string") {
browser.expect.element("#output-text").to.have.property("value").that.equals(output);
@@ -415,3 +448,23 @@ function testOp(browser, opName, input, output, args=[]) {
browser.expect.element("#output-text").to.have.property("value").that.matches(output);
}
}
/** @function
* Clears the current recipe and tests a new operation.
*
* @param {Browser} browser - Nightwatch client
* @param {string|Array<string>} opName - name of operation to be tested array for multiple ops
* @param {string} input - input text
* @param {string} cssSelector - CSS selector for HTML output
* @param {string} output - expected output
* @param {Array<string>|Array<Array<string>>} args - arguments, nested if multiple ops
*/
function testOpHtml(browser, opName, input, cssSelector, output, args=[]) {
bakeOp(browser, opName, input, args);
if (typeof output === "string") {
browser.expect.element("#output-html " + cssSelector).text.that.equals(output);
} else if (output instanceof RegExp) {
browser.expect.element("#output-html " + cssSelector).text.that.matches(output);
}
}
+4 -5
View File
@@ -471,7 +471,7 @@ color: white;
}),
it("Extract dates", () => {
assert.strictEqual(chef.extractDates("Don't Look a Gift Horse In The Mouth 01/02/1992").toString(), "01/02/1992\n");
assert.strictEqual(chef.extractDates("Don't Look a Gift Horse In The Mouth 01/02/1992").toString(), "01/02/1992");
}),
it("Filter", () => {
@@ -816,7 +816,7 @@ pCGTErs=
it("RC4 Drop", () => {
assert.strictEqual(
chef.RC4Drop("Go Out On a Limb", {passphrase: {string: "Under Your Nose", option: "UTF8"}, inputFormat: "UTF8", outputFormat: "Hex"}).toString(),
"8fa5f2751d34476a0c857439f43816cf");
"b85cb1c4ed6bed8f260ab92829bba942");
}),
it("Regular Expression", () => {
@@ -859,7 +859,7 @@ pCGTErs=
}),
it("SQL Beautify", () => {
const result = chef.SQLBeautify(`SELECT MONTH, ID, RAIN_I, TEMP_F
const result = chef.SQLBeautify(`SELECT MONTH, ID, RAIN_I, TEMP_F
FROM STATS;`);
const expected = `SELECT MONTH,
ID,
@@ -879,8 +879,7 @@ FROM STATS;`;
const result = chef.strings("smothering ampersand abreast", {displayTotal: true});
const expected = `Total found: 1
smothering ampersand abreast
`;
smothering ampersand abreast`;
assert.strictEqual(result.toString(), expected);
}),
+1
View File
@@ -96,6 +96,7 @@ import "./tests/Protobuf.mjs";
import "./tests/ParseSSHHostKey.mjs";
import "./tests/DefangIP.mjs";
import "./tests/ParseUDP.mjs";
import "./tests/ParseTCP.mjs";
import "./tests/AvroToJSON.mjs";
import "./tests/Lorenz.mjs";
import "./tests/LuhnChecksum.mjs";
@@ -11,7 +11,7 @@ TestRegister.addTests([
{
name: "Extract email address",
input: "email@example.com\nfirstname.lastname@example.com\nemail@subdomain.example.com\nfirstname+lastname@example.com\n1234567890@example.com\nemail@example-one.com\n_______@example.com email@example.name\nemail@example.museum email@example.co.jp firstname-lastname@example.com",
expectedOutput: "email@example.com\nfirstname.lastname@example.com\nemail@subdomain.example.com\nfirstname+lastname@example.com\n1234567890@example.com\nemail@example-one.com\n_______@example.com\nemail@example.name\nemail@example.museum\nemail@example.co.jp\nfirstname-lastname@example.com\n",
expectedOutput: "email@example.com\nfirstname.lastname@example.com\nemail@subdomain.example.com\nfirstname+lastname@example.com\n1234567890@example.com\nemail@example-one.com\n_______@example.com\nemail@example.name\nemail@example.museum\nemail@example.co.jp\nfirstname-lastname@example.com",
recipeConfig: [
{
"op": "Extract email addresses",
@@ -22,7 +22,7 @@ TestRegister.addTests([
{
name: "Extract email address - Display total",
input: "email@example.com\nfirstname.lastname@example.com\nemail@subdomain.example.com\nfirstname+lastname@example.com\n1234567890@example.com\nemail@example-one.com\n_______@example.com email@example.name\nemail@example.museum email@example.co.jp firstname-lastname@example.com",
expectedOutput: "Total found: 11\n\nemail@example.com\nfirstname.lastname@example.com\nemail@subdomain.example.com\nfirstname+lastname@example.com\n1234567890@example.com\nemail@example-one.com\n_______@example.com\nemail@example.name\nemail@example.museum\nemail@example.co.jp\nfirstname-lastname@example.com\n",
expectedOutput: "Total found: 11\n\nemail@example.com\nfirstname.lastname@example.com\nemail@subdomain.example.com\nfirstname+lastname@example.com\n1234567890@example.com\nemail@example-one.com\n_______@example.com\nemail@example.name\nemail@example.museum\nemail@example.co.jp\nfirstname-lastname@example.com",
recipeConfig: [
{
"op": "Extract email addresses",
@@ -33,7 +33,7 @@ TestRegister.addTests([
{
name: "Extract email address (Internationalized)",
input: "\u4f0a\u662d\u5091@\u90f5\u4ef6.\u5546\u52d9 \u093e\u092e@\u092e\u094b\u0939\u0928.\u0908\u0928\u094d\u092b\u094b\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c \u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc Jos\u1ec5Silv\u1ec5@googl\u1ec5.com\nJos\u1ec5Silv\u1ec5@google.com and Jos\u1ec5Silva@google.com\nFoO@BaR.CoM, john@192.168.10.100\ng\xf3mez@junk.br and Abc.123@example.com.\nuser+mailbox/department=shipping@example.com\n\u7528\u6237@\u4f8b\u5b50.\u5e7f\u544a\n\u0909\u092a\u092f\u094b\u0917\u0915\u0930\u094d\u0924\u093e@\u0909\u0926\u093e\u0939\u0930\u0923.\u0915\u0949\u092e\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nD\xf6rte@S\xf6rensen.example.com\n\u0430\u0434\u0436\u0430\u0439@\u044d\u043a\u0437\u0430\u043c\u043f\u043b.\u0440\u0443\u0441\ntest@xn--bcher-kva.com",
expectedOutput: "\u4f0a\u662d\u5091@\u90f5\u4ef6.\u5546\u52d9\n\u093e\u092e@\u092e\u094b\u0939\u0928.\u0908\u0928\u094d\u092b\u094b\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nJos\u1ec5Silv\u1ec5@googl\u1ec5.com\nJos\u1ec5Silv\u1ec5@google.com\nJos\u1ec5Silva@google.com\nFoO@BaR.CoM\njohn@192.168.10.100\ng\xf3mez@junk.br\nAbc.123@example.com\nuser+mailbox/department=shipping@example.com\n\u7528\u6237@\u4f8b\u5b50.\u5e7f\u544a\n\u0909\u092a\u092f\u094b\u0917\u0915\u0930\u094d\u0924\u093e@\u0909\u0926\u093e\u0939\u0930\u0923.\u0915\u0949\u092e\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nD\xf6rte@S\xf6rensen.example.com\n\u0430\u0434\u0436\u0430\u0439@\u044d\u043a\u0437\u0430\u043c\u043f\u043b.\u0440\u0443\u0441\ntest@xn--bcher-kva.com\n",
expectedOutput: "\u4f0a\u662d\u5091@\u90f5\u4ef6.\u5546\u52d9\n\u093e\u092e@\u092e\u094b\u0939\u0928.\u0908\u0928\u094d\u092b\u094b\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nJos\u1ec5Silv\u1ec5@googl\u1ec5.com\nJos\u1ec5Silv\u1ec5@google.com\nJos\u1ec5Silva@google.com\nFoO@BaR.CoM\njohn@192.168.10.100\ng\xf3mez@junk.br\nAbc.123@example.com\nuser+mailbox/department=shipping@example.com\n\u7528\u6237@\u4f8b\u5b50.\u5e7f\u544a\n\u0909\u092a\u092f\u094b\u0917\u0915\u0930\u094d\u0924\u093e@\u0909\u0926\u093e\u0939\u0930\u0923.\u0915\u0949\u092e\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nD\xf6rte@S\xf6rensen.example.com\n\u0430\u0434\u0436\u0430\u0439@\u044d\u043a\u0437\u0430\u043c\u043f\u043b.\u0440\u0443\u0441\ntest@xn--bcher-kva.com",
recipeConfig: [
{
"op": "Extract email addresses",
@@ -44,7 +44,7 @@ TestRegister.addTests([
{
name: "Extract email address - Display total (Internationalized)",
input: "\u4f0a\u662d\u5091@\u90f5\u4ef6.\u5546\u52d9 \u093e\u092e@\u092e\u094b\u0939\u0928.\u0908\u0928\u094d\u092b\u094b\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c \u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc Jos\u1ec5Silv\u1ec5@googl\u1ec5.com\nJos\u1ec5Silv\u1ec5@google.com and Jos\u1ec5Silva@google.com\nFoO@BaR.CoM, john@192.168.10.100\ng\xf3mez@junk.br and Abc.123@example.com.\nuser+mailbox/department=shipping@example.com\n\u7528\u6237@\u4f8b\u5b50.\u5e7f\u544a\n\u0909\u092a\u092f\u094b\u0917\u0915\u0930\u094d\u0924\u093e@\u0909\u0926\u093e\u0939\u0930\u0923.\u0915\u0949\u092e\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nD\xf6rte@S\xf6rensen.example.com\n\u0430\u0434\u0436\u0430\u0439@\u044d\u043a\u0437\u0430\u043c\u043f\u043b.\u0440\u0443\u0441\ntest@xn--bcher-kva.com",
expectedOutput: "Total found: 19\n\n\u4f0a\u662d\u5091@\u90f5\u4ef6.\u5546\u52d9\n\u093e\u092e@\u092e\u094b\u0939\u0928.\u0908\u0928\u094d\u092b\u094b\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nJos\u1ec5Silv\u1ec5@googl\u1ec5.com\nJos\u1ec5Silv\u1ec5@google.com\nJos\u1ec5Silva@google.com\nFoO@BaR.CoM\njohn@192.168.10.100\ng\xf3mez@junk.br\nAbc.123@example.com\nuser+mailbox/department=shipping@example.com\n\u7528\u6237@\u4f8b\u5b50.\u5e7f\u544a\n\u0909\u092a\u092f\u094b\u0917\u0915\u0930\u094d\u0924\u093e@\u0909\u0926\u093e\u0939\u0930\u0923.\u0915\u0949\u092e\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nD\xf6rte@S\xf6rensen.example.com\n\u0430\u0434\u0436\u0430\u0439@\u044d\u043a\u0437\u0430\u043c\u043f\u043b.\u0440\u0443\u0441\ntest@xn--bcher-kva.com\n",
expectedOutput: "Total found: 19\n\n\u4f0a\u662d\u5091@\u90f5\u4ef6.\u5546\u52d9\n\u093e\u092e@\u092e\u094b\u0939\u0928.\u0908\u0928\u094d\u092b\u094b\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nJos\u1ec5Silv\u1ec5@googl\u1ec5.com\nJos\u1ec5Silv\u1ec5@google.com\nJos\u1ec5Silva@google.com\nFoO@BaR.CoM\njohn@192.168.10.100\ng\xf3mez@junk.br\nAbc.123@example.com\nuser+mailbox/department=shipping@example.com\n\u7528\u6237@\u4f8b\u5b50.\u5e7f\u544a\n\u0909\u092a\u092f\u094b\u0917\u0915\u0930\u094d\u0924\u093e@\u0909\u0926\u093e\u0939\u0930\u0923.\u0915\u0949\u092e\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nD\xf6rte@S\xf6rensen.example.com\n\u0430\u0434\u0436\u0430\u0439@\u044d\u043a\u0437\u0430\u043c\u043f\u043b.\u0440\u0443\u0441\ntest@xn--bcher-kva.com",
recipeConfig: [
{
"op": "Extract email addresses",
+1 -1
View File
@@ -9,7 +9,7 @@
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";
import { GIF_ANIMATED_HEX, PNG_HEX, JPG_B64, EXIF_JPG_HEX, NO_EXIF_JPG_HEX } from "../samples/Images.mjs";
import { GIF_ANIMATED_HEX, PNG_HEX, JPG_B64, EXIF_JPG_HEX, NO_EXIF_JPG_HEX } from "../../samples/Images.mjs";
TestRegister.addTests([
{
+1 -1
View File
@@ -7,7 +7,7 @@
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";
import { JPG_RAW } from "../samples/Images.mjs";
import { JPG_RAW } from "../../samples/Images.mjs";
TestRegister.addTests([
{
+1 -1
View File
@@ -6,7 +6,7 @@
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";
import {ASCII_TEXT, UTF8_TEXT, ALL_BYTES} from "../samples/Ciphers.mjs";
import {ASCII_TEXT, UTF8_TEXT, ALL_BYTES} from "../../samples/Ciphers.mjs";
// RSA-1024
const ALICE_PRIVATE = `-----BEGIN PGP PRIVATE KEY BLOCK-----
+44
View File
@@ -0,0 +1,44 @@
/**
* Parse TCP tests.
*
* @author n1474335
* @copyright Crown Copyright 2022
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";
TestRegister.addTests([
{
name: "Parse TCP: No options",
input: "c2eb0050a138132e70dc9fb9501804025ea70000",
expectedMatch: /1026 \(Scaled: 1026\)/,
recipeConfig: [
{
op: "Parse TCP",
args: ["Hex"],
}
],
},
{
name: "Parse TCP: Options",
input: "c2eb0050a1380c1f000000008002faf080950000020405b40103030801010402",
expectedMatch: /1460/,
recipeConfig: [
{
op: "Parse TCP",
args: ["Hex"],
}
],
},
{
name: "Parse TCP: Timestamps",
input: "9e90e11574d57b2c00000000a002ffffe5740000020405b40402080aa4e8c8f50000000001030308",
expectedMatch: /2766719221/,
recipeConfig: [
{
op: "Parse TCP",
args: ["Hex"],
}
],
}
]);
+5 -18
View File
@@ -2,7 +2,6 @@
* Parse UDP tests.
*
* @author h345983745
*
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
@@ -12,15 +11,11 @@ TestRegister.addTests([
{
name: "Parse UDP: No Data - JSON",
input: "04 89 00 35 00 2c 01 01",
expectedOutput: "{\"Source port\":1161,\"Destination port\":53,\"Length\":44,\"Checksum\":\"0101\"}",
expectedOutput: "{\"Source port\":1161,\"Destination port\":53,\"Length\":44,\"Checksum\":\"0x0101\"}",
recipeConfig: [
{
op: "From Hex",
args: ["Auto"],
},
{
op: "Parse UDP",
args: [],
args: ["Hex"],
},
{
op: "JSON Minify",
@@ -30,15 +25,11 @@ TestRegister.addTests([
}, {
name: "Parse UDP: With Data - JSON",
input: "04 89 00 35 00 2c 01 01 02 02",
expectedOutput: "{\"Source port\":1161,\"Destination port\":53,\"Length\":44,\"Checksum\":\"0101\",\"Data\":\"0202\"}",
expectedOutput: "{\"Source port\":1161,\"Destination port\":53,\"Length\":44,\"Checksum\":\"0x0101\",\"Data\":\"0x0202\"}",
recipeConfig: [
{
op: "From Hex",
args: ["Auto"],
},
{
op: "Parse UDP",
args: [],
args: ["Hex"],
},
{
op: "JSON Minify",
@@ -51,13 +42,9 @@ TestRegister.addTests([
input: "04 89 00",
expectedOutput: "Need 8 bytes for a UDP Header",
recipeConfig: [
{
op: "From Hex",
args: ["Auto"],
},
{
op: "Parse UDP",
args: [],
args: ["Hex"],
},
{
op: "JSON Minify",
+1 -1
View File
@@ -6,7 +6,7 @@
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";
import {ASCII_TEXT, UTF8_TEXT, ALL_BYTES} from "../samples/Ciphers.mjs";
import {ASCII_TEXT, UTF8_TEXT, ALL_BYTES} from "../../samples/Ciphers.mjs";
const PEM_PRIV_2048 = `-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAwfaUOpUEutKyU3wkCv6kYunz4MqxzSuTSckRz1IxwZtwIiqq
File renamed without changes.
@@ -18,6 +18,18 @@ export const GIF_ANIMATED_HEX = "4749463839610f000f00b30b00424242ffe700ffef00ffc
*/
export const PNG_HEX = "89504e470d0a1a0a0000000d4948445200000020000000200806000000737a7af400000006624b474400ff00ff00ffa0bda793000000097048597300000dd700000dd70142289b78000005184944415458c3c5575d6c145514feeeccecccacdbddb6e096a5dbcdb6d06d80d06090466d6953454ab52ad0a65589840ac1d02a313c989af062820fa66210130d9a68b0363c34610135690b188b7183c13f44506c8115ba535ab6ddd2617f667f66ae0fb41596ddee2eadf13c4de69e7bcf77cff9cecf25b83f613b3b3b975b2c96f25028c47a3c9e1f5a5a5a7e05a0016000d0c9ef9442d23448a60edeb973a769c78e1d077272721a65594620106000505996bf1a1f1f3f67369bebc2e1f0ef6bd7aedd0a409d2d00e2743a1f2929296915046199a66901007aa3d1580600131313da24000000a594124288aaaab72a2b2bed1d1d1d8f8ba2386fc3860d9f25f3c84c0088cbe56a2d2c2cdc4708d12552880770a7288a3228088215003c1ecfd68d1b377e9e488f4b66dde974aeb2dbed498da71251146d538ed1b4e4746092dddee170b4300ca3c32c251c0edfd8bc79f3d164de4e0680110461794a02119292c482202c387efcf86f3d3d3d7b13814816024a2955e62a8b4451b4abaafad8e485d5743ca005028153699c4dd30c83140a857e4c9409c900a0bbbbfbc368343a34a3754a693a1c58b76eddf2dadada5d89002705b07bf7eee13367ce3cab284aff6c482808425e6767e70bc9ea0033d3e6c6c6c65fd6ac5953a1695a3453c3a150c84d295529a59aa669914cd3705adc6eb7926eaca74455d5605555d5c3030303f59224bd525f5f7f30992e87ff40344d5328a5caa64d9bbe4ca5cbe07f1666ae522dae40a5dd8ed30941c8e5727d63341a9f8a5f181a1ac2f0f07022029e02109d2b00bae2e26207cbb2f72cf03c8f9c9c9c441c580c804dc70b330258b6c020beb87ac9abecb59f8b087377b4f4f30a68b6de482549a29224ddb5168bc51cd5d5d54ff6f5f575cfa69633edeb971c78e2d195db055e77cfb6a2eaadb816e5b59ffafb19a7d3095555e3ab64341a8d96f6f6f6fe755f247c69d542abd9c0bd3c70f90a628c30fd5f56542c5c550fc3837600406e6e2eca9e2e433837fcefc0c8b2e079fe7b9fcfe7aba9a9296613c52f55084acc864a027013b28c828a2d30e805bcbe670fac4b5740f5a9285b18c6a0db4da8c180fdc6fdb035d850c555a174a4148410b85cae7293c97442a7d395363434347775757d91b6075a2a6c45d66ce18369258685de644659d96af45ff80345f9f908c932821313c4eff7639b6d1b06838358242c82d96c86288abe582ce6e6797e052184701c9797910796e61976b10c991fff7f7b5313b6373541d5340426d36f747414e5c67294679503a1e90634e6f57adbac56ebb14020f0e9a14387decf84038c8e232b53b45888dc6dec63636389d290c9caca5a3d09a6a2a6a6a628130054d33092a2c52272bbe4515996113f16288ab2c86432bd01001cc72db5582caf651202eaf5473e7e80d7af270409d9cb320c0c66331ca5a5602c1624180d492412392bcbf2db46a3f1394992f665c481b77a2f9f78e719476b5e16ff2e00d31dae8524cb30e8f560390ee72e5e243d7d7d34168bc16030a87575752ccbb20400a2d1e8b7478e1c390ce0f0fd5442fae6d7039f343d643956345f5fcbf1fafd00b219868145afc78d4b97101a1b833a32426d361bcdcfcf87cd6663a7a6649ee70725497a6faede86e4c2c993cf171716eee5753aeb9d0b7f5ebfae5df67a99b86164e8e6cd9badcdcdcdc7d27ae5a6a3f45147c7794dd30e2e59bcf896c0f3851ccbe602c0a8df4fc783413269d8130c06f79d3e7d7a4b5b5bdbd9b45b77c60304c3f0df75752db31714acf8dbe7cbbee2f5fafd7efff9f6f6f6b357af5e8d647ade3fa1780bad734c65970000000049454e44ae426082";
/**
* The CyberChef logo with 'chef'
* 32x32
*/
export const PNG_CHEF_B64 = "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";
/**
* The CyberChef logo with blur
* 32x32
*/
export const PNG_BLUR_B64 = "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";
/**
* Sunglasses smiley
* 32x32
+11
View File
@@ -1,6 +1,7 @@
const webpack = require("webpack");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const { ModifySourcePlugin } = require("modify-source-webpack-plugin");
const path = require("path");
/**
@@ -82,6 +83,16 @@ module.exports = {
to: "assets/forge/"
}
]
}),
new ModifySourcePlugin({
rules: [
{
// Fix toSpare(0) bug in Split.js by avoiding gutter accomodation
test: /split\.es\.js$/,
modify: (src, path) =>
src.replace("if (pixelSize < elementMinSize)", "if (false)")
}
]
})
],
resolve: {