mirror of
https://github.com/gchq/CyberChef
synced 2025-12-28 22:23:33 +00:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
95f7ed0de4 | ||
|
|
6e7240026a | ||
|
|
8bae7bf809 | ||
|
|
b78bb2d3d6 | ||
|
|
f9a6402825 | ||
|
|
8ec5f3cb18 | ||
|
|
c330394ff2 | ||
|
|
36e66ad5b4 | ||
|
|
a5a89efc06 | ||
|
|
1078c37043 | ||
|
|
535c7188a8 | ||
|
|
d6f9e216a6 | ||
|
|
7d6a879a67 | ||
|
|
668eac1f9e | ||
|
|
ff99436ce6 | ||
|
|
ec577fc075 | ||
|
|
cc9d51b7be | ||
|
|
cf2b54e8c0 | ||
|
|
a895d1d82a | ||
|
|
11da4188ee | ||
|
|
5b68bad185 | ||
|
|
ed542582f9 | ||
|
|
2574a63975 | ||
|
|
a7cdb095d2 |
@@ -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
|
||||
|
||||
@@ -217,7 +217,8 @@ module.exports = function (grunt) {
|
||||
client: {
|
||||
logging: "error",
|
||||
overlay: true
|
||||
}
|
||||
},
|
||||
hot: "only"
|
||||
},
|
||||
plugins: [
|
||||
new webpack.DefinePlugin(BUILD_CONSTANTS),
|
||||
|
||||
3049
package-lock.json
generated
3049
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
76
package.json
76
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cyberchef",
|
||||
"version": "9.37.3",
|
||||
"version": "9.38.5",
|
||||
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
|
||||
"author": "n1474335 <n1474335@gmail.com>",
|
||||
"homepage": "https://gchq.github.io/CyberChef",
|
||||
@@ -39,26 +39,27 @@
|
||||
"node >= 16"
|
||||
],
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.17.8",
|
||||
"@babel/eslint-parser": "^7.17.0",
|
||||
"@babel/plugin-syntax-import-assertions": "^7.16.7",
|
||||
"@babel/plugin-transform-runtime": "^7.17.0",
|
||||
"@babel/preset-env": "^7.16.11",
|
||||
"@babel/runtime": "^7.17.8",
|
||||
"autoprefixer": "^10.4.4",
|
||||
"babel-loader": "^8.2.4",
|
||||
"@babel/core": "^7.18.2",
|
||||
"@babel/eslint-parser": "^7.18.2",
|
||||
"@babel/plugin-syntax-import-assertions": "^7.17.12",
|
||||
"@babel/plugin-transform-runtime": "^7.18.2",
|
||||
"@babel/preset-env": "^7.18.2",
|
||||
"@babel/runtime": "^7.18.3",
|
||||
"autoprefixer": "^10.4.7",
|
||||
"babel-loader": "^8.2.5",
|
||||
"babel-plugin-dynamic-import-node": "^2.3.3",
|
||||
"chromedriver": "^99.0.0",
|
||||
"cli-progress": "^3.10.0",
|
||||
"babel-plugin-transform-builtin-extend": "1.1.2",
|
||||
"chromedriver": "^101.0.0",
|
||||
"cli-progress": "^3.11.1",
|
||||
"colors": "^1.4.0",
|
||||
"copy-webpack-plugin": "^10.2.4",
|
||||
"core-js": "^3.21.1",
|
||||
"copy-webpack-plugin": "^11.0.0",
|
||||
"core-js": "^3.22.8",
|
||||
"css-loader": "6.7.1",
|
||||
"eslint": "^8.12.0",
|
||||
"grunt": "^1.4.1",
|
||||
"eslint": "^8.16.0",
|
||||
"grunt": "^1.5.3",
|
||||
"grunt-chmod": "~1.1.1",
|
||||
"grunt-concurrent": "^3.0.0",
|
||||
"grunt-contrib-clean": "~2.0.0",
|
||||
"grunt-contrib-clean": "~2.0.1",
|
||||
"grunt-contrib-connect": "^3.0.0",
|
||||
"grunt-contrib-copy": "~1.0.0",
|
||||
"grunt-contrib-watch": "^1.1.0",
|
||||
@@ -67,28 +68,28 @@
|
||||
"grunt-webpack": "^5.0.0",
|
||||
"grunt-zip": "^0.18.2",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"imports-loader": "^3.1.1",
|
||||
"imports-loader": "^4.0.0",
|
||||
"mini-css-extract-plugin": "2.6.0",
|
||||
"nightwatch": "^2.0.10",
|
||||
"postcss": "^8.4.12",
|
||||
"modify-source-webpack-plugin": "^3.0.0",
|
||||
"nightwatch": "^2.1.7",
|
||||
"postcss": "^8.4.14",
|
||||
"postcss-css-variables": "^0.18.0",
|
||||
"postcss-import": "^14.1.0",
|
||||
"postcss-loader": "^6.2.1",
|
||||
"prompt": "^1.2.2",
|
||||
"sass-loader": "^12.6.0",
|
||||
"postcss-loader": "^7.0.0",
|
||||
"prompt": "^1.3.0",
|
||||
"sass-loader": "^13.0.0",
|
||||
"sitemap": "^7.1.1",
|
||||
"terser": "^5.12.1",
|
||||
"webpack": "^5.70.0",
|
||||
"terser": "^5.14.0",
|
||||
"webpack": "^5.73.0",
|
||||
"webpack-bundle-analyzer": "^4.5.0",
|
||||
"webpack-dev-server": "4.7.4",
|
||||
"webpack-dev-server": "4.9.1",
|
||||
"webpack-node-externals": "^3.0.0",
|
||||
"worker-loader": "^3.0.8"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/polyfill": "^7.12.1",
|
||||
"arrive": "^2.4.1",
|
||||
"avsc": "^5.7.3",
|
||||
"babel-plugin-transform-builtin-extend": "1.1.2",
|
||||
"avsc": "^5.7.4",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"bignumber.js": "^9.0.2",
|
||||
"blakejs": "^1.2.1",
|
||||
@@ -96,7 +97,7 @@
|
||||
"bootstrap-colorpicker": "^3.4.0",
|
||||
"bootstrap-material-design": "^4.1.3",
|
||||
"browserify-zlib": "^0.2.0",
|
||||
"bson": "^4.6.2",
|
||||
"bson": "^4.6.4",
|
||||
"buffer": "^6.0.3",
|
||||
"cbor": "8.1.0",
|
||||
"chi-squared": "^1.1.0",
|
||||
@@ -105,9 +106,9 @@
|
||||
"crypto-browserify": "^3.12.0",
|
||||
"crypto-js": "^4.1.1",
|
||||
"ctph.js": "0.0.5",
|
||||
"d3": "7.3.0",
|
||||
"d3": "7.4.4",
|
||||
"d3-hexbin": "^0.2.2",
|
||||
"diff": "^5.0.0",
|
||||
"diff": "^5.1.0",
|
||||
"es6-promisify": "^7.0.0",
|
||||
"escodegen": "^2.0.0",
|
||||
"esprima": "^4.0.1",
|
||||
@@ -115,7 +116,7 @@
|
||||
"file-saver": "^2.0.5",
|
||||
"flat": "^5.0.2",
|
||||
"geodesy": "1.1.3",
|
||||
"highlight.js": "^11.5.0",
|
||||
"highlight.js": "^11.5.1",
|
||||
"jimp": "^0.16.1",
|
||||
"jquery": "3.6.0",
|
||||
"js-crc": "^0.2.0",
|
||||
@@ -124,28 +125,28 @@
|
||||
"jsonpath": "^1.1.1",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"jsqr": "^1.4.0",
|
||||
"jsrsasign": "^10.5.14",
|
||||
"jsrsasign": "^10.5.23",
|
||||
"kbpgp": "2.1.15",
|
||||
"libbzip2-wasm": "0.0.4",
|
||||
"libyara-wasm": "^1.1.0",
|
||||
"lodash": "^4.17.21",
|
||||
"loglevel": "^1.8.0",
|
||||
"loglevel-message-prefix": "^3.0.0",
|
||||
"markdown-it": "^12.3.2",
|
||||
"moment": "^2.29.1",
|
||||
"markdown-it": "^13.0.1",
|
||||
"moment": "^2.29.3",
|
||||
"moment-timezone": "^0.5.34",
|
||||
"ngeohash": "^0.6.3",
|
||||
"node-forge": "^1.3.0",
|
||||
"node-forge": "^1.3.1",
|
||||
"node-md6": "^0.1.0",
|
||||
"node-sass": "^7.0.1",
|
||||
"nodom": "^2.4.0",
|
||||
"notepack.io": "^2.3.0",
|
||||
"notepack.io": "^3.0.1",
|
||||
"nwmatcher": "^1.4.4",
|
||||
"otp": "0.1.3",
|
||||
"path": "^0.12.7",
|
||||
"popper.js": "^1.16.1",
|
||||
"process": "^0.11.10",
|
||||
"protobufjs": "^6.11.2",
|
||||
"protobufjs": "^6.11.3",
|
||||
"qr-image": "^3.2.0",
|
||||
"scryptsy": "^2.1.0",
|
||||
"snackbarjs": "^1.1.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"
|
||||
}
|
||||
|
||||
@@ -190,6 +190,7 @@
|
||||
"Parse IP range",
|
||||
"Parse IPv6 address",
|
||||
"Parse IPv4 header",
|
||||
"Parse TCP",
|
||||
"Parse UDP",
|
||||
"Parse SSH Host Key",
|
||||
"Parse URI",
|
||||
|
||||
144
src/core/config/scripts/newMinorVersion.mjs
Normal file
144
src/core/config/scripts/newMinorVersion.mjs
Normal 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();
|
||||
@@ -82,15 +82,46 @@ export function toBase64(data, alphabet="A-Za-z0-9+/=") {
|
||||
* // returns [72, 101, 108, 108, 111]
|
||||
* fromBase64("SGVsbG8=", null, "byteArray");
|
||||
*/
|
||||
export function fromBase64(data, alphabet="A-Za-z0-9+/=", returnType="string", removeNonAlphChars=true) {
|
||||
export function fromBase64(data, alphabet="A-Za-z0-9+/=", returnType="string", removeNonAlphChars=true, strictMode=false) {
|
||||
if (!data) {
|
||||
return returnType === "string" ? "" : [];
|
||||
}
|
||||
|
||||
alphabet = alphabet || "A-Za-z0-9+/=";
|
||||
alphabet = Utils.expandAlphRange(alphabet).join("");
|
||||
|
||||
// Confirm alphabet is a valid length
|
||||
if (alphabet.length !== 64 && alphabet.length !== 65) { // Allow for padding
|
||||
throw new OperationError(`Invalid Base64 alphabet length (${alphabet.length}): ${alphabet}`);
|
||||
throw new OperationError(`Error: Base64 alphabet should be 64 characters long, or 65 with a padding character. Found ${alphabet.length}: ${alphabet}`);
|
||||
}
|
||||
|
||||
// Remove non-alphabet characters
|
||||
if (removeNonAlphChars) {
|
||||
const re = new RegExp("[^" + alphabet.replace(/[[\]\\\-^$]/g, "\\$&") + "]", "g");
|
||||
data = data.replace(re, "");
|
||||
}
|
||||
|
||||
if (strictMode) {
|
||||
// Check for incorrect lengths (even without padding)
|
||||
if (data.length % 4 === 1) {
|
||||
throw new OperationError(`Error: Invalid Base64 input length (${data.length}). Cannot be 4n+1, even without padding chars.`);
|
||||
}
|
||||
|
||||
if (alphabet.length === 65) { // Padding character included
|
||||
const pad = alphabet.charAt(64);
|
||||
const padPos = data.indexOf(pad);
|
||||
if (padPos >= 0) {
|
||||
// Check that the padding character is only used at the end and maximum of twice
|
||||
if (padPos < data.length - 2 || data.charAt(data.length - 1) !== pad) {
|
||||
throw new OperationError(`Error: Base64 padding character (${pad}) not used in the correct place.`);
|
||||
}
|
||||
|
||||
// Check that input is padded to the correct length
|
||||
if (data.length % 4 !== 0) {
|
||||
throw new OperationError("Error: Base64 not padded to a multiple of 4.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const output = [];
|
||||
@@ -98,31 +129,27 @@ export function fromBase64(data, alphabet="A-Za-z0-9+/=", returnType="string", r
|
||||
enc1, enc2, enc3, enc4,
|
||||
i = 0;
|
||||
|
||||
if (removeNonAlphChars) {
|
||||
const re = new RegExp("[^" + alphabet.replace(/[[\]\\\-^$]/g, "\\$&") + "]", "g");
|
||||
data = data.replace(re, "");
|
||||
}
|
||||
|
||||
while (i < data.length) {
|
||||
enc1 = alphabet.indexOf(data.charAt(i++));
|
||||
enc2 = alphabet.indexOf(data.charAt(i++) || "=");
|
||||
enc3 = alphabet.indexOf(data.charAt(i++) || "=");
|
||||
enc4 = alphabet.indexOf(data.charAt(i++) || "=");
|
||||
enc2 = alphabet.indexOf(data.charAt(i++));
|
||||
enc3 = alphabet.indexOf(data.charAt(i++));
|
||||
enc4 = alphabet.indexOf(data.charAt(i++));
|
||||
|
||||
enc2 = enc2 === -1 ? 64 : enc2;
|
||||
enc3 = enc3 === -1 ? 64 : enc3;
|
||||
enc4 = enc4 === -1 ? 64 : enc4;
|
||||
if (strictMode && (enc1 < 0 || enc2 < 0 || enc3 < 0 || enc4 < 0)) {
|
||||
throw new OperationError("Error: Base64 input contains non-alphabet char(s)");
|
||||
}
|
||||
|
||||
chr1 = (enc1 << 2) | (enc2 >> 4);
|
||||
chr2 = ((enc2 & 15) << 4) | (enc3 >> 2);
|
||||
chr3 = ((enc3 & 3) << 6) | enc4;
|
||||
|
||||
output.push(chr1);
|
||||
|
||||
if (enc3 !== 64) {
|
||||
if (chr1 < 256) {
|
||||
output.push(chr1);
|
||||
}
|
||||
if (chr2 < 256 && enc3 !== 64) {
|
||||
output.push(chr2);
|
||||
}
|
||||
if (enc4 !== 64) {
|
||||
if (chr3 < 256 && enc4 !== 64) {
|
||||
output.push(chr3);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,33 +13,39 @@ 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}
|
||||
*
|
||||
* @example
|
||||
* // returns "00010000 00100000 00110000"
|
||||
* // returns "00001010 00010100 00011110"
|
||||
* toBinary([10,20,30]);
|
||||
*
|
||||
* // returns "00010000 00100000 00110000"
|
||||
* toBinary([10,20,30], ":");
|
||||
* // returns "00001010:00010100:00011110"
|
||||
* toBinary([10,20,30], "Colon");
|
||||
*
|
||||
* // returns "1010:10100:11110"
|
||||
* toBinary([10,20,30], "Colon", 0);
|
||||
*/
|
||||
export function toBinary(data, delim="Space", padding=8) {
|
||||
if (!data) return "";
|
||||
if (data === undefined || data === null)
|
||||
throw new OperationError("Unable to convert to binary: Empty input data enocuntered");
|
||||
|
||||
delim = Utils.charRep(delim);
|
||||
let output = "";
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
output += data[i].toString(2).padStart(padding, "0") + delim;
|
||||
}
|
||||
|
||||
if (delim.length) {
|
||||
return output.slice(0, -delim.length);
|
||||
if (data.length) { // array
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
output += data[i].toString(2).padStart(padding, "0");
|
||||
if (i !== data.length - 1) output += delim;
|
||||
}
|
||||
} else if (typeof data === "number") { // Single value
|
||||
return data.toString(2).padStart(padding, "0");
|
||||
} else {
|
||||
return output;
|
||||
return "";
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,10 +59,10 @@ export function toBinary(data, delim="Space", padding=8) {
|
||||
*
|
||||
* @example
|
||||
* // returns [10,20,30]
|
||||
* fromBinary("00010000 00100000 00110000");
|
||||
* fromBinary("00001010 00010100 00011110");
|
||||
*
|
||||
* // returns [10,20,30]
|
||||
* fromBinary("00010000:00100000:00110000", "Colon");
|
||||
* fromBinary("00001010:00010100:00011110", "Colon");
|
||||
*/
|
||||
export function fromBinary(data, delim="Space", byteLen=8) {
|
||||
if (byteLen < 1 || Math.round(byteLen) !== byteLen)
|
||||
|
||||
@@ -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
src/core/lib/Protocol.mjs
Normal file
47
src/core/lib/Protocol.mjs
Normal 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();
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -34,93 +34,98 @@ class FromBase64 extends Operation {
|
||||
name: "Remove non-alphabet chars",
|
||||
type: "boolean",
|
||||
value: true
|
||||
},
|
||||
{
|
||||
name: "Strict mode",
|
||||
type: "boolean",
|
||||
value: false
|
||||
}
|
||||
];
|
||||
this.checks = [
|
||||
{
|
||||
pattern: "^\\s*(?:[A-Z\\d+/]{4})+(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
|
||||
flags: "i",
|
||||
args: ["A-Za-z0-9+/=", true]
|
||||
args: ["A-Za-z0-9+/=", true, false]
|
||||
},
|
||||
{
|
||||
pattern: "^\\s*[A-Z\\d\\-_]{20,}\\s*$",
|
||||
flags: "i",
|
||||
args: ["A-Za-z0-9-_", true]
|
||||
args: ["A-Za-z0-9-_", true, false]
|
||||
},
|
||||
{
|
||||
pattern: "^\\s*(?:[A-Z\\d+\\-]{4}){5,}(?:[A-Z\\d+\\-]{2}==|[A-Z\\d+\\-]{3}=)?\\s*$",
|
||||
flags: "i",
|
||||
args: ["A-Za-z0-9+\\-=", true]
|
||||
args: ["A-Za-z0-9+\\-=", true, false]
|
||||
},
|
||||
{
|
||||
pattern: "^\\s*(?:[A-Z\\d./]{4}){5,}(?:[A-Z\\d./]{2}==|[A-Z\\d./]{3}=)?\\s*$",
|
||||
flags: "i",
|
||||
args: ["./0-9A-Za-z=", true]
|
||||
args: ["./0-9A-Za-z=", true, false]
|
||||
},
|
||||
{
|
||||
pattern: "^\\s*[A-Z\\d_.]{20,}\\s*$",
|
||||
flags: "i",
|
||||
args: ["A-Za-z0-9_.", true]
|
||||
args: ["A-Za-z0-9_.", true, false]
|
||||
},
|
||||
{
|
||||
pattern: "^\\s*(?:[A-Z\\d._]{4}){5,}(?:[A-Z\\d._]{2}--|[A-Z\\d._]{3}-)?\\s*$",
|
||||
flags: "i",
|
||||
args: ["A-Za-z0-9._-", true]
|
||||
args: ["A-Za-z0-9._-", true, false]
|
||||
},
|
||||
{
|
||||
pattern: "^\\s*(?:[A-Z\\d+/]{4}){5,}(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
|
||||
flags: "i",
|
||||
args: ["0-9a-zA-Z+/=", true]
|
||||
args: ["0-9a-zA-Z+/=", true, false]
|
||||
},
|
||||
{
|
||||
pattern: "^\\s*(?:[A-Z\\d+/]{4}){5,}(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
|
||||
flags: "i",
|
||||
args: ["0-9A-Za-z+/=", true]
|
||||
args: ["0-9A-Za-z+/=", true, false]
|
||||
},
|
||||
{
|
||||
pattern: "^[ !\"#$%&'()*+,\\-./\\d:;<=>?@A-Z[\\\\\\]^_]{20,}$",
|
||||
flags: "",
|
||||
args: [" -_", false]
|
||||
args: [" -_", false, false]
|
||||
},
|
||||
{
|
||||
pattern: "^\\s*[A-Z\\d+\\-]{20,}\\s*$",
|
||||
flags: "i",
|
||||
args: ["+\\-0-9A-Za-z", true]
|
||||
args: ["+\\-0-9A-Za-z", true, false]
|
||||
},
|
||||
{
|
||||
pattern: "^\\s*[!\"#$%&'()*+,\\-0-689@A-NP-VX-Z[`a-fh-mp-r]{20,}\\s*$",
|
||||
flags: "",
|
||||
args: ["!-,-0-689@A-NP-VX-Z[`a-fh-mp-r", true]
|
||||
args: ["!-,-0-689@A-NP-VX-Z[`a-fh-mp-r", true, false]
|
||||
},
|
||||
{
|
||||
pattern: "^\\s*(?:[N-ZA-M\\d+/]{4}){5,}(?:[N-ZA-M\\d+/]{2}==|[N-ZA-M\\d+/]{3}=)?\\s*$",
|
||||
flags: "i",
|
||||
args: ["N-ZA-Mn-za-m0-9+/=", true]
|
||||
args: ["N-ZA-Mn-za-m0-9+/=", true, false]
|
||||
},
|
||||
{
|
||||
pattern: "^\\s*[A-Z\\d./]{20,}\\s*$",
|
||||
flags: "i",
|
||||
args: ["./0-9A-Za-z", true]
|
||||
args: ["./0-9A-Za-z", true, false]
|
||||
},
|
||||
{
|
||||
pattern: "^\\s*(?:[A-Z=\\d\\+/]{4}){5,}(?:[A-Z=\\d\\+/]{2}CC|[A-Z=\\d\\+/]{3}C)?\\s*$",
|
||||
flags: "i",
|
||||
args: ["/128GhIoPQROSTeUbADfgHijKLM+n0pFWXY456xyzB7=39VaqrstJklmNuZvwcdEC", true]
|
||||
args: ["/128GhIoPQROSTeUbADfgHijKLM+n0pFWXY456xyzB7=39VaqrstJklmNuZvwcdEC", true, false]
|
||||
},
|
||||
{
|
||||
pattern: "^\\s*(?:[A-Z=\\d\\+/]{4}){5,}(?:[A-Z=\\d\\+/]{2}55|[A-Z=\\d\\+/]{3}5)?\\s*$",
|
||||
flags: "i",
|
||||
args: ["3GHIJKLMNOPQRSTUb=cdefghijklmnopWXYZ/12+406789VaqrstuvwxyzABCDEF5", true]
|
||||
args: ["3GHIJKLMNOPQRSTUb=cdefghijklmnopWXYZ/12+406789VaqrstuvwxyzABCDEF5", true, false]
|
||||
},
|
||||
{
|
||||
pattern: "^\\s*(?:[A-Z=\\d\\+/]{4}){5,}(?:[A-Z=\\d\\+/]{2}22|[A-Z=\\d\\+/]{3}2)?\\s*$",
|
||||
flags: "i",
|
||||
args: ["ZKj9n+yf0wDVX1s/5YbdxSo=ILaUpPBCHg8uvNO4klm6iJGhQ7eFrWczAMEq3RTt2", true]
|
||||
args: ["ZKj9n+yf0wDVX1s/5YbdxSo=ILaUpPBCHg8uvNO4klm6iJGhQ7eFrWczAMEq3RTt2", true, false]
|
||||
},
|
||||
{
|
||||
pattern: "^\\s*(?:[A-Z=\\d\\+/]{4}){5,}(?:[A-Z=\\d\\+/]{2}55|[A-Z=\\d\\+/]{3}5)?\\s*$",
|
||||
flags: "i",
|
||||
args: ["HNO4klm6ij9n+J2hyf0gzA8uvwDEq3X1Q7ZKeFrWcVTts/MRGYbdxSo=ILaUpPBC5", true]
|
||||
args: ["HNO4klm6ij9n+J2hyf0gzA8uvwDEq3X1Q7ZKeFrWcVTts/MRGYbdxSo=ILaUpPBC5", true, false]
|
||||
}
|
||||
];
|
||||
}
|
||||
@@ -131,9 +136,9 @@ class FromBase64 extends Operation {
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [alphabet, removeNonAlphChars] = args;
|
||||
const [alphabet, removeNonAlphChars, strictMode] = args;
|
||||
|
||||
return fromBase64(input, alphabet, "byteArray", removeNonAlphChars);
|
||||
return fromBase64(input, alphabet, "byteArray", removeNonAlphChars, strictMode);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
245
src/core/operations/ParseTCP.mjs
Normal file
245
src/core/operations/ParseTCP.mjs
Normal 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;
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -65,6 +65,10 @@ class ToBase45 extends Operation {
|
||||
|
||||
if (chars < 2) {
|
||||
res.push("0");
|
||||
chars++;
|
||||
}
|
||||
if (pair.length > 1 && chars < 3) {
|
||||
res.push("0");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
*/
|
||||
|
||||
import Operation from "../Operation.mjs";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
|
||||
/**
|
||||
* To Upper case operation
|
||||
@@ -37,25 +38,30 @@ class ToUpperCase extends Operation {
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
if (!args || args.length === 0) {
|
||||
throw new OperationError("No capitalization scope was provided.");
|
||||
}
|
||||
|
||||
const scope = args[0];
|
||||
|
||||
switch (scope) {
|
||||
case "Word":
|
||||
return input.replace(/(\b\w)/gi, function(m) {
|
||||
return m.toUpperCase();
|
||||
});
|
||||
case "Sentence":
|
||||
return input.replace(/(?:\.|^)\s*(\b\w)/gi, function(m) {
|
||||
return m.toUpperCase();
|
||||
});
|
||||
case "Paragraph":
|
||||
return input.replace(/(?:\n|^)\s*(\b\w)/gi, function(m) {
|
||||
return m.toUpperCase();
|
||||
});
|
||||
case "All": /* falls through */
|
||||
default:
|
||||
return input.toUpperCase();
|
||||
if (scope === "All") {
|
||||
return input.toUpperCase();
|
||||
}
|
||||
|
||||
const scopeRegex = {
|
||||
"Word": /(\b\w)/gi,
|
||||
"Sentence": /(?:\.|^)\s*(\b\w)/gi,
|
||||
"Paragraph": /(?:\n|^)\s*(\b\w)/gi
|
||||
}[scope];
|
||||
|
||||
if (scopeRegex === undefined) {
|
||||
throw new OperationError("Unrecognized capitalization scope");
|
||||
}
|
||||
|
||||
// Use the regex to capitalize the input
|
||||
return input.replace(scopeRegex, function(m) {
|
||||
return m.toUpperCase();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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" />
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,6 +58,10 @@
|
||||
border-radius: 30px;
|
||||
}
|
||||
|
||||
.output-maximised .hide-on-maximised-output {
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
.spin {
|
||||
animation-name: spin;
|
||||
animation-duration: 3s;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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, [])();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -68,7 +68,7 @@ TestRegister.addTests([
|
||||
{
|
||||
name: "Magic Chain: Base64",
|
||||
input: "WkVkV2VtUkRRbnBrU0Vwd1ltMWpQUT09",
|
||||
expectedMatch: /From_Base64\('A-Za-z0-9\+\/=',true\)\nFrom_Base64\('A-Za-z0-9\+\/=',true\)\nFrom_Base64\('A-Za-z0-9\+\/=',true\)/,
|
||||
expectedMatch: /From_Base64\('A-Za-z0-9\+\/=',true,false\)\nFrom_Base64\('A-Za-z0-9\+\/=',true,false\)\nFrom_Base64\('A-Za-z0-9\+\/=',true,false\)/,
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Magic",
|
||||
@@ -79,7 +79,7 @@ TestRegister.addTests([
|
||||
{
|
||||
name: "Magic Chain: Hex -> Hexdump -> Base64",
|
||||
input: "MDAwMDAwMDAgIDM3IDM0IDIwIDM2IDM1IDIwIDM3IDMzIDIwIDM3IDM0IDIwIDMyIDMwIDIwIDM3ICB8NzQgNjUgNzMgNzQgMjAgN3wKMDAwMDAwMTAgIDMzIDIwIDM3IDM0IDIwIDM3IDMyIDIwIDM2IDM5IDIwIDM2IDY1IDIwIDM2IDM3ICB8MyA3NCA3MiA2OSA2ZSA2N3w=",
|
||||
expectedMatch: /From_Base64\('A-Za-z0-9\+\/=',true\)\nFrom_Hexdump\(\)\nFrom_Hex\('Space'\)/,
|
||||
expectedMatch: /From_Base64\('A-Za-z0-9\+\/=',true,false\)\nFrom_Hexdump\(\)\nFrom_Hex\('Space'\)/,
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Magic",
|
||||
|
||||
44
tests/operations/tests/ParseTCP.mjs
Normal file
44
tests/operations/tests/ParseTCP.mjs
Normal 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"],
|
||||
}
|
||||
],
|
||||
}
|
||||
]);
|
||||
@@ -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,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: {
|
||||
|
||||
Reference in New Issue
Block a user