Compare commits

...
20 Commits
Author SHA1 Message Date
n1474335 32455cd20f 9.27.4 2021-02-22 19:13:47 +00:00
n1474335 1e0e7f16a7 Added numeric validation for arguments in Binary and Hex operattions. Fixes #1178 2021-02-22 19:13:38 +00:00
n1474335 95884d77cf Extractable file formats are now listed properly in the 'Extract Files' description 2021-02-17 15:01:42 +00:00
n1474335 b69373f5e7 Fixed 'JSON to CSV' data flattening. 2021-02-16 14:48:56 +00:00
n1474335 61e85474d3 9.27.3 2021-02-16 14:36:36 +00:00
n1474335 3a9bdc58af Fixed 'JSON to CSV' handling of complex structures. Closes #637 2021-02-16 14:36:31 +00:00
n1474335 59c1c45d78 Updated dependencies 2021-02-16 14:17:09 +00:00
n1474335 b5f6cedd30 9.27.2 2021-02-16 14:12:18 +00:00
n1474335 c879af6860 Fixed 'Save recipe' URL generation issue. Closes #1176 2021-02-16 14:12:14 +00:00
n1474335 22fe5a6ae7 9.27.1 2021-02-12 17:55:36 +00:00
n1474335 57714c86a6 Escape HTML input in Fuzzy Match operation 2021-02-12 17:55:28 +00:00
n1474335 70cd375049 9.27.0 2021-02-12 13:54:52 +00:00
n1474335 e27e1dd42f Updated CHANGELOG 2021-02-12 13:53:59 +00:00
n1474335 8ad18bc7db Added 'Fuzzy Match' operation 2021-02-12 13:51:51 +00:00
n1474335 5893ac1a37 9.26.3 2021-02-12 12:12:08 +00:00
n1474335 83c3ab97f9 Merge branch 'n1073645-base64Alphabets' 2021-02-12 12:11:53 +00:00
n1474335 9b6be140fa Merge branch 'base64Alphabets' of https://github.com/n1073645/CyberChef into n1073645-base64Alphabets 2021-02-12 12:08:56 +00:00
n1073645 bda36e508a Regexes for magic for the new alphabets 2020-03-27 13:27:56 +00:00
n1073645 d2ea1273da Merge remote-tracking branch 'upstream/master' into base64Alphabets 2020-03-27 13:09:03 +00:00
n1073645 3a2580fbc2 Extra Base64 Alphabets 2020-01-22 10:35:11 +00:00
23 changed files with 317 additions and 86 deletions

No files matched your search

+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
- name: Install
run: |
npm install
export NODE_OPTIONS=--max_old_space_size=2048
npm run setheapsize
- name: Lint
run: npx grunt lint
+1 -1
View File
@@ -18,7 +18,7 @@ jobs:
- name: Install
run: |
npm install
export NODE_OPTIONS=--max_old_space_size=2048
npm run setheapsize
- name: Lint
run: npx grunt lint
+1 -1
View File
@@ -19,7 +19,7 @@ jobs:
- name: Install
run: |
npm install
export NODE_OPTIONS=--max_old_space_size=2048
npm run setheapsize
- name: Lint
run: npx grunt lint
+6
View File
@@ -13,6 +13,9 @@ All major and minor version changes will be documented in this file. Details of
## Details
### [9.27.0] - 2021-02-12
- 'Fuzzy Match' operation added [@n1474335] | [8ad18b]
### [9.26.0] - 2021-02-11
- 'Get Time' operation added [@n1073645] [@n1474335] | [#1045]
@@ -253,6 +256,7 @@ All major and minor version changes will be documented in this file. Details of
[9.27.0]: https://github.com/gchq/CyberChef/releases/tag/v9.27.0
[9.26.0]: https://github.com/gchq/CyberChef/releases/tag/v9.26.0
[9.25.0]: https://github.com/gchq/CyberChef/releases/tag/v9.25.0
[9.24.0]: https://github.com/gchq/CyberChef/releases/tag/v9.24.0
@@ -360,6 +364,8 @@ All major and minor version changes will be documented in this file. Details of
[@dmfj]: https://github.com/dmfj
[@mattnotmitt]: https://github.com/mattnotmitt
[8ad18b]: https://github.com/gchq/CyberChef/commit/8ad18bc7db6d9ff184ba3518686293a7685bf7b7
[#95]: https://github.com/gchq/CyberChef/pull/299
[#173]: https://github.com/gchq/CyberChef/pull/173
[#143]: https://github.com/gchq/CyberChef/pull/143
+33 -24
View File
@@ -1,6 +1,6 @@
{
"name": "cyberchef",
"version": "9.26.2",
"version": "9.27.4",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -6351,12 +6351,12 @@
}
},
"eslint": {
"version": "7.19.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.19.0.tgz",
"integrity": "sha512-CGlMgJY56JZ9ZSYhJuhow61lMPPjUzWmChFya71Z/jilVos7mR/jPgaEfVGgMBY5DshbKdG8Ezb8FDCHcoMEMg==",
"version": "7.20.0",
"resolved": "https://registry.npmjs.org/eslint/-/eslint-7.20.0.tgz",
"integrity": "sha512-qGi0CTcOGP2OtCQBgWZlQjcTuP0XkIpYFj25XtRTQSHC+umNnp7UMshr2G8SLsRFYDdAPFeHOsiteadmMH02Yw==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.0.0",
"@babel/code-frame": "7.12.11",
"@eslint/eslintrc": "^0.3.0",
"ajv": "^6.10.0",
"chalk": "^4.0.0",
@@ -6368,7 +6368,7 @@
"eslint-utils": "^2.1.0",
"eslint-visitor-keys": "^2.0.0",
"espree": "^7.3.1",
"esquery": "^1.2.0",
"esquery": "^1.4.0",
"esutils": "^2.0.2",
"file-entry-cache": "^6.0.0",
"functional-red-black-tree": "^1.0.1",
@@ -6395,6 +6395,15 @@
"v8-compile-cache": "^2.0.3"
},
"dependencies": {
"@babel/code-frame": {
"version": "7.12.11",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz",
"integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==",
"dev": true,
"requires": {
"@babel/highlight": "^7.10.4"
}
},
"ansi-regex": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
@@ -6606,9 +6615,9 @@
"integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A=="
},
"esquery": {
"version": "1.3.1",
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.3.1.tgz",
"integrity": "sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ==",
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz",
"integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==",
"dev": true,
"requires": {
"estraverse": "^5.1.0"
@@ -9408,9 +9417,9 @@
"integrity": "sha512-zCTP6Qd/WwjrpuHFkJuXc5opRdKprUr7eI7+JCCtcetThJt45qptu82MWQ+eET+FtDrMo7+BYjo3iD0XIq1L9Q=="
},
"jsrsasign": {
"version": "10.1.8",
"resolved": "https://registry.npmjs.org/jsrsasign/-/jsrsasign-10.1.8.tgz",
"integrity": "sha512-NdMWugkiOXk7dfB8a2PMlnzjf+8mxWgGC9IfWhiYouQa00Qcc4PBrCk4eH+MNB2O/DJ2Cjz1eEzI2usY3BSynQ=="
"version": "10.1.10",
"resolved": "https://registry.npmjs.org/jsrsasign/-/jsrsasign-10.1.10.tgz",
"integrity": "sha512-//Kkza0S/kFbK5fq6eVbwlM36tKes+ak6FfTn8+mFxKlYzN/3bVJDa0ZERGYu78QKWrXPpos+TIC1tTJDNFDRQ=="
},
"jszip": {
"version": "2.5.0",
@@ -10223,9 +10232,9 @@
}
},
"mini-css-extract-plugin": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-1.3.6.tgz",
"integrity": "sha512-t86rLnySRQgN2+58gAIARTEtnClLNZoC99shNrvQ960V/wB9n50AUKJyqly76/s4fT0zwaLFIDFZAW7aK25pvg==",
"version": "1.3.7",
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-1.3.7.tgz",
"integrity": "sha512-NDyOUqdfKVIfWTludTcZ6JDOMsIdWgyTEECYbfvZszPpkMRyQLvukqtLr92tfukPQxVZNCKb8TkOilFBvS5RIw==",
"dev": true,
"requires": {
"loader-utils": "^2.0.0",
@@ -13986,9 +13995,9 @@
},
"dependencies": {
"ajv": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-7.0.3.tgz",
"integrity": "sha512-R50QRlXSxqXcQP5SvKUrw8VZeypvo12i2IX0EeR5PiZ7bEKeHWgzgo264LDadUsCU42lTJVhFikTqJwNeH34gQ==",
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-7.1.0.tgz",
"integrity": "sha512-svS9uILze/cXbH0z2myCK2Brqprx/+JJYK5pHicT/GQiBfzzhUVAIT6MwqJg8y4xV/zoGsUeuPuwtoiKSGE15g==",
"dev": true,
"requires": {
"fast-deep-equal": "^3.1.1",
@@ -14061,9 +14070,9 @@
}
},
"terser": {
"version": "5.5.1",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.5.1.tgz",
"integrity": "sha512-6VGWZNVP2KTUcltUQJ25TtNjx/XgdDsBDKGt8nN0MpydU36LmbPPcMBd2kmtZNNGVVDLg44k7GKeHHj+4zPIBQ==",
"version": "5.6.0",
"resolved": "https://registry.npmjs.org/terser/-/terser-5.6.0.tgz",
"integrity": "sha512-vyqLMoqadC1uR0vywqOZzriDYzgEkNJFK4q9GeyOBHIbiECHiWLKcWfbQWAUaPfxkjDhapSlZB9f7fkMrvkVjA==",
"requires": {
"commander": "^2.20.0",
"source-map": "~0.7.2",
@@ -14807,9 +14816,9 @@
}
},
"webpack": {
"version": "5.21.2",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.21.2.tgz",
"integrity": "sha512-xHflCenx+AM4uWKX71SWHhxml5aMXdy2tu/vdi4lClm7PADKxlyDAFFN1rEFzNV0MAoPpHtBeJnl/+K6F4QBPg==",
"version": "5.22.0",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.22.0.tgz",
"integrity": "sha512-xqlb6r9RUXda/d9iA6P7YRTP1ChWeP50TEESKMMNIg0u8/Rb66zN9YJJO7oYgJTRyFyYi43NVC5feG45FSO1vQ==",
"dev": true,
"requires": {
"@types/eslint-scope": "^3.7.0",
+9 -7
View File
@@ -1,6 +1,6 @@
{
"name": "cyberchef",
"version": "9.26.2",
"version": "9.27.4",
"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 @@
"colors": "^1.4.0",
"copy-webpack-plugin": "^7.0.0",
"css-loader": "^5.0.2",
"eslint": "^7.19.0",
"eslint": "^7.20.0",
"exports-loader": "^2.0.0",
"file-loader": "^6.2.0",
"grunt": "^1.3.0",
@@ -64,7 +64,7 @@
"grunt-zip": "^0.18.2",
"html-webpack-plugin": "^5.1.0",
"imports-loader": "^2.0.0",
"mini-css-extract-plugin": "^1.3.6",
"mini-css-extract-plugin": "^1.3.7",
"nightwatch": "^1.5.1",
"node-sass": "^5.0.0",
"postcss": "^8.2.6",
@@ -77,7 +77,7 @@
"style-loader": "^2.0.0",
"svg-url-loader": "^7.1.1",
"url-loader": "^4.1.1",
"webpack": "^5.21.2",
"webpack": "^5.22.0",
"webpack-bundle-analyzer": "^4.4.0",
"webpack-dev-server": "^3.11.2",
"webpack-node-externals": "^2.5.2",
@@ -125,7 +125,7 @@
"jsonpath": "^1.1.0",
"jsonwebtoken": "^8.5.1",
"jsqr": "^1.3.1",
"jsrsasign": "10.1.8",
"jsrsasign": "^10.1.10",
"kbpgp": "2.1.15",
"libbzip2-wasm": "0.0.4",
"libyara-wasm": "^1.1.0",
@@ -152,7 +152,7 @@
"split.js": "^1.6.2",
"ssdeep.js": "0.0.2",
"stream-browserify": "^3.0.0",
"terser": "^5.5.1",
"terser": "^5.6.0",
"tesseract.js": "2.1.1",
"ua-parser-js": "^0.7.24",
"unorm": "^1.6.0",
@@ -173,6 +173,8 @@
"testuidev": "npx nightwatch --env=dev",
"lint": "npx grunt lint",
"postinstall": "npx grunt exec:fixCryptoApiImports",
"newop": "node --experimental-modules src/core/config/scripts/newOperation.mjs"
"newop": "node --experimental-modules src/core/config/scripts/newOperation.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
@@ -895,8 +895,8 @@ class Utils {
while ((m = recipeRegex.exec(recipe))) {
// Translate strings in args back to double-quotes
args = m[2]
.replace(/"/g, '\\"') // Escape double quotes // lgtm [js/incomplete-sanitization]
args = m[2] // lgtm [js/incomplete-sanitization]
.replace(/"/g, '\\"') // Escape double quotes
.replace(/(^|,|{|:)'/g, '$1"') // Replace opening ' with "
.replace(/([^\\]|(?:\\\\)+)'(,|:|}|$)/g, '$1"$2') // Replace closing ' with "
.replace(/\\'/g, "'"); // Unescape single quotes
+1
View File
@@ -238,6 +238,7 @@
"Pad lines",
"Find / Replace",
"Regular expression",
"Fuzzy Match",
"Offset checker",
"Hamming Distance",
"Convert distance",
+4
View File
@@ -148,4 +148,8 @@ export const ALPHABET_OPTIONS = [
{name: "BinHex: !-,-0-689@A-NP-VX-Z[`a-fh-mp-r", value: "!-,-0-689@A-NP-VX-Z[`a-fh-mp-r"},
{name: "ROT13: N-ZA-Mn-za-m0-9+/=", value: "N-ZA-Mn-za-m0-9+/="},
{name: "UNIX crypt: ./0-9A-Za-z", value: "./0-9A-Za-z"},
{name: "Atom128: /128GhIoPQROSTeUbADfgHijKLM+n0pFWXY456xyzB7=39VaqrstJklmNuZvwcdEC", value: "/128GhIoPQROSTeUbADfgHijKLM+n0pFWXY456xyzB7=39VaqrstJklmNuZvwcdEC"},
{name: "Megan35: 3GHIJKLMNOPQRSTUb=cdefghijklmnopWXYZ/12+406789VaqrstuvwxyzABCDEF5", value: "3GHIJKLMNOPQRSTUb=cdefghijklmnopWXYZ/12+406789VaqrstuvwxyzABCDEF5"},
{name: "Zong22: ZKj9n+yf0wDVX1s/5YbdxSo=ILaUpPBCHg8uvNO4klm6iJGhQ7eFrWczAMEq3RTt2", value: "ZKj9n+yf0wDVX1s/5YbdxSo=ILaUpPBCHg8uvNO4klm6iJGhQ7eFrWczAMEq3RTt2"},
{name: "Hazz15: HNO4klm6ij9n+J2hyf0gzA8uvwDEq3X1Q7ZKeFrWcVTts/MRGYbdxSo=ILaUpPBC5", value: "HNO4klm6ij9n+J2hyf0gzA8uvwDEq3X1Q7ZKeFrWcVTts/MRGYbdxSo=ILaUpPBC5"}
];
+4
View File
@@ -7,6 +7,7 @@
*/
import Utils from "../Utils.mjs";
import OperationError from "../errors/OperationError.mjs";
/**
@@ -58,6 +59,9 @@ export function toBinary(data, delim="Space", padding=8) {
* fromBinary("00010000:00100000:00110000", "Colon");
*/
export function fromBinary(data, delim="Space", byteLen=8) {
if (byteLen < 1 || Math.round(byteLen) !== byteLen)
throw new OperationError("Byte length must be a positive integer");
const delimRegex = Utils.regexRep(delim);
data = data.replace(delimRegex, "");
@@ -16,40 +16,72 @@
* Anurag Awasthi - updated to 0.2.0
*/
const SEQUENTIAL_BONUS = 15; // bonus for adjacent matches
const SEPARATOR_BONUS = 30; // bonus if match occurs after a separator
const CAMEL_BONUS = 30; // bonus if match is uppercase and prev is lower
const FIRST_LETTER_BONUS = 15; // bonus if the first letter is matched
export const DEFAULT_WEIGHTS = {
sequentialBonus: 15, // bonus for adjacent matches
separatorBonus: 30, // bonus if match occurs after a separator
camelBonus: 30, // bonus if match is uppercase and prev is lower
firstLetterBonus: 15, // bonus if the first letter is matched
const LEADING_LETTER_PENALTY = -5; // penalty applied for every letter in str before the first match
const MAX_LEADING_LETTER_PENALTY = -15; // maximum penalty for leading letters
const UNMATCHED_LETTER_PENALTY = -1;
leadingLetterPenalty: -5, // penalty applied for every letter in str before the first match
maxLeadingLetterPenalty: -15, // maximum penalty for leading letters
unmatchedLetterPenalty: -1
};
/**
* Does a fuzzy search to find pattern inside a string.
* @param {*} pattern string pattern to search for
* @param {*} str string string which is being searched
* @param {string} pattern pattern to search for
* @param {string} str string which is being searched
* @param {boolean} global whether to search for all matches or just one
* @returns [boolean, number] a boolean which tells if pattern was
* found or not and a search score
*/
export function fuzzyMatch(pattern, str) {
export function fuzzyMatch(pattern, str, global=false, weights=DEFAULT_WEIGHTS) {
const recursionCount = 0;
const recursionLimit = 10;
const matches = [];
const maxMatches = 256;
return fuzzyMatchRecursive(
pattern,
str,
0 /* patternCurIndex */,
0 /* strCurrIndex */,
null /* srcMatces */,
matches,
maxMatches,
0 /* nextMatch */,
recursionCount,
recursionLimit
);
if (!global) {
return fuzzyMatchRecursive(
pattern,
str,
0 /* patternCurIndex */,
0 /* strCurrIndex */,
null /* srcMatches */,
matches,
maxMatches,
0 /* nextMatch */,
recursionCount,
recursionLimit,
weights
);
}
// Return all matches
let foundMatch = true,
score,
idxs,
strCurrIndex = 0;
const results = [];
while (foundMatch) {
[foundMatch, score, idxs] = fuzzyMatchRecursive(
pattern,
str,
0 /* patternCurIndex */,
strCurrIndex,
null /* srcMatches */,
matches,
maxMatches,
0 /* nextMatch */,
recursionCount,
recursionLimit,
weights
);
if (foundMatch) results.push([foundMatch, score, [...idxs]]);
strCurrIndex = idxs[idxs.length - 1] + 1;
}
return results;
}
/**
@@ -65,7 +97,8 @@ function fuzzyMatchRecursive(
maxMatches,
nextMatch,
recursionCount,
recursionLimit
recursionLimit,
weights
) {
let outScore = 0;
@@ -110,7 +143,8 @@ function fuzzyMatchRecursive(
maxMatches,
nextMatch,
recursionCount,
recursionLimit
recursionLimit,
weights
);
if (matched) {
@@ -134,16 +168,16 @@ function fuzzyMatchRecursive(
outScore = 100;
// Apply leading letter penalty
let penalty = LEADING_LETTER_PENALTY * matches[0];
let penalty = weights.leadingLetterPenalty * matches[0];
penalty =
penalty < MAX_LEADING_LETTER_PENALTY ?
MAX_LEADING_LETTER_PENALTY :
penalty < weights.maxLeadingLetterPenalty ?
weights.maxLeadingLetterPenalty :
penalty;
outScore += penalty;
// Apply unmatched penalty
const unmatched = str.length - nextMatch;
outScore += UNMATCHED_LETTER_PENALTY * unmatched;
outScore += weights.unmatchedLetterPenalty * unmatched;
// Apply ordering bonuses
for (let i = 0; i < nextMatch; i++) {
@@ -152,7 +186,7 @@ function fuzzyMatchRecursive(
if (i > 0) {
const prevIdx = matches[i - 1];
if (currIdx === prevIdx + 1) {
outScore += SEQUENTIAL_BONUS;
outScore += weights.sequentialBonus;
}
}
@@ -165,15 +199,15 @@ function fuzzyMatchRecursive(
neighbor !== neighbor.toUpperCase() &&
curr !== curr.toLowerCase()
) {
outScore += CAMEL_BONUS;
outScore += weights.camelBonus;
}
const isNeighbourSeparator = neighbor === "_" || neighbor === " ";
if (isNeighbourSeparator) {
outScore += SEPARATOR_BONUS;
outScore += weights.separatorBonus;
}
} else {
// First letter
outScore += FIRST_LETTER_BONUS;
outScore += weights.firstLetterBonus;
}
}
+4
View File
@@ -7,6 +7,7 @@
*/
import Utils from "../Utils.mjs";
import OperationError from "../errors/OperationError.mjs";
/**
@@ -100,6 +101,9 @@ export function toHexFast(data) {
* fromHex("0a:14:1e", "Colon");
*/
export function fromHex(data, delim="Auto", byteLen=2) {
if (byteLen < 1 || Math.round(byteLen) !== byteLen)
throw new OperationError("Byte length must be a positive integer");
if (delim !== "None") {
const delimRegex = delim === "Auto" ? /[^a-f\d]|(0x)/gi : Utils.regexRep(delim);
data = data.replace(delimRegex, "");
+2 -2
View File
@@ -15,7 +15,7 @@ import { toHex, fromHex } from "./Hex.mjs";
* @param {number} indent
* @returns {string}
*/
export function formatDnStr (dnStr, indent) {
export function formatDnStr(dnStr, indent) {
const fields = dnStr.substr(1).replace(/([^\\])\//g, "$1$1/").split(/[^\\]\//);
let output = "",
maxKeyLen = 0,
@@ -54,7 +54,7 @@ export function formatDnStr (dnStr, indent) {
* @param {number} indent
* @returns {string}
*/
export function formatByteStr (byteStr, length, indent) {
export function formatByteStr(byteStr, length, indent) {
byteStr = toHex(fromHex(byteStr), ":");
length = length * 3;
let output = "";
+16 -1
View File
@@ -21,9 +21,24 @@ class ExtractFiles extends Operation {
constructor() {
super();
// Get the first extension for each signature that can be extracted
let supportedExts = Object.keys(FILE_SIGNATURES).map(cat => {
return FILE_SIGNATURES[cat]
.filter(sig => sig.extractor)
.map(sig => sig.extension.toUpperCase());
});
// Flatten categories and remove duplicates
supportedExts = [].concat(...supportedExts).unique();
this.name = "Extract Files";
this.module = "Default";
this.description = "Performs file carving to attempt to extract files from the input.<br><br>This operation is currently capable of carving out the following formats:<ul><li>JPG</li><li>EXE</li><li>ZIP</li><li>PDF</li><li>PNG</li><li>BMP</li><li>FLV</li><li>RTF</li><li>DOCX, PPTX, XLSX</li><li>EPUB</li><li>GZIP</li><li>ZLIB</li><li>ELF, BIN, AXF, O, PRX, SO</li></ul>";
this.description = `Performs file carving to attempt to extract files from the input.<br><br>This operation is currently capable of carving out the following formats:
<ul>
<li>
${supportedExts.join("</li><li>")}
</li>
</ul>`;
this.infoURL = "https://forensicswiki.xyz/wiki/index.php?title=File_Carving";
this.inputType = "ArrayBuffer";
this.outputType = "List<File>";
+20
View File
@@ -102,6 +102,26 @@ class FromBase64 extends Operation {
flags: "i",
args: ["./0-9A-Za-z", true]
},
{
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]
},
{
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]
},
{
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]
},
{
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]
}
];
}
+2 -1
View File
@@ -35,7 +35,8 @@ class FromBinary extends Operation {
{
"name": "Byte Length",
"type": "number",
"value": 8
"value": 8,
"min": 1
}
];
this.checks = [
+121
View File
@@ -0,0 +1,121 @@
/**
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2021
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import {fuzzyMatch, calcMatchRanges, DEFAULT_WEIGHTS} from "../lib/FuzzyMatch.mjs";
import Utils from "../Utils.mjs";
/**
* Fuzzy Match operation
*/
class FuzzyMatch extends Operation {
/**
* FuzzyMatch constructor
*/
constructor() {
super();
this.name = "Fuzzy Match";
this.module = "Default";
this.description = "Conducts a fuzzy search to find a pattern within the input based on weighted criteria.<br><br>e.g. A search for <code>dpan</code> will match on <code><b>D</b>on't <b>Pan</b>ic</code>";
this.infoURL = "https://wikipedia.org/wiki/Fuzzy_matching_(computer-assisted_translation)";
this.inputType = "string";
this.outputType = "html";
this.args = [
{
name: "Search",
type: "binaryString",
value: ""
},
{
name: "Sequential bonus",
type: "number",
value: DEFAULT_WEIGHTS.sequentialBonus,
hint: "Bonus for adjacent matches"
},
{
name: "Separator bonus",
type: "number",
value: DEFAULT_WEIGHTS.separatorBonus,
hint: "Bonus if match occurs after a separator"
},
{
name: "Camel bonus",
type: "number",
value: DEFAULT_WEIGHTS.camelBonus,
hint: "Bonus if match is uppercase and previous is lower"
},
{
name: "First letter bonus",
type: "number",
value: DEFAULT_WEIGHTS.firstLetterBonus,
hint: "Bonus if the first letter is matched"
},
{
name: "Leading letter penalty",
type: "number",
value: DEFAULT_WEIGHTS.leadingLetterPenalty,
hint: "Penalty applied for every letter in the input before the first match"
},
{
name: "Max leading letter penalty",
type: "number",
value: DEFAULT_WEIGHTS.maxLeadingLetterPenalty,
hint: "Maxiumum penalty for leading letters"
},
{
name: "Unmatched letter penalty",
type: "number",
value: DEFAULT_WEIGHTS.unmatchedLetterPenalty
},
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {html}
*/
run(input, args) {
const searchStr = args[0];
const weights = {
sequentialBonus: args[1],
separatorBonus: args[2],
camelBonus: args[3],
firstLetterBonus: args[4],
leadingLetterPenalty: args[5],
maxLeadingLetterPenalty: args[6],
unmatchedLetterPenalty: args[7]
};
const matches = fuzzyMatch(searchStr, input, true, weights);
if (!matches) {
return "No matches.";
}
let result = "", pos = 0, hlClass = "hl1";
matches.forEach(([matches, score, idxs]) => {
const matchRanges = calcMatchRanges(idxs);
matchRanges.forEach(([start, length], i) => {
result += Utils.escapeHtml(input.slice(pos, start));
if (i === 0) result += `<span class="${hlClass}">`;
pos = start + length;
result += `<b>${Utils.escapeHtml(input.slice(start, pos))}</b>`;
});
result += "</span>";
hlClass = hlClass === "hl1" ? "hl2" : "hl1";
});
result += Utils.escapeHtml(input.slice(pos, input.length));
return result;
}
}
export default FuzzyMatch;
+10 -7
View File
@@ -43,15 +43,16 @@ class JSONToCSV extends Operation {
/**
* Converts JSON to a CSV equivalent.
*
* @param {boolean} force - Whether to force conversion of data to fit in a cell
* @returns {string}
*/
toCSV() {
toCSV(force=false) {
const self = this;
// If the JSON is an array of arrays, this is easy
if (this.flattened[0] instanceof Array) {
return this.flattened
.map(row => row
.map(self.escapeCellContents.bind(self))
.map(d => self.escapeCellContents(d, force))
.join(this.cellDelim)
)
.join(this.rowDelim) +
@@ -61,13 +62,13 @@ class JSONToCSV extends Operation {
// If it's an array of dictionaries...
const header = Object.keys(this.flattened[0]);
return header
.map(self.escapeCellContents.bind(self))
.map(d => self.escapeCellContents(d, force))
.join(this.cellDelim) +
this.rowDelim +
this.flattened
.map(row => header
.map(h => row[h])
.map(self.escapeCellContents.bind(self))
.map(d => self.escapeCellContents(d, force))
.join(this.cellDelim)
)
.join(this.rowDelim) +
@@ -98,7 +99,7 @@ class JSONToCSV extends Operation {
if (!(this.flattened instanceof Array)) {
this.flattened = [this.flattened];
}
return this.toCSV();
return this.toCSV(true);
} catch (err) {
throw new OperationError("Unable to parse JSON to CSV: " + err.toString());
}
@@ -109,15 +110,17 @@ class JSONToCSV extends Operation {
* Correctly escapes a cell's contents based on the cell and row delimiters.
*
* @param {string} data
* @param {boolean} force - Whether to force conversion of data to fit in a cell
* @returns {string}
*/
escapeCellContents(data) {
escapeCellContents(data, force=false) {
if (typeof data === "number") data = data.toString();
if (force && typeof data !== "string") data = JSON.stringify(data);
// Double quotes should be doubled up
data = data.replace(/"/g, '""');
// If the cell contains a cell or row delimiter or a double quote, it mut be enclosed in double quotes
// If the cell contains a cell or row delimiter or a double quote, it must be enclosed in double quotes
if (
data.indexOf(this.cellDelim) >= 0 ||
data.indexOf(this.rowDelim) >= 0 ||
+2 -2
View File
@@ -185,7 +185,7 @@ class RegularExpression extends Operation {
* @param {boolean} captureGroups - Display each of the capture groups separately
* @returns {string}
*/
function regexList (input, regex, displayTotal, matches, captureGroups) {
function regexList(input, regex, displayTotal, matches, captureGroups) {
let output = "",
total = 0,
match;
@@ -225,7 +225,7 @@ function regexList (input, regex, displayTotal, matches, captureGroups) {
* @param {boolean} displayTotal
* @returns {string}
*/
function regexHighlight (input, regex, displayTotal) {
function regexHighlight(input, regex, displayTotal) {
let output = "",
title = "",
hl = 1,
+6 -1
View File
@@ -6,6 +6,7 @@
import Operation from "../Operation.mjs";
import Utils from "../Utils.mjs";
import OperationError from "../errors/OperationError.mjs";
/**
* To Hexdump operation
@@ -28,7 +29,8 @@ class ToHexdump extends Operation {
{
"name": "Width",
"type": "number",
"value": 16
"value": 16,
"min": 1
},
{
"name": "Upper case hex",
@@ -58,6 +60,9 @@ class ToHexdump extends Operation {
const [length, upperCase, includeFinalLength, unixFormat] = args;
const padding = 2;
if (length < 1 || Math.round(length) !== length)
throw new OperationError("Width must be a positive integer");
let output = "";
for (let i = 0; i < data.length; i += length) {
const buff = data.slice(i, i+length);
+1 -1
View File
@@ -725,7 +725,7 @@ class App {
this.progress = 0;
this.autoBake();
this.updateTitle(false, null, true);
this.updateTitle(true, null, true);
}
+4 -2
View File
@@ -100,7 +100,7 @@ class ControlsWaiter {
const includeRecipe = document.getElementById("save-link-recipe-checkbox").checked;
const includeInput = document.getElementById("save-link-input-checkbox").checked;
const saveLinkEl = document.getElementById("save-link");
const saveLink = this.generateStateUrl(includeRecipe, includeInput, recipeConfig);
const saveLink = this.generateStateUrl(includeRecipe, includeInput, null, recipeConfig);
saveLinkEl.innerHTML = Utils.escapeHtml(Utils.truncate(saveLink, 120));
saveLinkEl.setAttribute("href", saveLink);
@@ -128,11 +128,13 @@ class ControlsWaiter {
includeRecipe = includeRecipe && (recipeConfig.length > 0);
// If we don't get passed an input, get it from the current URI
if (input === null) {
if (input === null && includeInput) {
const params = this.app.getURIParams();
if (params.input) {
includeInput = true;
input = params.input;
} else {
includeInput = false;
}
}
+1 -1
View File
@@ -6,7 +6,7 @@
import HTMLOperation from "../HTMLOperation.mjs";
import Sortable from "sortablejs";
import {fuzzyMatch, calcMatchRanges} from "../../core/lib/FuzzySearch.mjs";
import {fuzzyMatch, calcMatchRanges} from "../../core/lib/FuzzyMatch.mjs";
/**