mirror of
https://github.com/gchq/CyberChef
synced 2024-11-15 00:57:08 +00:00
Merge branch 'esm' into node-lib
This commit is contained in:
commit
0977e82170
293 changed files with 32051 additions and 14655 deletions
|
@ -1,2 +1,2 @@
|
|||
src/core/vendor/**
|
||||
src/core/operations/legacy/**
|
||||
src/core/operations/legacy/**
|
||||
|
|
30
Gruntfile.js
30
Gruntfile.js
|
@ -22,11 +22,11 @@ module.exports = function (grunt) {
|
|||
// Tasks
|
||||
grunt.registerTask("dev",
|
||||
"A persistent task which creates a development build whenever source files are modified.",
|
||||
["clean:dev", "webpack-dev-server:start"]);
|
||||
["clean:dev", "exec:generateConfig", "concurrent:dev"]);
|
||||
|
||||
grunt.registerTask("node",
|
||||
"Compiles CyberChef into a single NodeJS module.",
|
||||
["clean:node", "clean:config", "webpack:node", "chmod:build"]);
|
||||
["clean:node", "clean:config", "exec:generateConfig", "webpack:node", "chmod:build"]);
|
||||
|
||||
grunt.registerTask("test",
|
||||
"A task which runs all the tests in test/tests.",
|
||||
|
@ -38,7 +38,7 @@ module.exports = function (grunt) {
|
|||
|
||||
grunt.registerTask("prod",
|
||||
"Creates a production-ready build. Use the --msg flag to add a compile message.",
|
||||
["eslint", "clean:prod", "webpack:web", "inline", "chmod"]);
|
||||
["eslint", "clean:prod", "exec:generateConfig", "webpack:web", "inline", "chmod"]);
|
||||
|
||||
grunt.registerTask("default",
|
||||
"Lints the code base",
|
||||
|
@ -46,7 +46,7 @@ module.exports = function (grunt) {
|
|||
|
||||
grunt.registerTask("inline",
|
||||
"Compiles a production build of CyberChef into a single, portable web page.",
|
||||
["webpack:webInline", "runInliner", "clean:inlineScripts"]);
|
||||
["exec:generateConfig", "webpack:webInline", "runInliner", "clean:inlineScripts"]);
|
||||
|
||||
|
||||
grunt.registerTask("runInliner", runInliner);
|
||||
|
@ -61,9 +61,11 @@ module.exports = function (grunt) {
|
|||
grunt.loadNpmTasks("grunt-jsdoc");
|
||||
grunt.loadNpmTasks("grunt-contrib-clean");
|
||||
grunt.loadNpmTasks("grunt-contrib-copy");
|
||||
grunt.loadNpmTasks("grunt-contrib-watch");
|
||||
grunt.loadNpmTasks("grunt-chmod");
|
||||
grunt.loadNpmTasks("grunt-exec");
|
||||
grunt.loadNpmTasks("grunt-accessibility");
|
||||
grunt.loadNpmTasks("grunt-concurrent");
|
||||
|
||||
|
||||
// Project configuration
|
||||
|
@ -278,7 +280,7 @@ module.exports = function (grunt) {
|
|||
chunks: false,
|
||||
modules: false,
|
||||
entrypoints: false,
|
||||
warningsFilter: /source-map/,
|
||||
warningsFilter: [/source-map/, /dependency is an expression/],
|
||||
}
|
||||
},
|
||||
start: {
|
||||
|
@ -348,6 +350,18 @@ module.exports = function (grunt) {
|
|||
src: ["docs/**/*", "docs/"]
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
config: {
|
||||
files: ["src/core/operations/**/*", "!src/core/operations/index.mjs"],
|
||||
tasks: ["exec:generateConfig"]
|
||||
}
|
||||
},
|
||||
concurrent: {
|
||||
dev: ["watch:config", "webpack-dev-server:start"],
|
||||
options: {
|
||||
logConcurrentOutput: true
|
||||
}
|
||||
},
|
||||
exec: {
|
||||
repoSize: {
|
||||
command: [
|
||||
|
@ -364,9 +378,13 @@ module.exports = function (grunt) {
|
|||
},
|
||||
generateConfig: {
|
||||
command: [
|
||||
"echo '\n--- Regenerating config files. ---'",
|
||||
"mkdir -p src/core/config/modules",
|
||||
"echo 'export default {};\n' > src/core/config/modules/OpModules.mjs",
|
||||
"echo '[]\n' > src/core/config/OperationConfig.json",
|
||||
"node --experimental-modules src/core/config/scripts/generateOpsIndex.mjs",
|
||||
"node --experimental-modules src/core/config/scripts/generateConfig.mjs",
|
||||
"echo ---\nConfig scripts finished.\n---\n"
|
||||
"echo '--- Config scripts finished. ---\n'"
|
||||
].join(";")
|
||||
},
|
||||
tests: {
|
||||
|
|
6272
package-lock.json
generated
6272
package-lock.json
generated
File diff suppressed because it is too large
Load diff
66
package.json
66
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "cyberchef",
|
||||
"version": "7.9.0",
|
||||
"version": "7.11.1",
|
||||
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
|
||||
"author": "n1474335 <n1474335@gmail.com>",
|
||||
"homepage": "https://gchq.github.io/CyberChef",
|
||||
|
@ -30,60 +30,64 @@
|
|||
"main": "build/node/CyberChef.js",
|
||||
"bugs": "https://github.com/gchq/CyberChef/issues",
|
||||
"devDependencies": {
|
||||
"babel-core": "^6.26.0",
|
||||
"babel-loader": "^7.1.3",
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-loader": "^7.1.4",
|
||||
"babel-preset-env": "^1.6.1",
|
||||
"css-loader": "^0.28.10",
|
||||
"eslint": "^4.18.1",
|
||||
"css-loader": "^0.28.11",
|
||||
"eslint": "^4.19.1",
|
||||
"exports-loader": "^0.7.0",
|
||||
"extract-text-webpack-plugin": "^4.0.0-alpha0",
|
||||
"file-loader": "^1.1.10",
|
||||
"file-loader": "^1.1.11",
|
||||
"grunt": ">=1.0.2",
|
||||
"grunt-accessibility": "~6.0.0",
|
||||
"grunt-chmod": "~1.1.1",
|
||||
"grunt-concurrent": "^2.3.1",
|
||||
"grunt-contrib-clean": "~1.1.0",
|
||||
"grunt-contrib-copy": "~1.0.0",
|
||||
"grunt-contrib-watch": "^1.0.1",
|
||||
"grunt-eslint": "^20.1.0",
|
||||
"grunt-exec": "~3.0.0",
|
||||
"grunt-jsdoc": "^2.2.1",
|
||||
"grunt-webpack": "^3.0.2",
|
||||
"html-webpack-plugin": "^3.0.4",
|
||||
"grunt-webpack": "^3.1.1",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"imports-loader": "^0.8.0",
|
||||
"ink-docstrap": "^1.3.2",
|
||||
"jsdoc-babel": "^0.3.0",
|
||||
"less": "^3.0.1",
|
||||
"less-loader": "^4.0.6",
|
||||
"postcss-css-variables": "^0.8.0",
|
||||
"js-to-mjs": "^0.2.0",
|
||||
"jsdoc-babel": "^0.4.0",
|
||||
"less": "^3.0.2",
|
||||
"less-loader": "^4.1.0",
|
||||
"postcss-css-variables": "^0.8.1",
|
||||
"postcss-import": "^11.1.0",
|
||||
"postcss-loader": "^2.1.1",
|
||||
"postcss-loader": "^2.1.4",
|
||||
"sitemap": "^1.13.0",
|
||||
"style-loader": "^0.20.2",
|
||||
"url-loader": "^0.6.2",
|
||||
"style-loader": "^0.21.0",
|
||||
"url-loader": "^1.0.1",
|
||||
"web-resource-inliner": "^4.2.1",
|
||||
"webpack": "^4.0.1",
|
||||
"webpack-dev-server": "^3.1.0",
|
||||
"webpack-node-externals": "^1.6.0",
|
||||
"webpack-synchronizable-shell-plugin": "0.0.7",
|
||||
"webpack": "^4.6.0",
|
||||
"webpack-dev-server": "^3.1.3",
|
||||
"webpack-node-externals": "^1.7.2",
|
||||
"worker-loader": "^1.1.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"babel-plugin-transform-builtin-extend": "1.1.2",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"bignumber.js": "^6.0.0",
|
||||
"bignumber.js": "^7.0.1",
|
||||
"bootstrap": "^3.3.7",
|
||||
"bootstrap-colorpicker": "^2.5.2",
|
||||
"bootstrap-switch": "^3.3.4",
|
||||
"bson": "^2.0.4",
|
||||
"bson": "^2.0.6",
|
||||
"chi-squared": "^1.1.0",
|
||||
"crypto-api": "^0.8.0",
|
||||
"crypto-js": "^3.1.9-1",
|
||||
"ctph.js": "0.0.5",
|
||||
"diff": "^3.4.0",
|
||||
"diff": "^3.5.0",
|
||||
"escodegen": "^1.9.1",
|
||||
"es6-promisify": "^6.0.0",
|
||||
"esmangle": "^1.0.1",
|
||||
"esprima": "^4.0.0",
|
||||
"exif-parser": "^0.1.12",
|
||||
"file-saver": "^1.3.3",
|
||||
"file-saver": "^1.3.8",
|
||||
"highlight.js": "^9.12.0",
|
||||
"jquery": "^3.3.1",
|
||||
"js-crc": "^0.2.0",
|
||||
|
@ -91,15 +95,16 @@
|
|||
"jsbn": "^1.1.0",
|
||||
"jsesc": "^2.5.1",
|
||||
"jsonpath": "^1.0.0",
|
||||
"jsrsasign": "8.0.6",
|
||||
"lodash": "^4.17.5",
|
||||
"jsrsasign": "8.0.12",
|
||||
"lodash": "^4.17.10",
|
||||
"loglevel": "^1.6.1",
|
||||
"kbpgp": "^2.0.77",
|
||||
"loglevel-message-prefix": "^3.0.0",
|
||||
"moment": "^2.20.1",
|
||||
"moment-timezone": "^0.5.14",
|
||||
"node-forge": "^0.7.2",
|
||||
"moment": "^2.22.1",
|
||||
"moment-timezone": "^0.5.16",
|
||||
"node-forge": "^0.7.5",
|
||||
"node-md6": "^0.1.0",
|
||||
"nwmatcher": "^1.4.3",
|
||||
"nwmatcher": "^1.4.4",
|
||||
"otp": "^0.1.3",
|
||||
"scryptsy": "^2.0.0",
|
||||
"sladex-blowfish": "^0.8.1",
|
||||
|
@ -120,6 +125,7 @@
|
|||
"test": "grunt test",
|
||||
"docs": "grunt docs",
|
||||
"lint": "grunt lint",
|
||||
"build-node": "grunt node"
|
||||
"build-node": "grunt node",
|
||||
"postinstall": "[ -f node_modules/crypto-api/src/crypto-api.mjs ] || npx j2m node_modules/crypto-api/src/crypto-api.js"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,6 +60,12 @@ class Chef {
|
|||
recipe.setBreakpoint(progress + 1, true);
|
||||
}
|
||||
|
||||
// If the previously run operation presented a different value to its
|
||||
// normal output, we need to recalculate it.
|
||||
if (recipe.lastOpPresented(progress)) {
|
||||
progress = 0;
|
||||
}
|
||||
|
||||
// If stepping with flow control, we have to start from the beginning
|
||||
// but still want to skip all previous breakpoints
|
||||
if (progress > 0 && containsFc) {
|
||||
|
|
|
@ -91,7 +91,7 @@ self.addEventListener("message", function(e) {
|
|||
*/
|
||||
async function bake(data) {
|
||||
// Ensure the relevant modules are loaded
|
||||
loadRequiredModules(data.recipeConfig);
|
||||
self.loadRequiredModules(data.recipeConfig);
|
||||
|
||||
try {
|
||||
const response = await self.chef.bake(
|
||||
|
@ -144,25 +144,6 @@ async function getDishAs(data) {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks that all required modules are loaded and loads them if not.
|
||||
*
|
||||
* @param {Object} recipeConfig
|
||||
*/
|
||||
function loadRequiredModules(recipeConfig) {
|
||||
recipeConfig.forEach(op => {
|
||||
const module = self.OperationConfig[op.op].module;
|
||||
|
||||
if (!OpModules.hasOwnProperty(module)) {
|
||||
log.info("Loading module " + module);
|
||||
self.sendStatusMessage("Loading module " + module);
|
||||
self.importScripts(self.docURL + "/" + module + ".js");
|
||||
self.sendStatusMessage("");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates highlight offsets if possible.
|
||||
*
|
||||
|
@ -182,6 +163,25 @@ function calculateHighlights(recipeConfig, direction, pos) {
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks that all required modules are loaded and loads them if not.
|
||||
*
|
||||
* @param {Object} recipeConfig
|
||||
*/
|
||||
self.loadRequiredModules = function(recipeConfig) {
|
||||
recipeConfig.forEach(op => {
|
||||
const module = self.OperationConfig[op.op].module;
|
||||
|
||||
if (!OpModules.hasOwnProperty(module)) {
|
||||
log.info(`Loading ${module} module`);
|
||||
self.sendStatusMessage(`Loading ${module} module`);
|
||||
self.importScripts(`${self.docURL}/${module}.js`);
|
||||
self.sendStatusMessage("");
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Send status update to the app.
|
||||
*
|
||||
|
|
|
@ -1,291 +0,0 @@
|
|||
import Recipe from "./Recipe";
|
||||
import Dish from "./Dish";
|
||||
|
||||
|
||||
/**
|
||||
* Flow Control operations.
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*
|
||||
* @namespace
|
||||
*/
|
||||
const FlowControl = {
|
||||
|
||||
/**
|
||||
* Fork operation.
|
||||
*
|
||||
* @param {Object} state - The current state of the recipe.
|
||||
* @param {number} state.progress - The current position in the recipe.
|
||||
* @param {Dish} state.dish - The Dish being operated on.
|
||||
* @param {Operation[]} state.opList - The list of operations in the recipe.
|
||||
* @returns {Object} The updated state of the recipe.
|
||||
*/
|
||||
runFork: async function(state) {
|
||||
const opList = state.opList,
|
||||
inputType = opList[state.progress].inputType,
|
||||
outputType = opList[state.progress].outputType,
|
||||
input = await state.dish.get(inputType),
|
||||
ings = opList[state.progress].ingValues,
|
||||
splitDelim = ings[0],
|
||||
mergeDelim = ings[1],
|
||||
ignoreErrors = ings[2],
|
||||
subOpList = [];
|
||||
let inputs = [],
|
||||
i;
|
||||
|
||||
if (input)
|
||||
inputs = input.split(splitDelim);
|
||||
|
||||
// Create subOpList for each tranche to operate on
|
||||
// (all remaining operations unless we encounter a Merge)
|
||||
for (i = state.progress + 1; i < opList.length; i++) {
|
||||
if (opList[i].name === "Merge" && !opList[i].disabled) {
|
||||
break;
|
||||
} else {
|
||||
subOpList.push(opList[i]);
|
||||
}
|
||||
}
|
||||
|
||||
const recipe = new Recipe();
|
||||
let output = "",
|
||||
progress = 0;
|
||||
|
||||
state.forkOffset += state.progress + 1;
|
||||
|
||||
recipe.addOperations(subOpList);
|
||||
|
||||
// Take a deep(ish) copy of the ingredient values
|
||||
const ingValues = subOpList.map(op => JSON.parse(JSON.stringify(op.ingValues)));
|
||||
|
||||
// Run recipe over each tranche
|
||||
for (i = 0; i < inputs.length; i++) {
|
||||
log.debug(`Entering tranche ${i + 1} of ${inputs.length}`);
|
||||
|
||||
// Baseline ing values for each tranche so that registers are reset
|
||||
subOpList.forEach((op, i) => {
|
||||
op.ingValues = JSON.parse(JSON.stringify(ingValues[i]));
|
||||
});
|
||||
|
||||
const dish = new Dish();
|
||||
dish.set(inputs[i], inputType);
|
||||
|
||||
try {
|
||||
progress = await recipe.execute(dish, 0, state);
|
||||
} catch (err) {
|
||||
if (!ignoreErrors) {
|
||||
throw err;
|
||||
}
|
||||
progress = err.progress + 1;
|
||||
}
|
||||
output += await dish.get(outputType) + mergeDelim;
|
||||
}
|
||||
|
||||
state.dish.set(output, outputType);
|
||||
state.progress += progress;
|
||||
return state;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Merge operation.
|
||||
*
|
||||
* @param {Object} state - The current state of the recipe.
|
||||
* @param {number} state.progress - The current position in the recipe.
|
||||
* @param {Dish} state.dish - The Dish being operated on.
|
||||
* @param {Operation[]} state.opList - The list of operations in the recipe.
|
||||
* @returns {Object} The updated state of the recipe.
|
||||
*/
|
||||
runMerge: function(state) {
|
||||
// No need to actually do anything here. The fork operation will
|
||||
// merge when it sees this operation.
|
||||
return state;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Register operation.
|
||||
*
|
||||
* @param {Object} state - The current state of the recipe.
|
||||
* @param {number} state.progress - The current position in the recipe.
|
||||
* @param {Dish} state.dish - The Dish being operated on.
|
||||
* @param {Operation[]} state.opList - The list of operations in the recipe.
|
||||
* @returns {Object} The updated state of the recipe.
|
||||
*/
|
||||
runRegister: async function(state) {
|
||||
const ings = state.opList[state.progress].ingValues,
|
||||
extractorStr = ings[0],
|
||||
i = ings[1],
|
||||
m = ings[2];
|
||||
|
||||
let modifiers = "";
|
||||
if (i) modifiers += "i";
|
||||
if (m) modifiers += "m";
|
||||
|
||||
const extractor = new RegExp(extractorStr, modifiers),
|
||||
input = await state.dish.get(Dish.STRING),
|
||||
registers = input.match(extractor);
|
||||
|
||||
if (!registers) return state;
|
||||
|
||||
if (ENVIRONMENT_IS_WORKER()) {
|
||||
self.setRegisters(state.forkOffset + state.progress, state.numRegisters, registers.slice(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces references to registers (e.g. $R0) with the contents of those registers.
|
||||
*
|
||||
* @param {string} str
|
||||
* @returns {string}
|
||||
*/
|
||||
function replaceRegister(str) {
|
||||
// Replace references to registers ($Rn) with contents of registers
|
||||
return str.replace(/(\\*)\$R(\d{1,2})/g, (match, slashes, regNum) => {
|
||||
const index = parseInt(regNum, 10) + 1;
|
||||
if (index <= state.numRegisters || index >= state.numRegisters + registers.length)
|
||||
return match;
|
||||
if (slashes.length % 2 !== 0) return match.slice(1); // Remove escape
|
||||
return slashes + registers[index - state.numRegisters];
|
||||
});
|
||||
}
|
||||
|
||||
// Step through all subsequent ops and replace registers in args with extracted content
|
||||
for (let i = state.progress + 1; i < state.opList.length; i++) {
|
||||
if (state.opList[i].disabled) continue;
|
||||
|
||||
let args = state.opList[i].ingValues;
|
||||
args = args.map(arg => {
|
||||
if (typeof arg !== "string" && typeof arg !== "object") return arg;
|
||||
|
||||
if (typeof arg === "object" && arg.hasOwnProperty("string")) {
|
||||
arg.string = replaceRegister(arg.string);
|
||||
return arg;
|
||||
}
|
||||
return replaceRegister(arg);
|
||||
});
|
||||
state.opList[i].setIngValues(args);
|
||||
}
|
||||
|
||||
state.numRegisters += registers.length - 1;
|
||||
return state;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Jump operation.
|
||||
*
|
||||
* @param {Object} state - The current state of the recipe.
|
||||
* @param {number} state.progress - The current position in the recipe.
|
||||
* @param {Dish} state.dish - The Dish being operated on.
|
||||
* @param {Operation[]} state.opList - The list of operations in the recipe.
|
||||
* @param {number} state.numJumps - The number of jumps taken so far.
|
||||
* @returns {Object} The updated state of the recipe.
|
||||
*/
|
||||
runJump: function(state) {
|
||||
const ings = state.opList[state.progress].ingValues,
|
||||
label = ings[0],
|
||||
maxJumps = ings[1],
|
||||
jmpIndex = FlowControl._getLabelIndex(label, state);
|
||||
|
||||
if (state.numJumps >= maxJumps || jmpIndex === -1) {
|
||||
log.debug("Maximum jumps reached or label cannot be found");
|
||||
return state;
|
||||
}
|
||||
|
||||
state.progress = jmpIndex;
|
||||
state.numJumps++;
|
||||
log.debug(`Jumping to label '${label}' at position ${jmpIndex} (jumps = ${state.numJumps})`);
|
||||
return state;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Conditional Jump operation.
|
||||
*
|
||||
* @param {Object} state - The current state of the recipe.
|
||||
* @param {number} state.progress - The current position in the recipe.
|
||||
* @param {Dish} state.dish - The Dish being operated on.
|
||||
* @param {Operation[]} state.opList - The list of operations in the recipe.
|
||||
* @param {number} state.numJumps - The number of jumps taken so far.
|
||||
* @returns {Object} The updated state of the recipe.
|
||||
*/
|
||||
runCondJump: async function(state) {
|
||||
const ings = state.opList[state.progress].ingValues,
|
||||
dish = state.dish,
|
||||
regexStr = ings[0],
|
||||
invert = ings[1],
|
||||
label = ings[2],
|
||||
maxJumps = ings[3],
|
||||
jmpIndex = FlowControl._getLabelIndex(label, state);
|
||||
|
||||
if (state.numJumps >= maxJumps || jmpIndex === -1) {
|
||||
log.debug("Maximum jumps reached or label cannot be found");
|
||||
return state;
|
||||
}
|
||||
|
||||
if (regexStr !== "") {
|
||||
const strMatch = await dish.get(Dish.STRING).search(regexStr) > -1;
|
||||
if (!invert && strMatch || invert && !strMatch) {
|
||||
state.progress = jmpIndex;
|
||||
state.numJumps++;
|
||||
log.debug(`Jumping to label '${label}' at position ${jmpIndex} (jumps = ${state.numJumps})`);
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Return operation.
|
||||
*
|
||||
* @param {Object} state - The current state of the recipe.
|
||||
* @param {number} state.progress - The current position in the recipe.
|
||||
* @param {Dish} state.dish - The Dish being operated on.
|
||||
* @param {Operation[]} state.opList - The list of operations in the recipe.
|
||||
* @returns {Object} The updated state of the recipe.
|
||||
*/
|
||||
runReturn: function(state) {
|
||||
state.progress = state.opList.length;
|
||||
return state;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Comment operation.
|
||||
*
|
||||
* @param {Object} state - The current state of the recipe.
|
||||
* @param {number} state.progress - The current position in the recipe.
|
||||
* @param {Dish} state.dish - The Dish being operated on.
|
||||
* @param {Operation[]} state.opList - The list of operations in the recipe.
|
||||
* @returns {Object} The updated state of the recipe.
|
||||
*/
|
||||
runComment: function(state) {
|
||||
return state;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Returns the index of a label.
|
||||
*
|
||||
* @private
|
||||
* @param {Object} state
|
||||
* @param {string} name
|
||||
* @returns {number}
|
||||
*/
|
||||
_getLabelIndex: function(name, state) {
|
||||
for (let o = 0; o < state.opList.length; o++) {
|
||||
const operation = state.opList[o];
|
||||
if (operation.name === "Label"){
|
||||
const ings = operation.ingValues;
|
||||
if (name === ings[0]) {
|
||||
return o;
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
},
|
||||
};
|
||||
|
||||
export default FlowControl;
|
|
@ -21,6 +21,7 @@ class Ingredient {
|
|||
this.name = "";
|
||||
this.type = "";
|
||||
this._value = null;
|
||||
this.toggleValues = [];
|
||||
|
||||
if (ingredientConfig) {
|
||||
this._parseConfig(ingredientConfig);
|
||||
|
@ -38,6 +39,7 @@ class Ingredient {
|
|||
this.name = ingredientConfig.name;
|
||||
this.type = ingredientConfig.type;
|
||||
this.defaultValue = ingredientConfig.value;
|
||||
this.toggleValues = ingredientConfig.toggleValues;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -81,9 +81,10 @@ class Operation {
|
|||
* this behaviour.
|
||||
*
|
||||
* @param {*} data - The result of the run() function
|
||||
* @param {Object[]} args - The operation's arguments
|
||||
* @returns {*} - A human-readable version of the data
|
||||
*/
|
||||
present(data) {
|
||||
present(data, args) {
|
||||
return data;
|
||||
}
|
||||
|
||||
|
@ -172,7 +173,8 @@ class Operation {
|
|||
return {
|
||||
name: ing.name,
|
||||
type: ing.type,
|
||||
value: ing.defaultValue
|
||||
value: ing.defaultValue,
|
||||
toggleValues: ing.toggleValues || []
|
||||
};
|
||||
});
|
||||
}
|
||||
|
@ -186,7 +188,7 @@ class Operation {
|
|||
get config() {
|
||||
return {
|
||||
"op": this.name,
|
||||
"args": this._ingList.map(ing => ing.conf)
|
||||
"args": this._ingList.map(ing => ing.config)
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -272,6 +274,15 @@ class Operation {
|
|||
return this._flowControl;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether this Operation is a flowcontrol op.
|
||||
*
|
||||
* @param {boolean} value
|
||||
*/
|
||||
set flowControl(value) {
|
||||
this._flowControl = !!value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Operation;
|
||||
|
|
|
@ -172,12 +172,15 @@ class Recipe {
|
|||
numRegisters = state.numRegisters;
|
||||
} else {
|
||||
output = await op.run(input, op.ingValues);
|
||||
this.lastRunOp = op;
|
||||
dish.set(output, op.outputType);
|
||||
}
|
||||
this.lastRunOp = op;
|
||||
} catch (err) {
|
||||
// Return expected errors as output
|
||||
if (err instanceof OperationError) {
|
||||
if (err instanceof OperationError ||
|
||||
(err.type && err.type === "OperationError")) {
|
||||
// Cannot rely on `err instanceof OperationError` here as extending
|
||||
// native types is not fully supported yet.
|
||||
dish.set(err.message, "string");
|
||||
return i;
|
||||
} else {
|
||||
|
@ -209,7 +212,10 @@ class Recipe {
|
|||
async present(dish) {
|
||||
if (!this.lastRunOp) return;
|
||||
|
||||
const output = await this.lastRunOp.present(await dish.get(this.lastRunOp.outputType));
|
||||
const output = await this.lastRunOp.present(
|
||||
await dish.get(this.lastRunOp.outputType),
|
||||
this.lastRunOp.ingValues
|
||||
);
|
||||
dish.set(output, this.lastRunOp.presentType);
|
||||
}
|
||||
|
||||
|
@ -267,6 +273,18 @@ class Recipe {
|
|||
return highlights;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determines whether the previous operation has a different presentation type to its normal output.
|
||||
*
|
||||
* @param {number} progress
|
||||
* @returns {boolean}
|
||||
*/
|
||||
lastOpPresented(progress) {
|
||||
if (progress < 1) return false;
|
||||
return this.opList[progress-1].presentType !== this.opList[progress-1].outputType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Recipe;
|
||||
|
|
|
@ -524,36 +524,43 @@ class Utils {
|
|||
* Parses CSV data and returns it as a two dimensional array or strings.
|
||||
*
|
||||
* @param {string} data
|
||||
* @param {string[]} [cellDelims=[","]]
|
||||
* @param {string[]} [lineDelims=["\n", "\r"]]
|
||||
* @returns {string[][]}
|
||||
*
|
||||
* @example
|
||||
* // returns [["head1", "head2"], ["data1", "data2"]]
|
||||
* Utils.parseCSV("head1,head2\ndata1,data2");
|
||||
*/
|
||||
static parseCSV(data) {
|
||||
static parseCSV(data, cellDelims=[","], lineDelims=["\n", "\r"]) {
|
||||
let b,
|
||||
ignoreNext = false,
|
||||
next,
|
||||
renderNext = false,
|
||||
inString = false,
|
||||
cell = "",
|
||||
line = [];
|
||||
const lines = [];
|
||||
|
||||
// Remove BOM, often present in Excel CSV files
|
||||
if (data.length && data[0] === "\uFEFF") data = data.substr(1);
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
b = data[i];
|
||||
if (ignoreNext) {
|
||||
next = data[i+1] || "";
|
||||
if (renderNext) {
|
||||
cell += b;
|
||||
ignoreNext = false;
|
||||
renderNext = false;
|
||||
} else if (b === "\\") {
|
||||
cell += b;
|
||||
ignoreNext = true;
|
||||
renderNext = true;
|
||||
} else if (b === "\"" && !inString) {
|
||||
inString = true;
|
||||
} else if (b === "\"" && inString) {
|
||||
inString = false;
|
||||
} else if (b === "," && !inString) {
|
||||
if (next === "\"") renderNext = true;
|
||||
else inString = false;
|
||||
} else if (!inString && cellDelims.indexOf(b) >= 0) {
|
||||
line.push(cell);
|
||||
cell = "";
|
||||
} else if ((b === "\n" || b === "\r") && !inString) {
|
||||
} else if (!inString && lineDelims.indexOf(b) >= 0) {
|
||||
line.push(cell);
|
||||
cell = "";
|
||||
lines.push(line);
|
||||
|
@ -713,7 +720,7 @@ class Utils {
|
|||
* @param {boolean} [newline=false] - whether to add a newline after each operation
|
||||
* @returns {string}
|
||||
*/
|
||||
static generatePrettyRecipe(recipeConfig, newline=false) {
|
||||
static generatePrettyRecipe(recipeConfig, newline = false) {
|
||||
let prettyConfig = "",
|
||||
name = "",
|
||||
args = "",
|
||||
|
|
|
@ -1,366 +0,0 @@
|
|||
/**
|
||||
* Type definition for a CatConf.
|
||||
*
|
||||
* @typedef {Object} CatConf
|
||||
* @property {string} name - The display name for the category
|
||||
* @property {string[]} ops - A list of the operations to be included in this category
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Categories of operations.
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*
|
||||
* @constant
|
||||
* @type {CatConf[]}
|
||||
*/
|
||||
const Categories = [
|
||||
{
|
||||
name: "Favourites",
|
||||
ops: []
|
||||
},
|
||||
{
|
||||
name: "Data format",
|
||||
ops: [
|
||||
// "To Hexdump",
|
||||
// "From Hexdump",
|
||||
"To Hex",
|
||||
"From Hex",
|
||||
// "To Charcode",
|
||||
// "From Charcode",
|
||||
// "To Decimal",
|
||||
// "From Decimal",
|
||||
// "To Binary",
|
||||
// "From Binary",
|
||||
// "To Octal",
|
||||
// "From Octal",
|
||||
"To Base64",
|
||||
"From Base64",
|
||||
"Show Base64 offsets",
|
||||
"To Base32",
|
||||
"From Base32",
|
||||
// "To Base58",
|
||||
// "From Base58",
|
||||
// "To Base",
|
||||
// "From Base",
|
||||
// "To BCD",
|
||||
// "From BCD",
|
||||
// "To HTML Entity",
|
||||
// "From HTML Entity",
|
||||
// "URL Encode",
|
||||
// "URL Decode",
|
||||
// "Escape Unicode Characters",
|
||||
// "Unescape Unicode Characters",
|
||||
// "To Quoted Printable",
|
||||
// "From Quoted Printable",
|
||||
// "To Punycode",
|
||||
// "From Punycode",
|
||||
// "To Hex Content",
|
||||
// "From Hex Content",
|
||||
// "PEM to Hex",
|
||||
// "Hex to PEM",
|
||||
// "Parse ASN.1 hex string",
|
||||
// "Change IP format",
|
||||
// "Encode text",
|
||||
// "Decode text",
|
||||
// "Swap endianness",
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// name: "Encryption / Encoding",
|
||||
// ops: [
|
||||
// "AES Encrypt",
|
||||
// "AES Decrypt",
|
||||
// "Blowfish Encrypt",
|
||||
// "Blowfish Decrypt",
|
||||
// "DES Encrypt",
|
||||
// "DES Decrypt",
|
||||
// "Triple DES Encrypt",
|
||||
// "Triple DES Decrypt",
|
||||
// "RC2 Encrypt",
|
||||
// "RC2 Decrypt",
|
||||
// "RC4",
|
||||
// "RC4 Drop",
|
||||
"ROT13",
|
||||
"ROT47",
|
||||
// "XOR",
|
||||
// "XOR Brute Force",
|
||||
// "Vigenère Encode",
|
||||
// "Vigenère Decode",
|
||||
// "To Morse Code",
|
||||
// "From Morse Code",
|
||||
// "Bifid Cipher Encode",
|
||||
// "Bifid Cipher Decode",
|
||||
// "Affine Cipher Encode",
|
||||
// "Affine Cipher Decode",
|
||||
// "Atbash Cipher",
|
||||
// "Substitute",
|
||||
// "Derive PBKDF2 key",
|
||||
// "Derive EVP key",
|
||||
// "Bcrypt",
|
||||
// "Scrypt",
|
||||
// "Pseudo-Random Number Generator",
|
||||
]
|
||||
},
|
||||
// {
|
||||
// name: "Public Key",
|
||||
// ops: [
|
||||
// "Parse X.509 certificate",
|
||||
// "Parse ASN.1 hex string",
|
||||
// "PEM to Hex",
|
||||
// "Hex to PEM",
|
||||
// "Hex to Object Identifier",
|
||||
// "Object Identifier to Hex",
|
||||
// ]
|
||||
// },
|
||||
{
|
||||
name: "Arithmetic / Logic",
|
||||
ops: [
|
||||
"Set Union",
|
||||
"Set Intersection",
|
||||
"Set Difference",
|
||||
"Symmetric Difference",
|
||||
"Cartesian Product",
|
||||
"Power Set",
|
||||
// "XOR",
|
||||
// "XOR Brute Force",
|
||||
// "OR",
|
||||
// "NOT",
|
||||
// "AND",
|
||||
// "ADD",
|
||||
// "SUB",
|
||||
// "Sum",
|
||||
// "Subtract",
|
||||
// "Multiply",
|
||||
// "Divide",
|
||||
// "Mean",
|
||||
// "Median",
|
||||
// "Standard Deviation",
|
||||
// "Bit shift left",
|
||||
// "Bit shift right",
|
||||
"Rotate left",
|
||||
"Rotate right",
|
||||
"ROT13"
|
||||
]
|
||||
},
|
||||
// {
|
||||
// name: "Networking",
|
||||
// ops: [
|
||||
// "HTTP request",
|
||||
// "Strip HTTP headers",
|
||||
// "Parse User Agent",
|
||||
// "Parse IP range",
|
||||
// "Parse IPv6 address",
|
||||
// "Parse IPv4 header",
|
||||
// "Parse URI",
|
||||
// "URL Encode",
|
||||
// "URL Decode",
|
||||
// "Format MAC addresses",
|
||||
// "Change IP format",
|
||||
// "Group IP addresses",
|
||||
// "Encode NetBIOS Name",
|
||||
// "Decode NetBIOS Name",
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// name: "Language",
|
||||
// ops: [
|
||||
// "Encode text",
|
||||
// "Decode text",
|
||||
// "Unescape Unicode Characters",
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// name: "Utils",
|
||||
// ops: [
|
||||
// "Diff",
|
||||
// "Remove whitespace",
|
||||
// "Remove null bytes",
|
||||
// "To Upper case",
|
||||
// "To Lower case",
|
||||
// "Add line numbers",
|
||||
// "Remove line numbers",
|
||||
// "Reverse",
|
||||
// "Sort",
|
||||
// "Unique",
|
||||
// "Split",
|
||||
// "Filter",
|
||||
// "Head",
|
||||
// "Tail",
|
||||
// "Count occurrences",
|
||||
// "Expand alphabet range",
|
||||
// "Drop bytes",
|
||||
// "Take bytes",
|
||||
// "Pad lines",
|
||||
// "Find / Replace",
|
||||
// "Regular expression",
|
||||
// "Offset checker",
|
||||
// "Hamming Distance",
|
||||
// "Convert distance",
|
||||
// "Convert area",
|
||||
// "Convert mass",
|
||||
// "Convert speed",
|
||||
// "Convert data units",
|
||||
// "Parse UNIX file permissions",
|
||||
// "Swap endianness",
|
||||
// "Parse colour code",
|
||||
// "Escape string",
|
||||
// "Unescape string",
|
||||
// "Pseudo-Random Number Generator",
|
||||
// "Sleep",
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// name: "Date / Time",
|
||||
// ops: [
|
||||
// "Parse DateTime",
|
||||
// "Translate DateTime Format",
|
||||
// "From UNIX Timestamp",
|
||||
// "To UNIX Timestamp",
|
||||
// "Windows Filetime to UNIX Timestamp",
|
||||
// "UNIX Timestamp to Windows Filetime",
|
||||
// "Extract dates",
|
||||
// "Sleep",
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// name: "Extractors",
|
||||
// ops: [
|
||||
// "Strings",
|
||||
// "Extract IP addresses",
|
||||
// "Extract email addresses",
|
||||
// "Extract MAC addresses",
|
||||
// "Extract URLs",
|
||||
// "Extract domains",
|
||||
// "Extract file paths",
|
||||
// "Extract dates",
|
||||
// "Regular expression",
|
||||
// "XPath expression",
|
||||
// "JPath expression",
|
||||
// "CSS selector",
|
||||
// "Extract EXIF",
|
||||
// ]
|
||||
// },
|
||||
{
|
||||
name: "Compression",
|
||||
ops: [
|
||||
"Raw Deflate",
|
||||
"Raw Inflate",
|
||||
"Zlib Deflate",
|
||||
"Zlib Inflate",
|
||||
"Gzip",
|
||||
"Gunzip",
|
||||
"Zip",
|
||||
"Unzip",
|
||||
// "Bzip2 Decompress",
|
||||
// "Tar",
|
||||
// "Untar",
|
||||
]
|
||||
},
|
||||
// {
|
||||
// name: "Hashing",
|
||||
// ops: [
|
||||
// "Analyse hash",
|
||||
// "Generate all hashes",
|
||||
// "MD2",
|
||||
// "MD4",
|
||||
// "MD5",
|
||||
// "MD6",
|
||||
// "SHA0",
|
||||
// "SHA1",
|
||||
// "SHA2",
|
||||
// "SHA3",
|
||||
// "Keccak",
|
||||
// "Shake",
|
||||
// "RIPEMD",
|
||||
// "HAS-160",
|
||||
// "Whirlpool",
|
||||
// "Snefru",
|
||||
// "SSDEEP",
|
||||
// "CTPH",
|
||||
// "Compare SSDEEP hashes",
|
||||
// "Compare CTPH hashes",
|
||||
// "HMAC",
|
||||
// "Bcrypt",
|
||||
// "Bcrypt compare",
|
||||
// "Bcrypt parse",
|
||||
// "Scrypt",
|
||||
// "Fletcher-8 Checksum",
|
||||
// "Fletcher-16 Checksum",
|
||||
// "Fletcher-32 Checksum",
|
||||
// "Fletcher-64 Checksum",
|
||||
// "Adler-32 Checksum",
|
||||
// "CRC-16 Checksum",
|
||||
// "CRC-32 Checksum",
|
||||
// "TCP/IP Checksum",
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// name: "Code tidy",
|
||||
// ops: [
|
||||
// "Syntax highlighter",
|
||||
// "Generic Code Beautify",
|
||||
// "JavaScript Parser",
|
||||
// "JavaScript Beautify",
|
||||
// "JavaScript Minify",
|
||||
// "JSON Beautify",
|
||||
// "JSON Minify",
|
||||
// "XML Beautify",
|
||||
// "XML Minify",
|
||||
// "SQL Beautify",
|
||||
// "SQL Minify",
|
||||
// "CSS Beautify",
|
||||
// "CSS Minify",
|
||||
// "XPath expression",
|
||||
// "JPath expression",
|
||||
// "CSS selector",
|
||||
// "PHP Deserialize",
|
||||
// "Microsoft Script Decoder",
|
||||
// "Strip HTML tags",
|
||||
// "Diff",
|
||||
// "To Snake case",
|
||||
// "To Camel case",
|
||||
// "To Kebab case",
|
||||
// "BSON serialise",
|
||||
// "BSON deserialise",
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// name: "Other",
|
||||
// ops: [
|
||||
// "Entropy",
|
||||
// "Frequency distribution",
|
||||
// "Chi Square",
|
||||
// "Detect File Type",
|
||||
// "Scan for Embedded Files",
|
||||
// "Disassemble x86",
|
||||
// "Pseudo-Random Number Generator",
|
||||
// "Generate UUID",
|
||||
// "Generate TOTP",
|
||||
// "Generate HOTP",
|
||||
// "Render Image",
|
||||
// "Remove EXIF",
|
||||
// "Extract EXIF",
|
||||
// "Numberwang",
|
||||
// "XKCD Random Number",
|
||||
// ]
|
||||
// },
|
||||
// {
|
||||
// name: "Flow control",
|
||||
// ops: [
|
||||
// "Fork",
|
||||
// "Merge",
|
||||
// "Register",
|
||||
// "Label",
|
||||
// "Jump",
|
||||
// "Conditional Jump",
|
||||
// "Return",
|
||||
// "Comment"
|
||||
// ]
|
||||
// },
|
||||
];
|
||||
|
||||
export default Categories;
|
352
src/core/config/Categories.json
Executable file
352
src/core/config/Categories.json
Executable file
|
@ -0,0 +1,352 @@
|
|||
[
|
||||
{
|
||||
"name": "Favourites",
|
||||
"ops": []
|
||||
},
|
||||
{
|
||||
"name": "Data format",
|
||||
"ops": [
|
||||
"To Hexdump",
|
||||
"From Hexdump",
|
||||
"To Hex",
|
||||
"From Hex",
|
||||
"To Charcode",
|
||||
"From Charcode",
|
||||
"To Decimal",
|
||||
"From Decimal",
|
||||
"To Binary",
|
||||
"From Binary",
|
||||
"To Octal",
|
||||
"From Octal",
|
||||
"To Base64",
|
||||
"From Base64",
|
||||
"Show Base64 offsets",
|
||||
"To Base32",
|
||||
"From Base32",
|
||||
"To Base58",
|
||||
"From Base58",
|
||||
"To Base",
|
||||
"From Base",
|
||||
"To BCD",
|
||||
"From BCD",
|
||||
"To HTML Entity",
|
||||
"From HTML Entity",
|
||||
"URL Encode",
|
||||
"URL Decode",
|
||||
"Escape Unicode Characters",
|
||||
"Unescape Unicode Characters",
|
||||
"To Quoted Printable",
|
||||
"From Quoted Printable",
|
||||
"To Punycode",
|
||||
"From Punycode",
|
||||
"To Hex Content",
|
||||
"From Hex Content",
|
||||
"PEM to Hex",
|
||||
"Hex to PEM",
|
||||
"Parse ASN.1 hex string",
|
||||
"Change IP format",
|
||||
"Encode text",
|
||||
"Decode text",
|
||||
"Swap endianness"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Encryption / Encoding",
|
||||
"ops": [
|
||||
"AES Encrypt",
|
||||
"AES Decrypt",
|
||||
"Blowfish Encrypt",
|
||||
"Blowfish Decrypt",
|
||||
"DES Encrypt",
|
||||
"DES Decrypt",
|
||||
"Triple DES Encrypt",
|
||||
"Triple DES Decrypt",
|
||||
"RC2 Encrypt",
|
||||
"RC2 Decrypt",
|
||||
"RC4",
|
||||
"RC4 Drop",
|
||||
"ROT13",
|
||||
"ROT47",
|
||||
"XOR",
|
||||
"XOR Brute Force",
|
||||
"Vigenère Encode",
|
||||
"Vigenère Decode",
|
||||
"To Morse Code",
|
||||
"From Morse Code",
|
||||
"Bifid Cipher Encode",
|
||||
"Bifid Cipher Decode",
|
||||
"Affine Cipher Encode",
|
||||
"Affine Cipher Decode",
|
||||
"Atbash Cipher",
|
||||
"Substitute",
|
||||
"Derive PBKDF2 key",
|
||||
"Derive EVP key",
|
||||
"Bcrypt",
|
||||
"Scrypt",
|
||||
"Pseudo-Random Number Generator"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Public Key",
|
||||
"ops": [
|
||||
"Parse X.509 certificate",
|
||||
"Parse ASN.1 hex string",
|
||||
"PEM to Hex",
|
||||
"Hex to PEM",
|
||||
"Hex to Object Identifier",
|
||||
"Object Identifier to Hex",
|
||||
"Generate PGP Key Pair",
|
||||
"PGP Encrypt",
|
||||
"PGP Decrypt",
|
||||
"PGP Encrypt and Sign",
|
||||
"PGP Decrypt and Verify"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Arithmetic / Logic",
|
||||
"ops": [
|
||||
"Set Union",
|
||||
"Set Intersection",
|
||||
"Set Difference",
|
||||
"Symmetric Difference",
|
||||
"Cartesian Product",
|
||||
"Power Set",
|
||||
"XOR",
|
||||
"XOR Brute Force",
|
||||
"OR",
|
||||
"NOT",
|
||||
"AND",
|
||||
"ADD",
|
||||
"SUB",
|
||||
"Sum",
|
||||
"Subtract",
|
||||
"Multiply",
|
||||
"Divide",
|
||||
"Mean",
|
||||
"Median",
|
||||
"Standard Deviation",
|
||||
"Bit shift left",
|
||||
"Bit shift right",
|
||||
"Rotate left",
|
||||
"Rotate right",
|
||||
"ROT13"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Networking",
|
||||
"ops": [
|
||||
"HTTP request",
|
||||
"Strip HTTP headers",
|
||||
"Parse User Agent",
|
||||
"Parse IP range",
|
||||
"Parse IPv6 address",
|
||||
"Parse IPv4 header",
|
||||
"Parse URI",
|
||||
"URL Encode",
|
||||
"URL Decode",
|
||||
"Format MAC addresses",
|
||||
"Change IP format",
|
||||
"Group IP addresses",
|
||||
"Encode NetBIOS Name",
|
||||
"Decode NetBIOS Name"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Language",
|
||||
"ops": [
|
||||
"Encode text",
|
||||
"Decode text",
|
||||
"Unescape Unicode Characters"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Utils",
|
||||
"ops": [
|
||||
"Diff",
|
||||
"Remove whitespace",
|
||||
"Remove null bytes",
|
||||
"To Upper case",
|
||||
"To Lower case",
|
||||
"Add line numbers",
|
||||
"Remove line numbers",
|
||||
"To Table",
|
||||
"Reverse",
|
||||
"Sort",
|
||||
"Unique",
|
||||
"Split",
|
||||
"Filter",
|
||||
"Head",
|
||||
"Tail",
|
||||
"Count occurrences",
|
||||
"Expand alphabet range",
|
||||
"Drop bytes",
|
||||
"Take bytes",
|
||||
"Pad lines",
|
||||
"Find / Replace",
|
||||
"Regular expression",
|
||||
"Offset checker",
|
||||
"Hamming Distance",
|
||||
"Convert distance",
|
||||
"Convert area",
|
||||
"Convert mass",
|
||||
"Convert speed",
|
||||
"Convert data units",
|
||||
"Parse UNIX file permissions",
|
||||
"Swap endianness",
|
||||
"Parse colour code",
|
||||
"Escape string",
|
||||
"Unescape string",
|
||||
"Pseudo-Random Number Generator",
|
||||
"Sleep"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Date / Time",
|
||||
"ops": [
|
||||
"Parse DateTime",
|
||||
"Translate DateTime Format",
|
||||
"From UNIX Timestamp",
|
||||
"To UNIX Timestamp",
|
||||
"Windows Filetime to UNIX Timestamp",
|
||||
"UNIX Timestamp to Windows Filetime",
|
||||
"Extract dates",
|
||||
"Sleep"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Extractors",
|
||||
"ops": [
|
||||
"Strings",
|
||||
"Extract IP addresses",
|
||||
"Extract email addresses",
|
||||
"Extract MAC addresses",
|
||||
"Extract URLs",
|
||||
"Extract domains",
|
||||
"Extract file paths",
|
||||
"Extract dates",
|
||||
"Regular expression",
|
||||
"XPath expression",
|
||||
"JPath expression",
|
||||
"CSS selector",
|
||||
"Extract EXIF"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Compression",
|
||||
"ops": [
|
||||
"Raw Deflate",
|
||||
"Raw Inflate",
|
||||
"Zlib Deflate",
|
||||
"Zlib Inflate",
|
||||
"Gzip",
|
||||
"Gunzip",
|
||||
"Zip",
|
||||
"Unzip",
|
||||
"Bzip2 Decompress",
|
||||
"Tar",
|
||||
"Untar"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Hashing",
|
||||
"ops": [
|
||||
"Analyse hash",
|
||||
"Generate all hashes",
|
||||
"MD2",
|
||||
"MD4",
|
||||
"MD5",
|
||||
"MD6",
|
||||
"SHA0",
|
||||
"SHA1",
|
||||
"SHA2",
|
||||
"SHA3",
|
||||
"Keccak",
|
||||
"Shake",
|
||||
"RIPEMD",
|
||||
"HAS-160",
|
||||
"Whirlpool",
|
||||
"Snefru",
|
||||
"SSDEEP",
|
||||
"CTPH",
|
||||
"Compare SSDEEP hashes",
|
||||
"Compare CTPH hashes",
|
||||
"HMAC",
|
||||
"Bcrypt",
|
||||
"Bcrypt compare",
|
||||
"Bcrypt parse",
|
||||
"Scrypt",
|
||||
"Fletcher-8 Checksum",
|
||||
"Fletcher-16 Checksum",
|
||||
"Fletcher-32 Checksum",
|
||||
"Fletcher-64 Checksum",
|
||||
"Adler-32 Checksum",
|
||||
"CRC-16 Checksum",
|
||||
"CRC-32 Checksum",
|
||||
"TCP/IP Checksum"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Code tidy",
|
||||
"ops": [
|
||||
"Syntax highlighter",
|
||||
"Generic Code Beautify",
|
||||
"JavaScript Parser",
|
||||
"JavaScript Beautify",
|
||||
"JavaScript Minify",
|
||||
"JSON Beautify",
|
||||
"JSON Minify",
|
||||
"XML Beautify",
|
||||
"XML Minify",
|
||||
"SQL Beautify",
|
||||
"SQL Minify",
|
||||
"CSS Beautify",
|
||||
"CSS Minify",
|
||||
"XPath expression",
|
||||
"JPath expression",
|
||||
"CSS selector",
|
||||
"PHP Deserialize",
|
||||
"Microsoft Script Decoder",
|
||||
"Strip HTML tags",
|
||||
"Diff",
|
||||
"To Snake case",
|
||||
"To Camel case",
|
||||
"To Kebab case",
|
||||
"BSON serialise",
|
||||
"BSON deserialise"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Other",
|
||||
"ops": [
|
||||
"Entropy",
|
||||
"Frequency distribution",
|
||||
"Chi Square",
|
||||
"Detect File Type",
|
||||
"Scan for Embedded Files",
|
||||
"Disassemble x86",
|
||||
"Pseudo-Random Number Generator",
|
||||
"Generate UUID",
|
||||
"Generate TOTP",
|
||||
"Generate HOTP",
|
||||
"Render Image",
|
||||
"Remove EXIF",
|
||||
"Extract EXIF",
|
||||
"Numberwang",
|
||||
"XKCD Random Number"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Flow control",
|
||||
"ops": [
|
||||
"Magic",
|
||||
"Fork",
|
||||
"Merge",
|
||||
"Register",
|
||||
"Label",
|
||||
"Jump",
|
||||
"Conditional Jump",
|
||||
"Return",
|
||||
"Comment"
|
||||
]
|
||||
}
|
||||
]
|
File diff suppressed because it is too large
Load diff
4815
src/core/config/scripts/portOperation.mjs
Normal file
4815
src/core/config/scripts/portOperation.mjs
Normal file
File diff suppressed because it is too large
Load diff
|
@ -15,6 +15,8 @@ class OperationError extends Error {
|
|||
constructor(...args) {
|
||||
super(...args);
|
||||
|
||||
this.type = "OperationError";
|
||||
|
||||
if (Error.captureStackTrace) {
|
||||
Error.captureStackTrace(this, OperationError);
|
||||
}
|
||||
|
|
139
src/core/lib/Arithmetic.mjs
Normal file
139
src/core/lib/Arithmetic.mjs
Normal file
|
@ -0,0 +1,139 @@
|
|||
/**
|
||||
* @author bwhitn [brian.m.whitney@outlook.com]
|
||||
* @author d98762625 [d98762625@gmailcom]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Utils from "../Utils";
|
||||
import BigNumber from "bignumber.js";
|
||||
|
||||
|
||||
/**
|
||||
* Converts a string array to a number array.
|
||||
*
|
||||
* @param {string[]} input
|
||||
* @param {string} delim
|
||||
* @returns {BigNumber[]}
|
||||
*/
|
||||
export function createNumArray(input, delim) {
|
||||
delim = Utils.charRep(delim || "Space");
|
||||
const splitNumbers = input.split(delim);
|
||||
const numbers = [];
|
||||
let num;
|
||||
|
||||
splitNumbers.map((number) => {
|
||||
try {
|
||||
num = BigNumber(number.trim());
|
||||
if (!num.isNaN()) {
|
||||
numbers.push(num);
|
||||
}
|
||||
} catch (err) {
|
||||
// This line is not a valid number
|
||||
}
|
||||
});
|
||||
return numbers;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds an array of numbers and returns the value.
|
||||
*
|
||||
* @param {BigNumber[]} data
|
||||
* @returns {BigNumber}
|
||||
*/
|
||||
export function sum(data) {
|
||||
if (data.length > 0) {
|
||||
return data.reduce((acc, curr) => acc.plus(curr));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Subtracts an array of numbers and returns the value.
|
||||
*
|
||||
* @param {BigNumber[]} data
|
||||
* @returns {BigNumber}
|
||||
*/
|
||||
export function sub(data) {
|
||||
if (data.length > 0) {
|
||||
return data.reduce((acc, curr) => acc.minus(curr));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Multiplies an array of numbers and returns the value.
|
||||
*
|
||||
* @param {BigNumber[]} data
|
||||
* @returns {BigNumber}
|
||||
*/
|
||||
export function multi(data) {
|
||||
if (data.length > 0) {
|
||||
return data.reduce((acc, curr) => acc.times(curr));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Divides an array of numbers and returns the value.
|
||||
*
|
||||
* @param {BigNumber[]} data
|
||||
* @returns {BigNumber}
|
||||
*/
|
||||
export function div(data) {
|
||||
if (data.length > 0) {
|
||||
return data.reduce((acc, curr) => acc.div(curr));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Computes mean of a number array and returns the value.
|
||||
*
|
||||
* @param {BigNumber[]} data
|
||||
* @returns {BigNumber}
|
||||
*/
|
||||
export function mean(data) {
|
||||
if (data.length > 0) {
|
||||
return sum(data).div(data.length);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Computes median of a number array and returns the value.
|
||||
*
|
||||
* @param {BigNumber[]} data
|
||||
* @returns {BigNumber}
|
||||
*/
|
||||
export function median(data) {
|
||||
if ((data.length % 2) === 0 && data.length > 0) {
|
||||
data.sort(function(a, b){
|
||||
return a.minus(b);
|
||||
});
|
||||
const first = data[Math.floor(data.length / 2)];
|
||||
const second = data[Math.floor(data.length / 2) - 1];
|
||||
return mean([first, second]);
|
||||
} else {
|
||||
return data[Math.floor(data.length / 2)];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Computes standard deviation of a number array and returns the value.
|
||||
*
|
||||
* @param {BigNumber[]} data
|
||||
* @returns {BigNumber}
|
||||
*/
|
||||
export function stdDev(data) {
|
||||
if (data.length > 0) {
|
||||
const avg = mean(data);
|
||||
let devSum = new BigNumber(0);
|
||||
data.map((datum) => {
|
||||
devSum = devSum.plus(datum.minus(avg).pow(2));
|
||||
});
|
||||
return devSum.div(data.length).sqrt();
|
||||
}
|
||||
}
|
48
src/core/lib/BCD.mjs
Executable file
48
src/core/lib/BCD.mjs
Executable file
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* Binary Code Decimal resources.
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* BCD encoding schemes.
|
||||
*/
|
||||
export const ENCODING_SCHEME = [
|
||||
"8 4 2 1",
|
||||
"7 4 2 1",
|
||||
"4 2 2 1",
|
||||
"2 4 2 1",
|
||||
"8 4 -2 -1",
|
||||
"Excess-3",
|
||||
"IBM 8 4 2 1",
|
||||
];
|
||||
|
||||
/**
|
||||
* Lookup table for the binary value of each digit representation.
|
||||
*
|
||||
* I wrote a very nice algorithm to generate 8 4 2 1 encoding programatically,
|
||||
* but unfortunately it's much easier (if less elegant) to use lookup tables
|
||||
* when supporting multiple encoding schemes.
|
||||
*
|
||||
* "Practicality beats purity" - PEP 20
|
||||
*
|
||||
* In some schemes it is possible to represent the same value in multiple ways.
|
||||
* For instance, in 4 2 2 1 encoding, 0100 and 0010 both represent 2. Support
|
||||
* has not yet been added for this.
|
||||
*/
|
||||
export const ENCODING_LOOKUP = {
|
||||
"8 4 2 1": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
||||
"7 4 2 1": [0, 1, 2, 3, 4, 5, 6, 8, 9, 10],
|
||||
"4 2 2 1": [0, 1, 4, 5, 8, 9, 12, 13, 14, 15],
|
||||
"2 4 2 1": [0, 1, 2, 3, 4, 11, 12, 13, 14, 15],
|
||||
"8 4 -2 -1": [0, 7, 6, 5, 4, 11, 10, 9, 8, 15],
|
||||
"Excess-3": [3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
|
||||
"IBM 8 4 2 1": [10, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
||||
};
|
||||
|
||||
/**
|
||||
* BCD formats.
|
||||
*/
|
||||
export const FORMAT = ["Nibbles", "Bytes", "Raw"];
|
22
src/core/lib/Base58.mjs
Executable file
22
src/core/lib/Base58.mjs
Executable file
|
@ -0,0 +1,22 @@
|
|||
/**
|
||||
* Base58 resources.
|
||||
*
|
||||
* @author tlwr [toby@toby.codes]
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base58 alphabet options.
|
||||
*/
|
||||
export const ALPHABET_OPTIONS = [
|
||||
{
|
||||
name: "Bitcoin",
|
||||
value: "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz",
|
||||
},
|
||||
{
|
||||
name: "Ripple",
|
||||
value: "rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz",
|
||||
},
|
||||
];
|
204
src/core/lib/CanvasComponents.mjs
Executable file
204
src/core/lib/CanvasComponents.mjs
Executable file
|
@ -0,0 +1,204 @@
|
|||
/**
|
||||
* Various components for drawing diagrams on an HTML5 canvas.
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Draws a line from one point to another
|
||||
*
|
||||
* @param ctx
|
||||
* @param startX
|
||||
* @param startY
|
||||
* @param endX
|
||||
* @param endY
|
||||
*/
|
||||
export function drawLine(ctx, startX, startY, endX, endY) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(startX, startY);
|
||||
ctx.lineTo(endX, endY);
|
||||
ctx.closePath();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a bar chart on the canvas.
|
||||
*
|
||||
* @param canvas
|
||||
* @param scores
|
||||
* @param xAxisLabel
|
||||
* @param yAxisLabel
|
||||
* @param numXLabels
|
||||
* @param numYLabels
|
||||
* @param fontSize
|
||||
*/
|
||||
export function drawBarChart(canvas, scores, xAxisLabel, yAxisLabel, numXLabels, numYLabels, fontSize) {
|
||||
fontSize = fontSize || 15;
|
||||
if (!numXLabels || numXLabels > Math.round(canvas.width / 50)) {
|
||||
numXLabels = Math.round(canvas.width / 50);
|
||||
}
|
||||
if (!numYLabels || numYLabels > Math.round(canvas.width / 50)) {
|
||||
numYLabels = Math.round(canvas.height / 50);
|
||||
}
|
||||
|
||||
// Graph properties
|
||||
const ctx = canvas.getContext("2d"),
|
||||
leftPadding = canvas.width * 0.08,
|
||||
rightPadding = canvas.width * 0.03,
|
||||
topPadding = canvas.height * 0.08,
|
||||
bottomPadding = canvas.height * 0.15,
|
||||
graphHeight = canvas.height - topPadding - bottomPadding,
|
||||
graphWidth = canvas.width - leftPadding - rightPadding,
|
||||
base = topPadding + graphHeight,
|
||||
ceil = topPadding;
|
||||
|
||||
ctx.font = fontSize + "px Arial";
|
||||
|
||||
// Draw axis
|
||||
ctx.lineWidth = "1.0";
|
||||
ctx.strokeStyle = "#444";
|
||||
drawLine(ctx, leftPadding, base, graphWidth + leftPadding, base); // x
|
||||
drawLine(ctx, leftPadding, base, leftPadding, ceil); // y
|
||||
|
||||
// Bar properties
|
||||
const barPadding = graphWidth * 0.003,
|
||||
barWidth = (graphWidth - (barPadding * scores.length)) / scores.length,
|
||||
max = Math.max.apply(Math, scores);
|
||||
let currX = leftPadding + barPadding;
|
||||
|
||||
// Draw bars
|
||||
ctx.fillStyle = "green";
|
||||
for (let i = 0; i < scores.length; i++) {
|
||||
const h = scores[i] / max * graphHeight;
|
||||
ctx.fillRect(currX, base - h, barWidth, h);
|
||||
currX += barWidth + barPadding;
|
||||
}
|
||||
|
||||
// Mark x axis
|
||||
ctx.fillStyle = "black";
|
||||
ctx.textAlign = "center";
|
||||
currX = leftPadding + barPadding;
|
||||
if (numXLabels >= scores.length) {
|
||||
// Mark every score
|
||||
for (let i = 0; i <= scores.length; i++) {
|
||||
ctx.fillText(i, currX, base + (bottomPadding * 0.3));
|
||||
currX += barWidth + barPadding;
|
||||
}
|
||||
} else {
|
||||
// Mark some scores
|
||||
for (let i = 0; i <= numXLabels; i++) {
|
||||
const val = Math.ceil((scores.length / numXLabels) * i);
|
||||
currX = (graphWidth / numXLabels) * i + leftPadding;
|
||||
ctx.fillText(val, currX, base + (bottomPadding * 0.3));
|
||||
}
|
||||
}
|
||||
|
||||
// Mark y axis
|
||||
ctx.textAlign = "right";
|
||||
let currY;
|
||||
if (numYLabels >= max) {
|
||||
// Mark every increment
|
||||
for (let i = 0; i <= max; i++) {
|
||||
currY = base - (i / max * graphHeight) + fontSize / 3;
|
||||
ctx.fillText(i, leftPadding * 0.8, currY);
|
||||
}
|
||||
} else {
|
||||
// Mark some increments
|
||||
for (let i = 0; i <= numYLabels; i++) {
|
||||
const val = Math.ceil((max / numYLabels) * i);
|
||||
currY = base - (val / max * graphHeight) + fontSize / 3;
|
||||
ctx.fillText(val, leftPadding * 0.8, currY);
|
||||
}
|
||||
}
|
||||
|
||||
// Label x axis
|
||||
if (xAxisLabel) {
|
||||
ctx.textAlign = "center";
|
||||
ctx.fillText(xAxisLabel, graphWidth / 2 + leftPadding, base + bottomPadding * 0.8);
|
||||
}
|
||||
|
||||
// Label y axis
|
||||
if (yAxisLabel) {
|
||||
ctx.save();
|
||||
const x = leftPadding * 0.3,
|
||||
y = graphHeight / 2 + topPadding;
|
||||
ctx.translate(x, y);
|
||||
ctx.rotate(-Math.PI / 2);
|
||||
ctx.textAlign = "center";
|
||||
ctx.fillText(yAxisLabel, 0, 0);
|
||||
ctx.restore();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a scale bar on the canvas.
|
||||
*
|
||||
* @param canvas
|
||||
* @param score
|
||||
* @param max
|
||||
* @param markings
|
||||
*/
|
||||
export function drawScaleBar(canvas, score, max, markings) {
|
||||
// Bar properties
|
||||
const ctx = canvas.getContext("2d"),
|
||||
leftPadding = canvas.width * 0.01,
|
||||
rightPadding = canvas.width * 0.01,
|
||||
topPadding = canvas.height * 0.1,
|
||||
bottomPadding = canvas.height * 0.3,
|
||||
barHeight = canvas.height - topPadding - bottomPadding,
|
||||
barWidth = canvas.width - leftPadding - rightPadding;
|
||||
|
||||
// Scale properties
|
||||
const proportion = score / max;
|
||||
|
||||
// Draw bar outline
|
||||
ctx.strokeRect(leftPadding, topPadding, barWidth, barHeight);
|
||||
|
||||
// Shade in up to proportion
|
||||
const grad = ctx.createLinearGradient(leftPadding, 0, barWidth + leftPadding, 0);
|
||||
grad.addColorStop(0, "green");
|
||||
grad.addColorStop(0.5, "gold");
|
||||
grad.addColorStop(1, "red");
|
||||
ctx.fillStyle = grad;
|
||||
ctx.fillRect(leftPadding, topPadding, barWidth * proportion, barHeight);
|
||||
|
||||
// Add markings
|
||||
let x0, y0, x1, y1;
|
||||
ctx.fillStyle = "black";
|
||||
ctx.textAlign = "center";
|
||||
ctx.font = "13px Arial";
|
||||
for (let i = 0; i < markings.length; i++) {
|
||||
// Draw min line down
|
||||
x0 = barWidth / max * markings[i].min + leftPadding;
|
||||
y0 = topPadding + barHeight + (bottomPadding * 0.1);
|
||||
x1 = x0;
|
||||
y1 = topPadding + barHeight + (bottomPadding * 0.3);
|
||||
drawLine(ctx, x0, y0, x1, y1);
|
||||
|
||||
// Draw max line down
|
||||
x0 = barWidth / max * markings[i].max + leftPadding;
|
||||
x1 = x0;
|
||||
drawLine(ctx, x0, y0, x1, y1);
|
||||
|
||||
// Join min and max lines
|
||||
x0 = barWidth / max * markings[i].min + leftPadding;
|
||||
y0 = topPadding + barHeight + (bottomPadding * 0.3);
|
||||
x1 = barWidth / max * markings[i].max + leftPadding;
|
||||
y1 = y0;
|
||||
drawLine(ctx, x0, y0, x1, y1);
|
||||
|
||||
// Add label
|
||||
if (markings[i].max >= max * 0.9) {
|
||||
ctx.textAlign = "right";
|
||||
x0 = x1;
|
||||
} else if (markings[i].max <= max * 0.1) {
|
||||
ctx.textAlign = "left";
|
||||
} else {
|
||||
x0 = x0 + (x1 - x0) / 2;
|
||||
}
|
||||
y0 = topPadding + barHeight + (bottomPadding * 0.8);
|
||||
ctx.fillText(markings[i].label, x0, y0);
|
||||
}
|
||||
}
|
58
src/core/lib/ChrEnc.mjs
Normal file
58
src/core/lib/ChrEnc.mjs
Normal file
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
* Character encoding resources.
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Character encoding format mappings.
|
||||
*/
|
||||
export const IO_FORMAT = {
|
||||
"UTF-8 (65001)": 65001,
|
||||
"UTF-7 (65000)": 65000,
|
||||
"UTF16LE (1200)": 1200,
|
||||
"UTF16BE (1201)": 1201,
|
||||
"UTF16 (1201)": 1201,
|
||||
"IBM EBCDIC International (500)": 500,
|
||||
"IBM EBCDIC US-Canada (37)": 37,
|
||||
"Windows-874 Thai (874)": 874,
|
||||
"Japanese Shift-JIS (932)": 932,
|
||||
"Simplified Chinese GBK (936)": 936,
|
||||
"Korean (949)": 949,
|
||||
"Traditional Chinese Big5 (950)": 950,
|
||||
"Windows-1250 Central European (1250)": 1250,
|
||||
"Windows-1251 Cyrillic (1251)": 1251,
|
||||
"Windows-1252 Latin (1252)": 1252,
|
||||
"Windows-1253 Greek (1253)": 1253,
|
||||
"Windows-1254 Turkish (1254)": 1254,
|
||||
"Windows-1255 Hebrew (1255)": 1255,
|
||||
"Windows-1256 Arabic (1256)": 1256,
|
||||
"Windows-1257 Baltic (1257)": 1257,
|
||||
"Windows-1258 Vietnam (1258)": 1258,
|
||||
"US-ASCII (20127)": 20127,
|
||||
"Simplified Chinese GB2312 (20936)": 20936,
|
||||
"KOI8-R Russian Cyrillic (20866)": 20866,
|
||||
"KOI8-U Ukrainian Cyrillic (21866)": 21866,
|
||||
"ISO-8859-1 Latin 1 Western European (28591)": 28591,
|
||||
"ISO-8859-2 Latin 2 Central European (28592)": 28592,
|
||||
"ISO-8859-3 Latin 3 South European (28593)": 28593,
|
||||
"ISO-8859-4 Latin 4 North European (28594)": 28594,
|
||||
"ISO-8859-5 Latin/Cyrillic (28595)": 28595,
|
||||
"ISO-8859-6 Latin/Arabic (28596)": 28596,
|
||||
"ISO-8859-7 Latin/Greek (28597)": 28597,
|
||||
"ISO-8859-8 Latin/Hebrew (28598)": 28598,
|
||||
"ISO-8859-9 Latin 5 Turkish (28599)": 28599,
|
||||
"ISO-8859-10 Latin 6 Nordic (28600)": 28600,
|
||||
"ISO-8859-11 Latin/Thai (28601)": 28601,
|
||||
"ISO-8859-13 Latin 7 Baltic Rim (28603)": 28603,
|
||||
"ISO-8859-14 Latin 8 Celtic (28604)": 28604,
|
||||
"ISO-8859-15 Latin 9 (28605)": 28605,
|
||||
"ISO-8859-16 Latin 10 (28606)": 28606,
|
||||
"ISO-2022 JIS Japanese (50222)": 50222,
|
||||
"EUC Japanese (51932)": 51932,
|
||||
"EUC Korean (51949)": 51949,
|
||||
"Simplified Chinese GB18030 (54936)": 54936,
|
||||
};
|
||||
|
82
src/core/lib/Ciphers.mjs
Normal file
82
src/core/lib/Ciphers.mjs
Normal file
|
@ -0,0 +1,82 @@
|
|||
/**
|
||||
* Cipher functions.
|
||||
*
|
||||
* @author Matt C [matt@artemisbot.uk]
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
*
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
import OperationError from "../errors/OperationError";
|
||||
import CryptoJS from "crypto-js";
|
||||
|
||||
/**
|
||||
* Affine Cipher Encode operation.
|
||||
*
|
||||
* @author Matt C [matt@artemisbot.uk]
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
export function affineEncode(input, args) {
|
||||
const alphabet = "abcdefghijklmnopqrstuvwxyz",
|
||||
a = args[0],
|
||||
b = args[1];
|
||||
let output = "";
|
||||
|
||||
if (!/^\+?(0|[1-9]\d*)$/.test(a) || !/^\+?(0|[1-9]\d*)$/.test(b)) {
|
||||
throw new OperationError("The values of a and b can only be integers.");
|
||||
}
|
||||
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
if (alphabet.indexOf(input[i]) >= 0) {
|
||||
// Uses the affine function ax+b % m = y (where m is length of the alphabet)
|
||||
output += alphabet[((a * alphabet.indexOf(input[i])) + b) % 26];
|
||||
} else if (alphabet.indexOf(input[i].toLowerCase()) >= 0) {
|
||||
// Same as above, accounting for uppercase
|
||||
output += alphabet[((a * alphabet.indexOf(input[i].toLowerCase())) + b) % 26].toUpperCase();
|
||||
} else {
|
||||
// Non-alphabetic characters
|
||||
output += input[i];
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a polybius square for the given keyword
|
||||
*
|
||||
* @private
|
||||
* @author Matt C [matt@artemisbot.uk]
|
||||
* @param {string} keyword - Must be upper case
|
||||
* @returns {string}
|
||||
*/
|
||||
export function genPolybiusSquare (keyword) {
|
||||
const alpha = "ABCDEFGHIKLMNOPQRSTUVWXYZ",
|
||||
polArray = `${keyword}${alpha}`.split("").unique(),
|
||||
polybius = [];
|
||||
|
||||
for (let i = 0; i < 5; i++) {
|
||||
polybius[i] = polArray.slice(i*5, i*5 + 5);
|
||||
}
|
||||
|
||||
return polybius;
|
||||
}
|
||||
|
||||
/**
|
||||
* A mapping of string formats to their classes in the CryptoJS library.
|
||||
*
|
||||
* @private
|
||||
* @constant
|
||||
*/
|
||||
export const format = {
|
||||
"Hex": CryptoJS.enc.Hex,
|
||||
"Base64": CryptoJS.enc.Base64,
|
||||
"UTF8": CryptoJS.enc.Utf8,
|
||||
"UTF16": CryptoJS.enc.Utf16,
|
||||
"UTF16LE": CryptoJS.enc.Utf16LE,
|
||||
"UTF16BE": CryptoJS.enc.Utf16BE,
|
||||
"Latin1": CryptoJS.enc.Latin1,
|
||||
};
|
313
src/core/lib/DateTime.mjs
Normal file
313
src/core/lib/DateTime.mjs
Normal file
|
@ -0,0 +1,313 @@
|
|||
/**
|
||||
* DateTime resources.
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* DateTime units.
|
||||
*/
|
||||
export const UNITS = ["Seconds (s)", "Milliseconds (ms)", "Microseconds (μs)", "Nanoseconds (ns)"];
|
||||
|
||||
/**
|
||||
* DateTime formats.
|
||||
*/
|
||||
export const DATETIME_FORMATS = [
|
||||
{
|
||||
name: "Standard date and time",
|
||||
value: "DD/MM/YYYY HH:mm:ss"
|
||||
},
|
||||
{
|
||||
name: "American-style date and time",
|
||||
value: "MM/DD/YYYY HH:mm:ss"
|
||||
},
|
||||
{
|
||||
name: "International date and time",
|
||||
value: "YYYY-MM-DD HH:mm:ss"
|
||||
},
|
||||
{
|
||||
name: "Verbose date and time",
|
||||
value: "dddd Do MMMM YYYY HH:mm:ss Z z"
|
||||
},
|
||||
{
|
||||
name: "UNIX timestamp (seconds)",
|
||||
value: "X"
|
||||
},
|
||||
{
|
||||
name: "UNIX timestamp offset (milliseconds)",
|
||||
value: "x"
|
||||
},
|
||||
{
|
||||
name: "Automatic",
|
||||
value: ""
|
||||
},
|
||||
];
|
||||
|
||||
/**
|
||||
* MomentJS DateTime formatting examples.
|
||||
*/
|
||||
export const FORMAT_EXAMPLES = `Format string tokens:
|
||||
<table class="table table-striped table-hover table-condensed table-bordered" style="font-family: sans-serif">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Category</th>
|
||||
<th>Token</th>
|
||||
<th>Output</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><b>Month</b></td>
|
||||
<td>M</td>
|
||||
<td>1 2 ... 11 12</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>Mo</td>
|
||||
<td>1st 2nd ... 11th 12th</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>MM</td>
|
||||
<td>01 02 ... 11 12</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>MMM</td>
|
||||
<td>Jan Feb ... Nov Dec</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>MMMM</td>
|
||||
<td>January February ... November December</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Quarter</b></td>
|
||||
<td>Q</td>
|
||||
<td>1 2 3 4</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Day of Month</b></td>
|
||||
<td>D</td>
|
||||
<td>1 2 ... 30 31</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>Do</td>
|
||||
<td>1st 2nd ... 30th 31st</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>DD</td>
|
||||
<td>01 02 ... 30 31</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Day of Year</b></td>
|
||||
<td>DDD</td>
|
||||
<td>1 2 ... 364 365</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>DDDo</td>
|
||||
<td>1st 2nd ... 364th 365th</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>DDDD</td>
|
||||
<td>001 002 ... 364 365</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Day of Week</b></td>
|
||||
<td>d</td>
|
||||
<td>0 1 ... 5 6</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>do</td>
|
||||
<td>0th 1st ... 5th 6th</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>dd</td>
|
||||
<td>Su Mo ... Fr Sa</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>ddd</td>
|
||||
<td>Sun Mon ... Fri Sat</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>dddd</td>
|
||||
<td>Sunday Monday ... Friday Saturday</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Day of Week (Locale)</b></td>
|
||||
<td>e</td>
|
||||
<td>0 1 ... 5 6</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Day of Week (ISO)</b></td>
|
||||
<td>E</td>
|
||||
<td>1 2 ... 6 7</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Week of Year</b></td>
|
||||
<td>w</td>
|
||||
<td>1 2 ... 52 53</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>wo</td>
|
||||
<td>1st 2nd ... 52nd 53rd</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>ww</td>
|
||||
<td>01 02 ... 52 53</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Week of Year (ISO)</b></td>
|
||||
<td>W</td>
|
||||
<td>1 2 ... 52 53</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>Wo</td>
|
||||
<td>1st 2nd ... 52nd 53rd</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>WW</td>
|
||||
<td>01 02 ... 52 53</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Year</b></td>
|
||||
<td>YY</td>
|
||||
<td>70 71 ... 29 30</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>YYYY</td>
|
||||
<td>1970 1971 ... 2029 2030</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Week Year</b></td>
|
||||
<td>gg</td>
|
||||
<td>70 71 ... 29 30</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>gggg</td>
|
||||
<td>1970 1971 ... 2029 2030</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Week Year (ISO)</b></td>
|
||||
<td>GG</td>
|
||||
<td>70 71 ... 29 30</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>GGGG</td>
|
||||
<td>1970 1971 ... 2029 2030</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>AM/PM</b></td>
|
||||
<td>A</td>
|
||||
<td>AM PM</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>a</td>
|
||||
<td>am pm</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Hour</b></td>
|
||||
<td>H</td>
|
||||
<td>0 1 ... 22 23</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>HH</td>
|
||||
<td>00 01 ... 22 23</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>h</td>
|
||||
<td>1 2 ... 11 12</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>hh</td>
|
||||
<td>01 02 ... 11 12</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Minute</b></td>
|
||||
<td>m</td>
|
||||
<td>0 1 ... 58 59</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>mm</td>
|
||||
<td>00 01 ... 58 59</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Second</b></td>
|
||||
<td>s</td>
|
||||
<td>0 1 ... 58 59</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>ss</td>
|
||||
<td>00 01 ... 58 59</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Fractional Second</b></td>
|
||||
<td>S</td>
|
||||
<td>0 1 ... 8 9</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>SS</td>
|
||||
<td>00 01 ... 98 99</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>SSS</td>
|
||||
<td>000 001 ... 998 999</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>SSSS ... SSSSSSSSS</td>
|
||||
<td>000[0..] 001[0..] ... 998[0..] 999[0..]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Timezone</b></td>
|
||||
<td>z or zz</td>
|
||||
<td>EST CST ... MST PST</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>Z</td>
|
||||
<td>-07:00 -06:00 ... +06:00 +07:00</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>ZZ</td>
|
||||
<td>-0700 -0600 ... +0600 +0700</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Unix Timestamp</b></td>
|
||||
<td>X</td>
|
||||
<td>1360013296</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Unix Millisecond Timestamp</b></td>
|
||||
<td>x</td>
|
||||
<td>1360013296123</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>`;
|
||||
|
69
src/core/lib/Delim.mjs
Normal file
69
src/core/lib/Delim.mjs
Normal file
|
@ -0,0 +1,69 @@
|
|||
/**
|
||||
* Various delimiters
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Generic sequence delimiters.
|
||||
*/
|
||||
export const DELIM_OPTIONS = ["Space", "Comma", "Semi-colon", "Colon", "Line feed", "CRLF"];
|
||||
|
||||
/**
|
||||
* Binary sequence delimiters.
|
||||
*/
|
||||
export const BIN_DELIM_OPTIONS = ["Space", "Comma", "Semi-colon", "Colon", "Line feed", "CRLF", "None"];
|
||||
|
||||
/**
|
||||
* Letter sequence delimiters.
|
||||
*/
|
||||
export const LETTER_DELIM_OPTIONS = ["Space", "Line feed", "CRLF", "Forward slash", "Backslash", "Comma", "Semi-colon", "Colon"];
|
||||
|
||||
/**
|
||||
* Word sequence delimiters.
|
||||
*/
|
||||
export const WORD_DELIM_OPTIONS = ["Line feed", "CRLF", "Forward slash", "Backslash", "Comma", "Semi-colon", "Colon"];
|
||||
|
||||
/**
|
||||
* Input sequence delimiters.
|
||||
*/
|
||||
export const INPUT_DELIM_OPTIONS = ["Line feed", "CRLF", "Space", "Comma", "Semi-colon", "Colon", "Nothing (separate chars)"];
|
||||
|
||||
/**
|
||||
* Armithmetic sequence delimiters
|
||||
*/
|
||||
export const ARITHMETIC_DELIM_OPTIONS = ["Line feed", "Space", "Comma", "Semi-colon", "Colon", "CRLF"];
|
||||
|
||||
/**
|
||||
* Hash delimiters
|
||||
*/
|
||||
export const HASH_DELIM_OPTIONS = ["Line feed", "CRLF", "Space", "Comma"];
|
||||
|
||||
/**
|
||||
* Split delimiters.
|
||||
*/
|
||||
export const SPLIT_DELIM_OPTIONS = [
|
||||
{name: "Comma", value: ","},
|
||||
{name: "Space", value: " "},
|
||||
{name: "Line feed", value: "\\n"},
|
||||
{name: "CRLF", value: "\\r\\n"},
|
||||
{name: "Semi-colon", value: ";"},
|
||||
{name: "Colon", value: ":"},
|
||||
{name: "Nothing (separate chars)", value: ""}
|
||||
];
|
||||
|
||||
/**
|
||||
* Join delimiters.
|
||||
*/
|
||||
export const JOIN_DELIM_OPTIONS = [
|
||||
{name: "Line feed", value: "\\n"},
|
||||
{name: "CRLF", value: "\\r\\n"},
|
||||
{name: "Space", value: " "},
|
||||
{name: "Comma", value: ","},
|
||||
{name: "Semi-colon", value: ";"},
|
||||
{name: "Colon", value: ":"},
|
||||
{name: "Nothing (join chars)", value: ""}
|
||||
];
|
||||
|
41
src/core/lib/Extract.mjs
Normal file
41
src/core/lib/Extract.mjs
Normal file
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* Identifier extraction functions
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* Runs search operations across the input data using regular expressions.
|
||||
*
|
||||
* @param {string} input
|
||||
* @param {RegExp} searchRegex
|
||||
* @param {RegExp} removeRegex - A regular expression defining results to remove from the
|
||||
* final list
|
||||
* @param {boolean} includeTotal - Whether or not to include the total number of results
|
||||
* @returns {string}
|
||||
*/
|
||||
export function search (input, searchRegex, removeRegex, includeTotal) {
|
||||
let output = "",
|
||||
total = 0,
|
||||
match;
|
||||
|
||||
while ((match = searchRegex.exec(input))) {
|
||||
// Moves pointer when an empty string is matched (prevents infinite loop)
|
||||
if (match.index === searchRegex.lastIndex) {
|
||||
searchRegex.lastIndex++;
|
||||
}
|
||||
|
||||
if (removeRegex && removeRegex.test(match[0]))
|
||||
continue;
|
||||
total++;
|
||||
output += match[0] + "\n";
|
||||
}
|
||||
|
||||
if (includeTotal)
|
||||
output = "Total found: " + total + "\n\n" + output;
|
||||
|
||||
return output;
|
||||
}
|
20
src/core/lib/FlowControl.mjs
Normal file
20
src/core/lib/FlowControl.mjs
Normal file
|
@ -0,0 +1,20 @@
|
|||
/**
|
||||
* Flow control functions
|
||||
*
|
||||
* @author d98762625 [d98762625@gmail.com]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Returns the index of a label.
|
||||
*
|
||||
* @param {Object} state - The current state of the recipe.
|
||||
* @param {string} name - The label name to look for.
|
||||
* @returns {number}
|
||||
*/
|
||||
export function getLabelIndex(name, state) {
|
||||
return state.opList.findIndex((operation) => {
|
||||
return (operation.name === "Label") && (name === operation.ingValues[0]);
|
||||
});
|
||||
}
|
28
src/core/lib/Hash.mjs
Normal file
28
src/core/lib/Hash.mjs
Normal file
|
@ -0,0 +1,28 @@
|
|||
/**
|
||||
* Hashing resources.
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
*
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Utils from "../Utils";
|
||||
import CryptoApi from "crypto-api/src/crypto-api";
|
||||
|
||||
|
||||
/**
|
||||
* Generic hash function.
|
||||
*
|
||||
* @param {string} name
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object} [options={}]
|
||||
* @returns {string}
|
||||
*/
|
||||
export function runHash(name, input, options={}) {
|
||||
const msg = Utils.arrayBufferToStr(input, false),
|
||||
hasher = CryptoApi.getHasher(name, options);
|
||||
hasher.update(msg);
|
||||
return CryptoApi.encoder.toHex(hasher.finalize());
|
||||
}
|
||||
|
|
@ -84,9 +84,9 @@ export function toHexFast(data) {
|
|||
* fromHex("0a:14:1e", "Colon");
|
||||
*/
|
||||
export function fromHex(data, delim, byteLen=2) {
|
||||
delim = delim || (data.indexOf(" ") >= 0 ? "Space" : "None");
|
||||
delim = delim || "Auto";
|
||||
if (delim !== "None") {
|
||||
const delimRegex = Utils.regexRep(delim);
|
||||
const delimRegex = delim === "Auto" ? /[^a-f\d]/gi : Utils.regexRep(delim);
|
||||
data = data.replace(delimRegex, "");
|
||||
}
|
||||
|
||||
|
@ -99,6 +99,12 @@ export function fromHex(data, delim, byteLen=2) {
|
|||
|
||||
|
||||
/**
|
||||
* Hexadecimal delimiters.
|
||||
* To Hexadecimal delimiters.
|
||||
*/
|
||||
export const HEX_DELIM_OPTIONS = ["Space", "Comma", "Semi-colon", "Colon", "Line feed", "CRLF", "0x", "\\x", "None"];
|
||||
export const TO_HEX_DELIM_OPTIONS = ["Space", "Comma", "Semi-colon", "Colon", "Line feed", "CRLF", "0x", "\\x", "None"];
|
||||
|
||||
|
||||
/**
|
||||
* From Hexadecimal delimiters.
|
||||
*/
|
||||
export const FROM_HEX_DELIM_OPTIONS = ["Auto"].concat(TO_HEX_DELIM_OPTIONS);
|
||||
|
|
1535
src/core/lib/Magic.mjs
Normal file
1535
src/core/lib/Magic.mjs
Normal file
File diff suppressed because it is too large
Load diff
117
src/core/lib/PGP.mjs
Normal file
117
src/core/lib/PGP.mjs
Normal file
|
@ -0,0 +1,117 @@
|
|||
/**
|
||||
* PGP functions.
|
||||
*
|
||||
* @author tlwr [toby@toby.codes]
|
||||
* @author Matt C [matt@artemisbot.uk]
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
*
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*
|
||||
*/
|
||||
|
||||
import OperationError from "../errors/OperationError";
|
||||
import kbpgp from "kbpgp";
|
||||
import promisifyDefault from "es6-promisify";
|
||||
const promisify = promisifyDefault.promisify;
|
||||
|
||||
/**
|
||||
* Progress callback
|
||||
*/
|
||||
export const ASP = kbpgp.ASP({
|
||||
"progress_hook": info => {
|
||||
let msg = "";
|
||||
|
||||
switch (info.what) {
|
||||
case "guess":
|
||||
msg = "Guessing a prime";
|
||||
break;
|
||||
case "fermat":
|
||||
msg = "Factoring prime using Fermat's factorization method";
|
||||
break;
|
||||
case "mr":
|
||||
msg = "Performing Miller-Rabin primality test";
|
||||
break;
|
||||
case "passed_mr":
|
||||
msg = "Passed Miller-Rabin primality test";
|
||||
break;
|
||||
case "failed_mr":
|
||||
msg = "Failed Miller-Rabin primality test";
|
||||
break;
|
||||
case "found":
|
||||
msg = "Prime found";
|
||||
break;
|
||||
default:
|
||||
msg = `Stage: ${info.what}`;
|
||||
}
|
||||
|
||||
if (ENVIRONMENT_IS_WORKER())
|
||||
self.sendStatusMessage(msg);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Get size of subkey
|
||||
*
|
||||
* @param {number} keySize
|
||||
* @returns {number}
|
||||
*/
|
||||
export function getSubkeySize(keySize) {
|
||||
return {
|
||||
1024: 1024,
|
||||
2048: 1024,
|
||||
4096: 2048,
|
||||
256: 256,
|
||||
384: 256,
|
||||
}[keySize];
|
||||
}
|
||||
|
||||
/**
|
||||
* Import private key and unlock if necessary
|
||||
*
|
||||
* @param {string} privateKey
|
||||
* @param {string} [passphrase]
|
||||
* @returns {Object}
|
||||
*/
|
||||
export async function importPrivateKey(privateKey, passphrase) {
|
||||
try {
|
||||
const key = await promisify(kbpgp.KeyManager.import_from_armored_pgp)({
|
||||
armored: privateKey,
|
||||
opts: {
|
||||
"no_check_keys": true
|
||||
}
|
||||
});
|
||||
if (key.is_pgp_locked()) {
|
||||
if (passphrase) {
|
||||
await promisify(key.unlock_pgp.bind(key))({
|
||||
passphrase
|
||||
});
|
||||
} else {
|
||||
throw new OperationError("Did not provide passphrase with locked private key.");
|
||||
}
|
||||
}
|
||||
return key;
|
||||
} catch (err) {
|
||||
throw new OperationError(`Could not import private key: ${err}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Import public key
|
||||
*
|
||||
* @param {string} publicKey
|
||||
* @returns {Object}
|
||||
*/
|
||||
export async function importPublicKey (publicKey) {
|
||||
try {
|
||||
const key = await promisify(kbpgp.KeyManager.import_from_armored_pgp)({
|
||||
armored: publicKey,
|
||||
opts: {
|
||||
"no_check_keys": true
|
||||
}
|
||||
});
|
||||
return key;
|
||||
} catch (err) {
|
||||
throw new OperationError(`Could not import public key: ${err}`);
|
||||
}
|
||||
}
|
108
src/core/operations/AESDecrypt.mjs
Normal file
108
src/core/operations/AESDecrypt.mjs
Normal file
|
@ -0,0 +1,108 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import forge from "node-forge/dist/forge.min.js";
|
||||
import OperationError from "../errors/OperationError";
|
||||
|
||||
/**
|
||||
* AES Decrypt operation
|
||||
*/
|
||||
class AESDecrypt extends Operation {
|
||||
|
||||
/**
|
||||
* AESDecrypt constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "AES Decrypt";
|
||||
this.module = "Ciphers";
|
||||
this.description = "Advanced Encryption Standard (AES) is a U.S. Federal Information Processing Standard (FIPS). It was selected after a 5-year process where 15 competing designs were evaluated.<br><br><b>Key:</b> The following algorithms will be used based on the size of the key:<ul><li>16 bytes = AES-128</li><li>24 bytes = AES-192</li><li>32 bytes = AES-256</li></ul><br><br><b>IV:</b> The Initialization Vector should be 16 bytes long. If not entered, it will default to 16 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used.<br><br><b>GCM Tag:</b> This field is ignored unless 'GCM' mode is used.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Key",
|
||||
"type": "toggleString",
|
||||
"value": "",
|
||||
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
|
||||
},
|
||||
{
|
||||
"name": "IV",
|
||||
"type": "toggleString",
|
||||
"value": "",
|
||||
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
|
||||
},
|
||||
{
|
||||
"name": "Mode",
|
||||
"type": "option",
|
||||
"value": ["CBC", "CFB", "OFB", "CTR", "GCM", "ECB"]
|
||||
},
|
||||
{
|
||||
"name": "Input",
|
||||
"type": "option",
|
||||
"value": ["Hex", "Raw"]
|
||||
},
|
||||
{
|
||||
"name": "Output",
|
||||
"type": "option",
|
||||
"value": ["Raw", "Hex"]
|
||||
},
|
||||
{
|
||||
"name": "GCM Tag",
|
||||
"type": "toggleString",
|
||||
"value": "",
|
||||
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*
|
||||
* @throws {OperationError} if cannot decrypt input or invalid key length
|
||||
*/
|
||||
run(input, args) {
|
||||
const key = Utils.convertToByteArray(args[0].string, args[0].option),
|
||||
iv = Utils.convertToByteArray(args[1].string, args[1].option),
|
||||
mode = args[2],
|
||||
inputType = args[3],
|
||||
outputType = args[4],
|
||||
gcmTag = Utils.convertToByteString(args[5].string, args[5].option);
|
||||
|
||||
if ([16, 24, 32].indexOf(key.length) < 0) {
|
||||
throw new OperationError(`Invalid key length: ${key.length} bytes
|
||||
|
||||
The following algorithms will be used based on the size of the key:
|
||||
16 bytes = AES-128
|
||||
24 bytes = AES-192
|
||||
32 bytes = AES-256`);
|
||||
}
|
||||
|
||||
input = Utils.convertToByteString(input, inputType);
|
||||
|
||||
const decipher = forge.cipher.createDecipher("AES-" + mode, key);
|
||||
decipher.start({
|
||||
iv: iv,
|
||||
tag: gcmTag
|
||||
});
|
||||
decipher.update(forge.util.createBuffer(input));
|
||||
const result = decipher.finish();
|
||||
|
||||
if (result) {
|
||||
return outputType === "Hex" ? decipher.output.toHex() : decipher.output.getBytes();
|
||||
} else {
|
||||
throw new OperationError("Unable to decrypt input with these parameters.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default AESDecrypt;
|
106
src/core/operations/AESEncrypt.mjs
Normal file
106
src/core/operations/AESEncrypt.mjs
Normal file
|
@ -0,0 +1,106 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import forge from "node-forge/dist/forge.min.js";
|
||||
import OperationError from "../errors/OperationError";
|
||||
|
||||
/**
|
||||
* AES Encrypt operation
|
||||
*/
|
||||
class AESEncrypt extends Operation {
|
||||
|
||||
/**
|
||||
* AESEncrypt constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "AES Encrypt";
|
||||
this.module = "Ciphers";
|
||||
this.description = "Advanced Encryption Standard (AES) is a U.S. Federal Information Processing Standard (FIPS). It was selected after a 5-year process where 15 competing designs were evaluated.<br><br><b>Key:</b> The following algorithms will be used based on the size of the key:<ul><li>16 bytes = AES-128</li><li>24 bytes = AES-192</li><li>32 bytes = AES-256</li></ul>You can generate a password-based key using one of the KDF operations.<br><br><b>IV:</b> The Initialization Vector should be 16 bytes long. If not entered, it will default to 16 null bytes.<br><br><b>Padding:</b> In CBC and ECB mode, PKCS#7 padding will be used.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Key",
|
||||
"type": "toggleString",
|
||||
"value": "",
|
||||
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
|
||||
},
|
||||
{
|
||||
"name": "IV",
|
||||
"type": "toggleString",
|
||||
"value": "",
|
||||
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
|
||||
},
|
||||
{
|
||||
"name": "Mode",
|
||||
"type": "option",
|
||||
"value": ["CBC", "CFB", "OFB", "CTR", "GCM", "ECB"]
|
||||
},
|
||||
{
|
||||
"name": "Input",
|
||||
"type": "option",
|
||||
"value": ["Raw", "Hex"]
|
||||
},
|
||||
{
|
||||
"name": "Output",
|
||||
"type": "option",
|
||||
"value": ["Hex", "Raw"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*
|
||||
* @throws {OperationError} if invalid key length
|
||||
*/
|
||||
run(input, args) {
|
||||
const key = Utils.convertToByteArray(args[0].string, args[0].option),
|
||||
iv = Utils.convertToByteArray(args[1].string, args[1].option),
|
||||
mode = args[2],
|
||||
inputType = args[3],
|
||||
outputType = args[4];
|
||||
|
||||
if ([16, 24, 32].indexOf(key.length) < 0) {
|
||||
throw new OperationError(`Invalid key length: ${key.length} bytes
|
||||
|
||||
The following algorithms will be used based on the size of the key:
|
||||
16 bytes = AES-128
|
||||
24 bytes = AES-192
|
||||
32 bytes = AES-256`);
|
||||
}
|
||||
|
||||
input = Utils.convertToByteString(input, inputType);
|
||||
|
||||
const cipher = forge.cipher.createCipher("AES-" + mode, key);
|
||||
cipher.start({iv: iv});
|
||||
cipher.update(forge.util.createBuffer(input));
|
||||
cipher.finish();
|
||||
|
||||
if (outputType === "Hex") {
|
||||
if (mode === "GCM") {
|
||||
return cipher.output.toHex() + "\n\n" +
|
||||
"Tag: " + cipher.mode.tag.toHex();
|
||||
}
|
||||
return cipher.output.toHex();
|
||||
} else {
|
||||
if (mode === "GCM") {
|
||||
return cipher.output.getBytes() + "\n\n" +
|
||||
"Tag: " + cipher.mode.tag.getBytes();
|
||||
}
|
||||
return cipher.output.getBytes();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default AESEncrypt;
|
46
src/core/operations/AddLineNumbers.mjs
Normal file
46
src/core/operations/AddLineNumbers.mjs
Normal file
|
@ -0,0 +1,46 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
|
||||
/**
|
||||
* Add line numbers operation
|
||||
*/
|
||||
class AddLineNumbers extends Operation {
|
||||
|
||||
/**
|
||||
* AddLineNumbers constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Add line numbers";
|
||||
this.module = "Default";
|
||||
this.description = "Adds line numbers to the output.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const lines = input.split("\n"),
|
||||
width = lines.length.toString().length;
|
||||
let output = "";
|
||||
|
||||
for (let n = 0; n < lines.length; n++) {
|
||||
output += (n+1).toString().padStart(width, " ") + " " + lines[n] + "\n";
|
||||
}
|
||||
return output.slice(0, output.length-1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default AddLineNumbers;
|
52
src/core/operations/Adler32Checksum.mjs
Normal file
52
src/core/operations/Adler32Checksum.mjs
Normal file
|
@ -0,0 +1,52 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
|
||||
/**
|
||||
* Adler-32 Checksum operation
|
||||
*/
|
||||
class Adler32Checksum extends Operation {
|
||||
|
||||
/**
|
||||
* Adler32Checksum constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Adler-32 Checksum";
|
||||
this.module = "Hashing";
|
||||
this.description = "Adler-32 is a checksum algorithm which was invented by Mark Adler in 1995, and is a modification of the Fletcher checksum. Compared to a cyclic redundancy check of the same length, it trades reliability for speed (preferring the latter).<br><br>Adler-32 is more reliable than Fletcher-16, and slightly less reliable than Fletcher-32.";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const MOD_ADLER = 65521;
|
||||
let a = 1,
|
||||
b = 0;
|
||||
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
a += input[i];
|
||||
b += a;
|
||||
}
|
||||
|
||||
a %= MOD_ADLER;
|
||||
b %= MOD_ADLER;
|
||||
|
||||
return Utils.hex(((b << 16) | a) >>> 0, 8);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Adler32Checksum;
|
105
src/core/operations/AffineCipherDecode.mjs
Normal file
105
src/core/operations/AffineCipherDecode.mjs
Normal file
|
@ -0,0 +1,105 @@
|
|||
/**
|
||||
* @author Matt C [matt@artemisbot.uk]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import OperationError from "../errors/OperationError";
|
||||
|
||||
/**
|
||||
* Affine Cipher Decode operation
|
||||
*/
|
||||
class AffineCipherDecode extends Operation {
|
||||
|
||||
/**
|
||||
* AffineCipherDecode constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Affine Cipher Decode";
|
||||
this.module = "Ciphers";
|
||||
this.description = "The Affine cipher is a type of monoalphabetic substitution cipher. To decrypt, each letter in an alphabet is mapped to its numeric equivalent, decrypted by a mathematical function, and converted back to a letter.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "a",
|
||||
"type": "number",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"name": "b",
|
||||
"type": "number",
|
||||
"value": 0
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*
|
||||
* @throws {OperationError} if a or b values are invalid
|
||||
*/
|
||||
run(input, args) {
|
||||
const alphabet = "abcdefghijklmnopqrstuvwxyz",
|
||||
[a, b] = args,
|
||||
aModInv = Utils.modInv(a, 26); // Calculates modular inverse of a
|
||||
let output = "";
|
||||
|
||||
if (!/^\+?(0|[1-9]\d*)$/.test(a) || !/^\+?(0|[1-9]\d*)$/.test(b)) {
|
||||
throw new OperationError("The values of a and b can only be integers.");
|
||||
}
|
||||
|
||||
if (Utils.gcd(a, 26) !== 1) {
|
||||
throw new OperationError("The value of `a` must be coprime to 26.");
|
||||
}
|
||||
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
if (alphabet.indexOf(input[i]) >= 0) {
|
||||
// Uses the affine decode function (y-b * A') % m = x (where m is length of the alphabet and A' is modular inverse)
|
||||
output += alphabet[Utils.mod((alphabet.indexOf(input[i]) - b) * aModInv, 26)];
|
||||
} else if (alphabet.indexOf(input[i].toLowerCase()) >= 0) {
|
||||
// Same as above, accounting for uppercase
|
||||
output += alphabet[Utils.mod((alphabet.indexOf(input[i].toLowerCase()) - b) * aModInv, 26)].toUpperCase();
|
||||
} else {
|
||||
// Non-alphabetic characters
|
||||
output += input[i];
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight Affine Cipher Decode
|
||||
*
|
||||
* @param {Object[]} pos
|
||||
* @param {number} pos[].start
|
||||
* @param {number} pos[].end
|
||||
* @param {Object[]} args
|
||||
* @returns {Object[]} pos
|
||||
*/
|
||||
highlight(pos, args) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight Affine Cipher Decode in reverse
|
||||
*
|
||||
* @param {Object[]} pos
|
||||
* @param {number} pos[].start
|
||||
* @param {number} pos[].end
|
||||
* @param {Object[]} args
|
||||
* @returns {Object[]} pos
|
||||
*/
|
||||
highlightReverse(pos, args) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default AffineCipherDecode;
|
77
src/core/operations/AffineCipherEncode.mjs
Normal file
77
src/core/operations/AffineCipherEncode.mjs
Normal file
|
@ -0,0 +1,77 @@
|
|||
/**
|
||||
* @author Matt C [matt@artemisbot.uk]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import { affineEncode } from "../lib/Ciphers";
|
||||
|
||||
/**
|
||||
* Affine Cipher Encode operation
|
||||
*/
|
||||
class AffineCipherEncode extends Operation {
|
||||
|
||||
/**
|
||||
* AffineCipherEncode constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Affine Cipher Encode";
|
||||
this.module = "Ciphers";
|
||||
this.description = "The Affine cipher is a type of monoalphabetic substitution cipher, wherein each letter in an alphabet is mapped to its numeric equivalent, encrypted using simple mathematical function, <code>(ax + b) % 26</code>, and converted back to a letter.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "a",
|
||||
"type": "number",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"name": "b",
|
||||
"type": "number",
|
||||
"value": 0
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
return affineEncode(input, args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight Affine Cipher Encode
|
||||
*
|
||||
* @param {Object[]} pos
|
||||
* @param {number} pos[].start
|
||||
* @param {number} pos[].end
|
||||
* @param {Object[]} args
|
||||
* @returns {Object[]} pos
|
||||
*/
|
||||
highlight(pos, args) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight Affine Cipher Encode in reverse
|
||||
*
|
||||
* @param {Object[]} pos
|
||||
* @param {number} pos[].start
|
||||
* @param {number} pos[].end
|
||||
* @param {Object[]} args
|
||||
* @returns {Object[]} pos
|
||||
*/
|
||||
highlightReverse(pos, args) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default AffineCipherEncode;
|
183
src/core/operations/AnalyseHash.mjs
Normal file
183
src/core/operations/AnalyseHash.mjs
Normal file
|
@ -0,0 +1,183 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
|
||||
/**
|
||||
* Analyse hash operation
|
||||
*/
|
||||
class AnalyseHash extends Operation {
|
||||
|
||||
/**
|
||||
* AnalyseHash constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Analyse hash";
|
||||
this.module = "Hashing";
|
||||
this.description = "Tries to determine information about a given hash and suggests which algorithm may have been used to generate it based on its length.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
input = input.replace(/\s/g, "");
|
||||
|
||||
let output = "",
|
||||
possibleHashFunctions = [];
|
||||
const byteLength = input.length / 2,
|
||||
bitLength = byteLength * 8;
|
||||
|
||||
if (!/^[a-f0-9]+$/i.test(input)) {
|
||||
throw new OperationError("Invalid hash");
|
||||
}
|
||||
|
||||
output += "Hash length: " + input.length + "\n" +
|
||||
"Byte length: " + byteLength + "\n" +
|
||||
"Bit length: " + bitLength + "\n\n" +
|
||||
"Based on the length, this hash could have been generated by one of the following hashing functions:\n";
|
||||
|
||||
switch (bitLength) {
|
||||
case 4:
|
||||
possibleHashFunctions = [
|
||||
"Fletcher-4",
|
||||
"Luhn algorithm",
|
||||
"Verhoeff algorithm",
|
||||
];
|
||||
break;
|
||||
case 8:
|
||||
possibleHashFunctions = [
|
||||
"Fletcher-8",
|
||||
];
|
||||
break;
|
||||
case 16:
|
||||
possibleHashFunctions = [
|
||||
"BSD checksum",
|
||||
"CRC-16",
|
||||
"SYSV checksum",
|
||||
"Fletcher-16"
|
||||
];
|
||||
break;
|
||||
case 32:
|
||||
possibleHashFunctions = [
|
||||
"CRC-32",
|
||||
"Fletcher-32",
|
||||
"Adler-32",
|
||||
];
|
||||
break;
|
||||
case 64:
|
||||
possibleHashFunctions = [
|
||||
"CRC-64",
|
||||
"RIPEMD-64",
|
||||
"SipHash",
|
||||
];
|
||||
break;
|
||||
case 128:
|
||||
possibleHashFunctions = [
|
||||
"MD5",
|
||||
"MD4",
|
||||
"MD2",
|
||||
"HAVAL-128",
|
||||
"RIPEMD-128",
|
||||
"Snefru",
|
||||
"Tiger-128",
|
||||
];
|
||||
break;
|
||||
case 160:
|
||||
possibleHashFunctions = [
|
||||
"SHA-1",
|
||||
"SHA-0",
|
||||
"FSB-160",
|
||||
"HAS-160",
|
||||
"HAVAL-160",
|
||||
"RIPEMD-160",
|
||||
"Tiger-160",
|
||||
];
|
||||
break;
|
||||
case 192:
|
||||
possibleHashFunctions = [
|
||||
"Tiger",
|
||||
"HAVAL-192",
|
||||
];
|
||||
break;
|
||||
case 224:
|
||||
possibleHashFunctions = [
|
||||
"SHA-224",
|
||||
"SHA3-224",
|
||||
"ECOH-224",
|
||||
"FSB-224",
|
||||
"HAVAL-224",
|
||||
];
|
||||
break;
|
||||
case 256:
|
||||
possibleHashFunctions = [
|
||||
"SHA-256",
|
||||
"SHA3-256",
|
||||
"BLAKE-256",
|
||||
"ECOH-256",
|
||||
"FSB-256",
|
||||
"GOST",
|
||||
"Grøstl-256",
|
||||
"HAVAL-256",
|
||||
"PANAMA",
|
||||
"RIPEMD-256",
|
||||
"Snefru",
|
||||
];
|
||||
break;
|
||||
case 320:
|
||||
possibleHashFunctions = [
|
||||
"RIPEMD-320",
|
||||
];
|
||||
break;
|
||||
case 384:
|
||||
possibleHashFunctions = [
|
||||
"SHA-384",
|
||||
"SHA3-384",
|
||||
"ECOH-384",
|
||||
"FSB-384",
|
||||
];
|
||||
break;
|
||||
case 512:
|
||||
possibleHashFunctions = [
|
||||
"SHA-512",
|
||||
"SHA3-512",
|
||||
"BLAKE-512",
|
||||
"ECOH-512",
|
||||
"FSB-512",
|
||||
"Grøstl-512",
|
||||
"JH",
|
||||
"MD6",
|
||||
"Spectral Hash",
|
||||
"SWIFFT",
|
||||
"Whirlpool",
|
||||
];
|
||||
break;
|
||||
case 1024:
|
||||
possibleHashFunctions = [
|
||||
"Fowler-Noll-Vo",
|
||||
];
|
||||
break;
|
||||
default:
|
||||
possibleHashFunctions = [
|
||||
"Unknown"
|
||||
];
|
||||
break;
|
||||
}
|
||||
|
||||
return output + possibleHashFunctions.join("\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default AnalyseHash;
|
66
src/core/operations/AtbashCipher.mjs
Normal file
66
src/core/operations/AtbashCipher.mjs
Normal file
|
@ -0,0 +1,66 @@
|
|||
/**
|
||||
* @author Matt C [matt@artemisbot.uk]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import { affineEncode } from "../lib/Ciphers";
|
||||
|
||||
/**
|
||||
* Atbash Cipher operation
|
||||
*/
|
||||
class AtbashCipher extends Operation {
|
||||
|
||||
/**
|
||||
* AtbashCipher constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Atbash Cipher";
|
||||
this.module = "Ciphers";
|
||||
this.description = "Atbash is a mono-alphabetic substitution cipher originally used to encode the Hebrew alphabet. It has been modified here for use with the Latin alphabet.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
return affineEncode(input, [25, 25]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight Atbash Cipher
|
||||
*
|
||||
* @param {Object[]} pos
|
||||
* @param {number} pos[].start
|
||||
* @param {number} pos[].end
|
||||
* @param {Object[]} args
|
||||
* @returns {Object[]} pos
|
||||
*/
|
||||
highlight(pos, args) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight Atbash Cipher in reverse
|
||||
*
|
||||
* @param {Object[]} pos
|
||||
* @param {number} pos[].start
|
||||
* @param {number} pos[].end
|
||||
* @param {Object[]} args
|
||||
* @returns {Object[]} pos
|
||||
*/
|
||||
highlightReverse(pos, args) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default AtbashCipher;
|
50
src/core/operations/BSONDeserialise.mjs
Normal file
50
src/core/operations/BSONDeserialise.mjs
Normal file
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import bsonjs from "bson";
|
||||
import OperationError from "../errors/OperationError";
|
||||
|
||||
/**
|
||||
* BSON deserialise operation
|
||||
*/
|
||||
class BSONDeserialise extends Operation {
|
||||
|
||||
/**
|
||||
* BSONDeserialise constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "BSON deserialise";
|
||||
this.module = "BSON";
|
||||
this.description = "BSON is a computer data interchange format used mainly as a data storage and network transfer format in the MongoDB database. It is a binary form for representing simple data structures, associative arrays (called objects or documents in MongoDB), and various data types of specific interest to MongoDB. The name 'BSON' is based on the term JSON and stands for 'Binary JSON'.<br><br>Input data should be in a raw bytes format.";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
if (!input.byteLength) return "";
|
||||
|
||||
const bson = new bsonjs();
|
||||
|
||||
try {
|
||||
const data = bson.deserialize(new Buffer(input));
|
||||
return JSON.stringify(data, null, 2);
|
||||
} catch (err) {
|
||||
throw new OperationError(err.toString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default BSONDeserialise;
|
50
src/core/operations/BSONSerialise.mjs
Normal file
50
src/core/operations/BSONSerialise.mjs
Normal file
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import bsonjs from "bson";
|
||||
import OperationError from "../errors/OperationError";
|
||||
|
||||
/**
|
||||
* BSON serialise operation
|
||||
*/
|
||||
class BSONSerialise extends Operation {
|
||||
|
||||
/**
|
||||
* BSONSerialise constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "BSON serialise";
|
||||
this.module = "BSON";
|
||||
this.description = "BSON is a computer data interchange format used mainly as a data storage and network transfer format in the MongoDB database. It is a binary form for representing simple data structures, associative arrays (called objects or documents in MongoDB), and various data types of specific interest to MongoDB. The name 'BSON' is based on the term JSON and stands for 'Binary JSON'.<br><br>Input data should be valid JSON.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "ArrayBuffer";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {ArrayBuffer}
|
||||
*/
|
||||
run(input, args) {
|
||||
if (!input) return new ArrayBuffer();
|
||||
|
||||
const bson = new bsonjs();
|
||||
|
||||
try {
|
||||
const data = JSON.parse(input);
|
||||
return bson.serialize(data).buffer;
|
||||
} catch (err) {
|
||||
throw new OperationError(err.toString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default BSONSerialise;
|
54
src/core/operations/Bcrypt.mjs
Normal file
54
src/core/operations/Bcrypt.mjs
Normal file
|
@ -0,0 +1,54 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import bcrypt from "bcryptjs";
|
||||
|
||||
/**
|
||||
* Bcrypt operation
|
||||
*/
|
||||
class Bcrypt extends Operation {
|
||||
|
||||
/**
|
||||
* Bcrypt constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Bcrypt";
|
||||
this.module = "Hashing";
|
||||
this.description = "bcrypt is a password hashing function designed by Niels Provos and David Mazi\xe8res, based on the Blowfish cipher, and presented at USENIX in 1999. Besides incorporating a salt to protect against rainbow table attacks, bcrypt is an adaptive function: over time, the iteration count (rounds) can be increased to make it slower, so it remains resistant to brute-force search attacks even with increasing computation power.<br><br>Enter the password in the input to generate its hash.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Rounds",
|
||||
"type": "number",
|
||||
"value": 10
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
async run(input, args) {
|
||||
const rounds = args[0];
|
||||
const salt = await bcrypt.genSalt(rounds);
|
||||
|
||||
return await bcrypt.hash(input, salt, null, p => {
|
||||
// Progress callback
|
||||
if (ENVIRONMENT_IS_WORKER())
|
||||
self.sendStatusMessage(`Progress: ${(p * 100).toFixed(0)}%`);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Bcrypt;
|
55
src/core/operations/BcryptCompare.mjs
Normal file
55
src/core/operations/BcryptCompare.mjs
Normal file
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import bcrypt from "bcryptjs";
|
||||
|
||||
/**
|
||||
* Bcrypt compare operation
|
||||
*/
|
||||
class BcryptCompare extends Operation {
|
||||
|
||||
/**
|
||||
* BcryptCompare constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Bcrypt compare";
|
||||
this.module = "Hashing";
|
||||
this.description = "Tests whether the input matches the given bcrypt hash. To test multiple possible passwords, use the 'Fork' operation.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Hash",
|
||||
"type": "string",
|
||||
"value": ""
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
async run(input, args) {
|
||||
const hash = args[0];
|
||||
|
||||
const match = await bcrypt.compare(input, hash, null, p => {
|
||||
// Progress callback
|
||||
if (ENVIRONMENT_IS_WORKER())
|
||||
self.sendStatusMessage(`Progress: ${(p * 100).toFixed(0)}%`);
|
||||
});
|
||||
|
||||
return match ? "Match: " + input : "No match";
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default BcryptCompare;
|
48
src/core/operations/BcryptParse.mjs
Normal file
48
src/core/operations/BcryptParse.mjs
Normal file
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import bcrypt from "bcryptjs";
|
||||
|
||||
/**
|
||||
* Bcrypt parse operation
|
||||
*/
|
||||
class BcryptParse extends Operation {
|
||||
|
||||
/**
|
||||
* BcryptParse constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Bcrypt parse";
|
||||
this.module = "Hashing";
|
||||
this.description = "Parses a bcrypt hash to determine the number of rounds used, the salt, and the password hash.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
async run(input, args) {
|
||||
try {
|
||||
return `Rounds: ${bcrypt.getRounds(input)}
|
||||
Salt: ${bcrypt.getSalt(input)}
|
||||
Password hash: ${input.split(bcrypt.getSalt(input))[1]}
|
||||
Full hash: ${input}`;
|
||||
} catch (err) {
|
||||
throw new OperationError("Error: " + err.toString());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default BcryptParse;
|
124
src/core/operations/BifidCipherDecode.mjs
Normal file
124
src/core/operations/BifidCipherDecode.mjs
Normal file
|
@ -0,0 +1,124 @@
|
|||
/**
|
||||
* @author Matt C [matt@artemisbot.uk]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import { genPolybiusSquare } from "../lib/Ciphers";
|
||||
import OperationError from "../errors/OperationError";
|
||||
|
||||
/**
|
||||
* Bifid Cipher Decode operation
|
||||
*/
|
||||
class BifidCipherDecode extends Operation {
|
||||
|
||||
/**
|
||||
* BifidCipherDecode constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Bifid Cipher Decode";
|
||||
this.module = "Ciphers";
|
||||
this.description = "The Bifid cipher is a cipher which uses a Polybius square in conjunction with transposition, which can be fairly difficult to decipher without knowing the alphabet keyword.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Keyword",
|
||||
"type": "string",
|
||||
"value": ""
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*
|
||||
* @throws {OperationError} if invalid key
|
||||
*/
|
||||
run(input, args) {
|
||||
const keywordStr = args[0].toUpperCase().replace("J", "I"),
|
||||
keyword = keywordStr.split("").unique(),
|
||||
alpha = "ABCDEFGHIKLMNOPQRSTUVWXYZ",
|
||||
structure = [];
|
||||
|
||||
let output = "",
|
||||
count = 0,
|
||||
trans = "";
|
||||
|
||||
if (!/^[A-Z]+$/.test(keywordStr) && keyword.length > 0)
|
||||
throw new OperationError("The key must consist only of letters in the English alphabet");
|
||||
|
||||
const polybius = genPolybiusSquare(keywordStr);
|
||||
|
||||
input.replace("J", "I").split("").forEach((letter) => {
|
||||
const alpInd = alpha.split("").indexOf(letter.toLocaleUpperCase()) >= 0;
|
||||
let polInd;
|
||||
|
||||
if (alpInd) {
|
||||
for (let i = 0; i < 5; i++) {
|
||||
polInd = polybius[i].indexOf(letter.toLocaleUpperCase());
|
||||
if (polInd >= 0) {
|
||||
trans += `${i}${polInd}`;
|
||||
}
|
||||
}
|
||||
|
||||
if (alpha.split("").indexOf(letter) >= 0) {
|
||||
structure.push(true);
|
||||
} else if (alpInd) {
|
||||
structure.push(false);
|
||||
}
|
||||
} else {
|
||||
structure.push(letter);
|
||||
}
|
||||
});
|
||||
|
||||
structure.forEach(pos => {
|
||||
if (typeof pos === "boolean") {
|
||||
const coords = [trans[count], trans[count+trans.length/2]];
|
||||
|
||||
output += pos ?
|
||||
polybius[coords[0]][coords[1]] :
|
||||
polybius[coords[0]][coords[1]].toLocaleLowerCase();
|
||||
count++;
|
||||
} else {
|
||||
output += pos;
|
||||
}
|
||||
});
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight Bifid Cipher Decode
|
||||
*
|
||||
* @param {Object[]} pos
|
||||
* @param {number} pos[].start
|
||||
* @param {number} pos[].end
|
||||
* @param {Object[]} args
|
||||
* @returns {Object[]} pos
|
||||
*/
|
||||
highlight(pos, args) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight Bifid Cipher Decode in reverse
|
||||
*
|
||||
* @param {Object[]} pos
|
||||
* @param {number} pos[].start
|
||||
* @param {number} pos[].end
|
||||
* @param {Object[]} args
|
||||
* @returns {Object[]} pos
|
||||
*/
|
||||
highlightReverse(pos, args) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default BifidCipherDecode;
|
129
src/core/operations/BifidCipherEncode.mjs
Normal file
129
src/core/operations/BifidCipherEncode.mjs
Normal file
|
@ -0,0 +1,129 @@
|
|||
/**
|
||||
* @author Matt C [matt@artemisbot.uk]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import { genPolybiusSquare } from "../lib/Ciphers";
|
||||
|
||||
/**
|
||||
* Bifid Cipher Encode operation
|
||||
*/
|
||||
class BifidCipherEncode extends Operation {
|
||||
|
||||
/**
|
||||
* BifidCipherEncode constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Bifid Cipher Encode";
|
||||
this.module = "Ciphers";
|
||||
this.description = "The Bifid cipher is a cipher which uses a Polybius square in conjunction with transposition, which can be fairly difficult to decipher without knowing the alphabet keyword.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Keyword",
|
||||
"type": "string",
|
||||
"value": ""
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*
|
||||
* @throws {OperationError} if key is invalid
|
||||
*/
|
||||
run(input, args) {
|
||||
const keywordStr = args[0].toUpperCase().replace("J", "I"),
|
||||
keyword = keywordStr.split("").unique(),
|
||||
alpha = "ABCDEFGHIKLMNOPQRSTUVWXYZ",
|
||||
xCo = [],
|
||||
yCo = [],
|
||||
structure = [];
|
||||
|
||||
let output = "",
|
||||
count = 0;
|
||||
|
||||
|
||||
if (!/^[A-Z]+$/.test(keywordStr) && keyword.length > 0)
|
||||
throw new OperationError("The key must consist only of letters in the English alphabet");
|
||||
|
||||
const polybius = genPolybiusSquare(keywordStr);
|
||||
|
||||
input.replace("J", "I").split("").forEach(letter => {
|
||||
const alpInd = alpha.split("").indexOf(letter.toLocaleUpperCase()) >= 0;
|
||||
let polInd;
|
||||
|
||||
if (alpInd) {
|
||||
for (let i = 0; i < 5; i++) {
|
||||
polInd = polybius[i].indexOf(letter.toLocaleUpperCase());
|
||||
if (polInd >= 0) {
|
||||
xCo.push(polInd);
|
||||
yCo.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (alpha.split("").indexOf(letter) >= 0) {
|
||||
structure.push(true);
|
||||
} else if (alpInd) {
|
||||
structure.push(false);
|
||||
}
|
||||
} else {
|
||||
structure.push(letter);
|
||||
}
|
||||
});
|
||||
|
||||
const trans = `${yCo.join("")}${xCo.join("")}`;
|
||||
|
||||
structure.forEach(pos => {
|
||||
if (typeof pos === "boolean") {
|
||||
const coords = trans.substr(2*count, 2).split("");
|
||||
|
||||
output += pos ?
|
||||
polybius[coords[0]][coords[1]] :
|
||||
polybius[coords[0]][coords[1]].toLocaleLowerCase();
|
||||
count++;
|
||||
} else {
|
||||
output += pos;
|
||||
}
|
||||
});
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight Bifid Cipher Encode
|
||||
*
|
||||
* @param {Object[]} pos
|
||||
* @param {number} pos[].start
|
||||
* @param {number} pos[].end
|
||||
* @param {Object[]} args
|
||||
* @returns {Object[]} pos
|
||||
*/
|
||||
highlight(pos, args) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight Bifid Cipher Encode in reverse
|
||||
*
|
||||
* @param {Object[]} pos
|
||||
* @param {number} pos[].start
|
||||
* @param {number} pos[].end
|
||||
* @param {Object[]} args
|
||||
* @returns {Object[]} pos
|
||||
*/
|
||||
highlightReverse(pos, args) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default BifidCipherEncode;
|
75
src/core/operations/BitShiftLeft.mjs
Normal file
75
src/core/operations/BitShiftLeft.mjs
Normal file
|
@ -0,0 +1,75 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
|
||||
/**
|
||||
* Bit shift left operation
|
||||
*/
|
||||
class BitShiftLeft extends Operation {
|
||||
|
||||
/**
|
||||
* BitShiftLeft constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Bit shift left";
|
||||
this.module = "Default";
|
||||
this.description = "Shifts the bits in each byte towards the left by the specified amount.";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "byteArray";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Amount",
|
||||
"type": "number",
|
||||
"value": 1
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
run(input, args) {
|
||||
const amount = args[0];
|
||||
|
||||
return input.map(b => {
|
||||
return (b << amount) & 0xff;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight Bit shift left
|
||||
*
|
||||
* @param {Object[]} pos
|
||||
* @param {number} pos[].start
|
||||
* @param {number} pos[].end
|
||||
* @param {Object[]} args
|
||||
* @returns {Object[]} pos
|
||||
*/
|
||||
highlight(pos, args) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight Bit shift left in reverse
|
||||
*
|
||||
* @param {Object[]} pos
|
||||
* @param {number} pos[].start
|
||||
* @param {number} pos[].end
|
||||
* @param {Object[]} args
|
||||
* @returns {Object[]} pos
|
||||
*/
|
||||
highlightReverse(pos, args) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default BitShiftLeft;
|
82
src/core/operations/BitShiftRight.mjs
Normal file
82
src/core/operations/BitShiftRight.mjs
Normal file
|
@ -0,0 +1,82 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
|
||||
/**
|
||||
* Bit shift right operation
|
||||
*/
|
||||
class BitShiftRight extends Operation {
|
||||
|
||||
/**
|
||||
* BitShiftRight constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Bit shift right";
|
||||
this.module = "Default";
|
||||
this.description = "Shifts the bits in each byte towards the right by the specified amount.<br><br><i>Logical shifts</i> replace the leftmost bits with zeros.<br><i>Arithmetic shifts</i> preserve the most significant bit (MSB) of the original byte keeping the sign the same (positive or negative).";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "byteArray";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Amount",
|
||||
"type": "number",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"name": "Type",
|
||||
"type": "option",
|
||||
"value": ["Logical shift", "Arithmetic shift"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
run(input, args) {
|
||||
const amount = args[0],
|
||||
type = args[1],
|
||||
mask = type === "Logical shift" ? 0 : 0x80;
|
||||
|
||||
return input.map(b => {
|
||||
return (b >>> amount) ^ (b & mask);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight Bit shift right
|
||||
*
|
||||
* @param {Object[]} pos
|
||||
* @param {number} pos[].start
|
||||
* @param {number} pos[].end
|
||||
* @param {Object[]} args
|
||||
* @returns {Object[]} pos
|
||||
*/
|
||||
highlight(pos, args) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight Bit shift right in reverse
|
||||
*
|
||||
* @param {Object[]} pos
|
||||
* @param {number} pos[].start
|
||||
* @param {number} pos[].end
|
||||
* @param {Object[]} args
|
||||
* @returns {Object[]} pos
|
||||
*/
|
||||
highlightReverse(pos, args) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default BitShiftRight;
|
55
src/core/operations/Bzip2Decompress.mjs
Normal file
55
src/core/operations/Bzip2Decompress.mjs
Normal file
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import bzip2 from "../vendor/bzip2.js";
|
||||
import OperationError from "../errors/OperationError";
|
||||
|
||||
/**
|
||||
* Bzip2 Decompress operation
|
||||
*/
|
||||
class Bzip2Decompress extends Operation {
|
||||
|
||||
/**
|
||||
* Bzip2Decompress constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Bzip2 Decompress";
|
||||
this.module = "Compression";
|
||||
this.description = "Decompresses data using the Bzip2 algorithm.";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
this.patterns = [
|
||||
{
|
||||
"match": "^\\x42\\x5a\\x68",
|
||||
"flags": "",
|
||||
"args": []
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const compressed = new Uint8Array(input);
|
||||
|
||||
try {
|
||||
const bzip2Reader = bzip2.array(compressed);
|
||||
return bzip2.simple(bzip2Reader);
|
||||
} catch (err) {
|
||||
throw new OperationError(err);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Bzip2Decompress;
|
40
src/core/operations/CRC16Checksum.mjs
Normal file
40
src/core/operations/CRC16Checksum.mjs
Normal file
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import JSCRC from "js-crc";
|
||||
|
||||
/**
|
||||
* CRC-16 Checksum operation
|
||||
*/
|
||||
class CRC16Checksum extends Operation {
|
||||
|
||||
/**
|
||||
* CRC16Checksum constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "CRC-16 Checksum";
|
||||
this.module = "Hashing";
|
||||
this.description = "A cyclic redundancy check (CRC) is an error-detecting code commonly used in digital networks and storage devices to detect accidental changes to raw data.<br><br>The CRC was invented by W. Wesley Peterson in 1961.";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
return JSCRC.crc16(input);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default CRC16Checksum;
|
40
src/core/operations/CRC32Checksum.mjs
Normal file
40
src/core/operations/CRC32Checksum.mjs
Normal file
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import JSCRC from "js-crc";
|
||||
|
||||
/**
|
||||
* CRC-32 Checksum operation
|
||||
*/
|
||||
class CRC32Checksum extends Operation {
|
||||
|
||||
/**
|
||||
* CRC32Checksum constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "CRC-32 Checksum";
|
||||
this.module = "Hashing";
|
||||
this.description = "A cyclic redundancy check (CRC) is an error-detecting code commonly used in digital networks and storage devices to detect accidental changes to raw data.<br><br>The CRC was invented by W. Wesley Peterson in 1961; the 32-bit CRC function of Ethernet and many other standards is the work of several researchers and was published in 1975.";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
return JSCRC.crc32(input);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default CRC32Checksum;
|
40
src/core/operations/CTPH.mjs
Normal file
40
src/core/operations/CTPH.mjs
Normal file
|
@ -0,0 +1,40 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import ctphjs from "ctph.js";
|
||||
|
||||
/**
|
||||
* CTPH operation
|
||||
*/
|
||||
class CTPH extends Operation {
|
||||
|
||||
/**
|
||||
* CTPH constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "CTPH";
|
||||
this.module = "Hashing";
|
||||
this.description = "Context Triggered Piecewise Hashing, also called Fuzzy Hashing, can match inputs that have homologies. Such inputs have sequences of identical bytes in the same order, although bytes in between these sequences may be different in both content and length.<br><br>CTPH was originally based on the work of Dr. Andrew Tridgell and a spam email detector called SpamSum. This method was adapted by Jesse Kornblum and published at the DFRWS conference in 2006 in a paper 'Identifying Almost Identical Files Using Context Triggered Piecewise Hashing'.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
return ctphjs.digest(input);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default CTPH;
|
|
@ -41,7 +41,7 @@ class CartesianProduct extends Operation {
|
|||
* Validate input length
|
||||
*
|
||||
* @param {Object[]} sets
|
||||
* @throws {Error} if fewer than 2 sets
|
||||
* @throws {OperationError} if fewer than 2 sets
|
||||
*/
|
||||
validateSampleNumbers(sets) {
|
||||
if (!sets || sets.length < 2) {
|
||||
|
|
53
src/core/operations/ChiSquare.mjs
Normal file
53
src/core/operations/ChiSquare.mjs
Normal file
|
@ -0,0 +1,53 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
|
||||
/**
|
||||
* Chi Square operation
|
||||
*/
|
||||
class ChiSquare extends Operation {
|
||||
|
||||
/**
|
||||
* ChiSquare constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Chi Square";
|
||||
this.module = "Default";
|
||||
this.description = "Calculates the Chi Square distribution of values.";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "number";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {number}
|
||||
*/
|
||||
run(input, args) {
|
||||
const data = new Uint8Array(input);
|
||||
const distArray = new Array(256).fill(0);
|
||||
let total = 0;
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
distArray[data[i]]++;
|
||||
}
|
||||
|
||||
for (let i = 0; i < distArray.length; i++) {
|
||||
if (distArray[i] > 0) {
|
||||
total += Math.pow(distArray[i] - data.length / 256, 2) / (data.length / 256);
|
||||
}
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ChiSquare;
|
48
src/core/operations/Comment.mjs
Normal file
48
src/core/operations/Comment.mjs
Normal file
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
|
||||
/**
|
||||
* Comment operation
|
||||
*/
|
||||
class Comment extends Operation {
|
||||
|
||||
/**
|
||||
* Comment constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Comment";
|
||||
this.flowControl = true;
|
||||
this.module = "Default";
|
||||
this.description = "Provides a place to write comments within the flow of the recipe. This operation has no computational effect.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "",
|
||||
"type": "text",
|
||||
"value": ""
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} state - The current state of the recipe.
|
||||
* @param {number} state.progress - The current position in the recipe.
|
||||
* @param {Dish} state.dish - The Dish being operated on.
|
||||
* @param {Operation[]} state.opList - The list of operations in the recipe.
|
||||
* @returns {Object} The updated state of the recipe.
|
||||
*/
|
||||
run(state) {
|
||||
return state;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Comment;
|
51
src/core/operations/CompareCTPHHashes.mjs
Normal file
51
src/core/operations/CompareCTPHHashes.mjs
Normal file
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import {HASH_DELIM_OPTIONS} from "../lib/Delim";
|
||||
import ctphjs from "ctph.js";
|
||||
import OperationError from "../errors/OperationError";
|
||||
|
||||
/**
|
||||
* Compare CTPH hashes operation
|
||||
*/
|
||||
class CompareCTPHHashes extends Operation {
|
||||
|
||||
/**
|
||||
* CompareCTPHHashes constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Compare CTPH hashes";
|
||||
this.module = "Hashing";
|
||||
this.description = "Compares two Context Triggered Piecewise Hashing (CTPH) fuzzy hashes to determine the similarity between them on a scale of 0 to 100.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "Number";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Delimiter",
|
||||
"type": "option",
|
||||
"value": HASH_DELIM_OPTIONS
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {Number}
|
||||
*/
|
||||
run(input, args) {
|
||||
const samples = input.split(Utils.charRep(args[0]));
|
||||
if (samples.length !== 2) throw new OperationError("Incorrect number of samples.");
|
||||
return ctphjs.similarity(samples[0], samples[1]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default CompareCTPHHashes;
|
51
src/core/operations/CompareSSDEEPHashes.mjs
Normal file
51
src/core/operations/CompareSSDEEPHashes.mjs
Normal file
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import {HASH_DELIM_OPTIONS} from "../lib/Delim";
|
||||
import ssdeepjs from "ssdeep.js";
|
||||
import OperationError from "../errors/OperationError";
|
||||
|
||||
/**
|
||||
* Compare SSDEEP hashes operation
|
||||
*/
|
||||
class CompareSSDEEPHashes extends Operation {
|
||||
|
||||
/**
|
||||
* CompareSSDEEPHashes constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Compare SSDEEP hashes";
|
||||
this.module = "Hashing";
|
||||
this.description = "Compares two SSDEEP fuzzy hashes to determine the similarity between them on a scale of 0 to 100.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "Number";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Delimiter",
|
||||
"type": "option",
|
||||
"value": HASH_DELIM_OPTIONS
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {Number}
|
||||
*/
|
||||
run(input, args) {
|
||||
const samples = input.split(Utils.charRep(args[0]));
|
||||
if (samples.length !== 2) throw new OperationError("Incorrect number of samples.");
|
||||
return ssdeepjs.similarity(samples[0], samples[1]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default CompareSSDEEPHashes;
|
84
src/core/operations/ConditionalJump.mjs
Normal file
84
src/core/operations/ConditionalJump.mjs
Normal file
|
@ -0,0 +1,84 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Dish from "../Dish";
|
||||
import { getLabelIndex } from "../lib/FlowControl";
|
||||
|
||||
/**
|
||||
* Conditional Jump operation
|
||||
*/
|
||||
class ConditionalJump extends Operation {
|
||||
|
||||
/**
|
||||
* ConditionalJump constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Conditional Jump";
|
||||
this.flowControl = true;
|
||||
this.module = "Default";
|
||||
this.description = "Conditionally jump forwards or backwards to the specified Label based on whether the data matches the specified regular expression.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Match (regex)",
|
||||
"type": "string",
|
||||
"value": ""
|
||||
},
|
||||
{
|
||||
"name": "Invert match",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
},
|
||||
{
|
||||
"name": "Label name",
|
||||
"type": "shortString",
|
||||
"value": ""
|
||||
},
|
||||
{
|
||||
"name": "Maximum jumps (if jumping backwards)",
|
||||
"type": "number",
|
||||
"value": 10
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} state - The current state of the recipe.
|
||||
* @param {number} state.progress - The current position in the recipe.
|
||||
* @param {Dish} state.dish - The Dish being operated on.
|
||||
* @param {Operation[]} state.opList - The list of operations in the recipe.
|
||||
* @param {number} state.numJumps - The number of jumps taken so far.
|
||||
* @returns {Object} The updated state of the recipe.
|
||||
*/
|
||||
async run(state) {
|
||||
const ings = state.opList[state.progress].ingValues,
|
||||
dish = state.dish,
|
||||
[regexStr, invert, label, maxJumps] = ings,
|
||||
jmpIndex = getLabelIndex(label, state);
|
||||
|
||||
if (state.numJumps >= maxJumps || jmpIndex === -1) {
|
||||
return state;
|
||||
}
|
||||
|
||||
if (regexStr !== "") {
|
||||
const str = await dish.get(Dish.STRING);
|
||||
const strMatch = str.search(regexStr) > -1;
|
||||
if (!invert && strMatch || invert && !strMatch) {
|
||||
state.progress = jmpIndex;
|
||||
state.numJumps++;
|
||||
}
|
||||
}
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ConditionalJump;
|
112
src/core/operations/ConvertArea.mjs
Normal file
112
src/core/operations/ConvertArea.mjs
Normal file
|
@ -0,0 +1,112 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
|
||||
/**
|
||||
* Convert area operation
|
||||
*/
|
||||
class ConvertArea extends Operation {
|
||||
|
||||
/**
|
||||
* ConvertArea constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Convert area";
|
||||
this.module = "Default";
|
||||
this.description = "Converts a unit of area to another format.";
|
||||
this.inputType = "BigNumber";
|
||||
this.outputType = "BigNumber";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Input units",
|
||||
"type": "option",
|
||||
"value": AREA_UNITS
|
||||
},
|
||||
{
|
||||
"name": "Output units",
|
||||
"type": "option",
|
||||
"value": AREA_UNITS
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {BigNumber} input
|
||||
* @param {Object[]} args
|
||||
* @returns {BigNumber}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [inputUnits, outputUnits] = args;
|
||||
|
||||
input = input.times(AREA_FACTOR[inputUnits]);
|
||||
return input.div(AREA_FACTOR[outputUnits]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
const AREA_UNITS = [
|
||||
"[Metric]", "Square metre (sq m)", "Square kilometre (sq km)", "Centiare (ca)", "Deciare (da)", "Are (a)", "Decare (daa)", "Hectare (ha)", "[/Metric]",
|
||||
"[Imperial]", "Square inch (sq in)", "Square foot (sq ft)", "Square yard (sq yd)", "Square mile (sq mi)", "Perch (sq per)", "Rood (ro)", "International acre (ac)", "[/Imperial]",
|
||||
"[US customary units]", "US survey acre (ac)", "US survey square mile (sq mi)", "US survey township", "[/US customary units]",
|
||||
"[Nuclear physics]", "Yoctobarn (yb)", "Zeptobarn (zb)", "Attobarn (ab)", "Femtobarn (fb)", "Picobarn (pb)", "Nanobarn (nb)", "Microbarn (μb)", "Millibarn (mb)", "Barn (b)", "Kilobarn (kb)", "Megabarn (Mb)", "Outhouse", "Shed", "Planck area", "[/Nuclear physics]",
|
||||
"[Comparisons]", "Washington D.C.", "Isle of Wight", "Wales", "Texas", "[/Comparisons]",
|
||||
];
|
||||
|
||||
const AREA_FACTOR = { // Multiples of a square metre
|
||||
// Metric
|
||||
"Square metre (sq m)": 1,
|
||||
"Square kilometre (sq km)": 1e6,
|
||||
|
||||
"Centiare (ca)": 1,
|
||||
"Deciare (da)": 10,
|
||||
"Are (a)": 100,
|
||||
"Decare (daa)": 1e3,
|
||||
"Hectare (ha)": 1e4,
|
||||
|
||||
// Imperial
|
||||
"Square inch (sq in)": 0.00064516,
|
||||
"Square foot (sq ft)": 0.09290304,
|
||||
"Square yard (sq yd)": 0.83612736,
|
||||
"Square mile (sq mi)": 2589988.110336,
|
||||
"Perch (sq per)": 42.21,
|
||||
"Rood (ro)": 1011,
|
||||
"International acre (ac)": 4046.8564224,
|
||||
|
||||
// US customary units
|
||||
"US survey acre (ac)": 4046.87261,
|
||||
"US survey square mile (sq mi)": 2589998.470305239,
|
||||
"US survey township": 93239944.9309886,
|
||||
|
||||
// Nuclear physics
|
||||
"Yoctobarn (yb)": 1e-52,
|
||||
"Zeptobarn (zb)": 1e-49,
|
||||
"Attobarn (ab)": 1e-46,
|
||||
"Femtobarn (fb)": 1e-43,
|
||||
"Picobarn (pb)": 1e-40,
|
||||
"Nanobarn (nb)": 1e-37,
|
||||
"Microbarn (μb)": 1e-34,
|
||||
"Millibarn (mb)": 1e-31,
|
||||
"Barn (b)": 1e-28,
|
||||
"Kilobarn (kb)": 1e-25,
|
||||
"Megabarn (Mb)": 1e-22,
|
||||
|
||||
"Planck area": 2.6e-70,
|
||||
"Shed": 1e-52,
|
||||
"Outhouse": 1e-34,
|
||||
|
||||
// Comparisons
|
||||
"Washington D.C.": 176119191.502848,
|
||||
"Isle of Wight": 380000000,
|
||||
"Wales": 20779000000,
|
||||
"Texas": 696241000000,
|
||||
};
|
||||
|
||||
|
||||
export default ConvertArea;
|
111
src/core/operations/ConvertDataUnits.mjs
Normal file
111
src/core/operations/ConvertDataUnits.mjs
Normal file
|
@ -0,0 +1,111 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
|
||||
/**
|
||||
* Convert data units operation
|
||||
*/
|
||||
class ConvertDataUnits extends Operation {
|
||||
|
||||
/**
|
||||
* ConvertDataUnits constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Convert data units";
|
||||
this.module = "Default";
|
||||
this.description = "Converts a unit of data to another format.";
|
||||
this.inputType = "BigNumber";
|
||||
this.outputType = "BigNumber";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Input units",
|
||||
"type": "option",
|
||||
"value": DATA_UNITS
|
||||
},
|
||||
{
|
||||
"name": "Output units",
|
||||
"type": "option",
|
||||
"value": DATA_UNITS
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {BigNumber} input
|
||||
* @param {Object[]} args
|
||||
* @returns {BigNumber}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [inputUnits, outputUnits] = args;
|
||||
|
||||
input = input.times(DATA_FACTOR[inputUnits]);
|
||||
return input.div(DATA_FACTOR[outputUnits]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const DATA_UNITS = [
|
||||
"Bits (b)", "Nibbles", "Octets", "Bytes (B)",
|
||||
"[Binary bits (2^n)]", "Kibibits (Kib)", "Mebibits (Mib)", "Gibibits (Gib)", "Tebibits (Tib)", "Pebibits (Pib)", "Exbibits (Eib)", "Zebibits (Zib)", "Yobibits (Yib)", "[/Binary bits (2^n)]",
|
||||
"[Decimal bits (10^n)]", "Decabits", "Hectobits", "Kilobits (kb)", "Megabits (Mb)", "Gigabits (Gb)", "Terabits (Tb)", "Petabits (Pb)", "Exabits (Eb)", "Zettabits (Zb)", "Yottabits (Yb)", "[/Decimal bits (10^n)]",
|
||||
"[Binary bytes (8 x 2^n)]", "Kibibytes (KiB)", "Mebibytes (MiB)", "Gibibytes (GiB)", "Tebibytes (TiB)", "Pebibytes (PiB)", "Exbibytes (EiB)", "Zebibytes (ZiB)", "Yobibytes (YiB)", "[/Binary bytes (8 x 2^n)]",
|
||||
"[Decimal bytes (8 x 10^n)]", "Kilobytes (KB)", "Megabytes (MB)", "Gigabytes (GB)", "Terabytes (TB)", "Petabytes (PB)", "Exabytes (EB)", "Zettabytes (ZB)", "Yottabytes (YB)", "[/Decimal bytes (8 x 10^n)]"
|
||||
];
|
||||
|
||||
const DATA_FACTOR = { // Multiples of a bit
|
||||
"Bits (b)": 1,
|
||||
"Nibbles": 4,
|
||||
"Octets": 8,
|
||||
"Bytes (B)": 8,
|
||||
|
||||
// Binary bits (2^n)
|
||||
"Kibibits (Kib)": 1024,
|
||||
"Mebibits (Mib)": 1048576,
|
||||
"Gibibits (Gib)": 1073741824,
|
||||
"Tebibits (Tib)": 1099511627776,
|
||||
"Pebibits (Pib)": 1125899906842624,
|
||||
"Exbibits (Eib)": 1152921504606846976,
|
||||
"Zebibits (Zib)": 1180591620717411303424,
|
||||
"Yobibits (Yib)": 1208925819614629174706176,
|
||||
|
||||
// Decimal bits (10^n)
|
||||
"Decabits": 10,
|
||||
"Hectobits": 100,
|
||||
"Kilobits (Kb)": 1e3,
|
||||
"Megabits (Mb)": 1e6,
|
||||
"Gigabits (Gb)": 1e9,
|
||||
"Terabits (Tb)": 1e12,
|
||||
"Petabits (Pb)": 1e15,
|
||||
"Exabits (Eb)": 1e18,
|
||||
"Zettabits (Zb)": 1e21,
|
||||
"Yottabits (Yb)": 1e24,
|
||||
|
||||
// Binary bytes (8 x 2^n)
|
||||
"Kibibytes (KiB)": 8192,
|
||||
"Mebibytes (MiB)": 8388608,
|
||||
"Gibibytes (GiB)": 8589934592,
|
||||
"Tebibytes (TiB)": 8796093022208,
|
||||
"Pebibytes (PiB)": 9007199254740992,
|
||||
"Exbibytes (EiB)": 9223372036854775808,
|
||||
"Zebibytes (ZiB)": 9444732965739290427392,
|
||||
"Yobibytes (YiB)": 9671406556917033397649408,
|
||||
|
||||
// Decimal bytes (8 x 10^n)
|
||||
"Kilobytes (KB)": 8e3,
|
||||
"Megabytes (MB)": 8e6,
|
||||
"Gigabytes (GB)": 8e9,
|
||||
"Terabytes (TB)": 8e12,
|
||||
"Petabytes (PB)": 8e15,
|
||||
"Exabytes (EB)": 8e18,
|
||||
"Zettabytes (ZB)": 8e21,
|
||||
"Yottabytes (YB)": 8e24,
|
||||
};
|
||||
|
||||
|
||||
export default ConvertDataUnits;
|
95
src/core/operations/ConvertDistance.mjs
Normal file
95
src/core/operations/ConvertDistance.mjs
Normal file
|
@ -0,0 +1,95 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
|
||||
/**
|
||||
* Convert distance operation
|
||||
*/
|
||||
class ConvertDistance extends Operation {
|
||||
|
||||
/**
|
||||
* ConvertDistance constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Convert distance";
|
||||
this.module = "Default";
|
||||
this.description = "Converts a unit of distance to another format.";
|
||||
this.inputType = "BigNumber";
|
||||
this.outputType = "BigNumber";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Input units",
|
||||
"type": "option",
|
||||
"value": DISTANCE_UNITS
|
||||
},
|
||||
{
|
||||
"name": "Output units",
|
||||
"type": "option",
|
||||
"value": DISTANCE_UNITS
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {BigNumber} input
|
||||
* @param {Object[]} args
|
||||
* @returns {BigNumber}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [inputUnits, outputUnits] = args;
|
||||
|
||||
input = input.times(DISTANCE_FACTOR[inputUnits]);
|
||||
return input.div(DISTANCE_FACTOR[outputUnits]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const DISTANCE_UNITS = [
|
||||
"[Metric]", "Nanometres (nm)", "Micrometres (µm)", "Millimetres (mm)", "Centimetres (cm)", "Metres (m)", "Kilometers (km)", "[/Metric]",
|
||||
"[Imperial]", "Thou (th)", "Inches (in)", "Feet (ft)", "Yards (yd)", "Chains (ch)", "Furlongs (fur)", "Miles (mi)", "Leagues (lea)", "[/Imperial]",
|
||||
"[Maritime]", "Fathoms (ftm)", "Cables", "Nautical miles", "[/Maritime]",
|
||||
"[Comparisons]", "Cars (4m)", "Buses (8.4m)", "American football fields (91m)", "Football pitches (105m)", "[/Comparisons]",
|
||||
"[Astronomical]", "Earth-to-Moons", "Earth's equators", "Astronomical units (au)", "Light-years (ly)", "Parsecs (pc)", "[/Astronomical]",
|
||||
];
|
||||
|
||||
const DISTANCE_FACTOR = { // Multiples of a metre
|
||||
"Nanometres (nm)": 1e-9,
|
||||
"Micrometres (µm)": 1e-6,
|
||||
"Millimetres (mm)": 1e-3,
|
||||
"Centimetres (cm)": 1e-2,
|
||||
"Metres (m)": 1,
|
||||
"Kilometers (km)": 1e3,
|
||||
|
||||
"Thou (th)": 0.0000254,
|
||||
"Inches (in)": 0.0254,
|
||||
"Feet (ft)": 0.3048,
|
||||
"Yards (yd)": 0.9144,
|
||||
"Chains (ch)": 20.1168,
|
||||
"Furlongs (fur)": 201.168,
|
||||
"Miles (mi)": 1609.344,
|
||||
"Leagues (lea)": 4828.032,
|
||||
|
||||
"Fathoms (ftm)": 1.853184,
|
||||
"Cables": 185.3184,
|
||||
"Nautical miles": 1853.184,
|
||||
|
||||
"Cars (4m)": 4,
|
||||
"Buses (8.4m)": 8.4,
|
||||
"American football fields (91m)": 91,
|
||||
"Football pitches (105m)": 105,
|
||||
|
||||
"Earth-to-Moons": 380000000,
|
||||
"Earth's equators": 40075016.686,
|
||||
"Astronomical units (au)": 149597870700,
|
||||
"Light-years (ly)": 9460730472580800,
|
||||
"Parsecs (pc)": 3.0856776e16
|
||||
};
|
||||
|
||||
|
||||
export default ConvertDistance;
|
143
src/core/operations/ConvertMass.mjs
Normal file
143
src/core/operations/ConvertMass.mjs
Normal file
|
@ -0,0 +1,143 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
|
||||
/**
|
||||
* Convert mass operation
|
||||
*/
|
||||
class ConvertMass extends Operation {
|
||||
|
||||
/**
|
||||
* ConvertMass constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Convert mass";
|
||||
this.module = "Default";
|
||||
this.description = "Converts a unit of mass to another format.";
|
||||
this.inputType = "BigNumber";
|
||||
this.outputType = "BigNumber";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Input units",
|
||||
"type": "option",
|
||||
"value": MASS_UNITS
|
||||
},
|
||||
{
|
||||
"name": "Output units",
|
||||
"type": "option",
|
||||
"value": MASS_UNITS
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {BigNumber} input
|
||||
* @param {Object[]} args
|
||||
* @returns {BigNumber}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [inputUnits, outputUnits] = args;
|
||||
|
||||
input = input.times(MASS_FACTOR[inputUnits]);
|
||||
return input.div(MASS_FACTOR[outputUnits]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
const MASS_UNITS = [
|
||||
"[Metric]", "Yoctogram (yg)", "Zeptogram (zg)", "Attogram (ag)", "Femtogram (fg)", "Picogram (pg)", "Nanogram (ng)", "Microgram (μg)", "Milligram (mg)", "Centigram (cg)", "Decigram (dg)", "Gram (g)", "Decagram (dag)", "Hectogram (hg)", "Kilogram (kg)", "Megagram (Mg)", "Tonne (t)", "Gigagram (Gg)", "Teragram (Tg)", "Petagram (Pg)", "Exagram (Eg)", "Zettagram (Zg)", "Yottagram (Yg)", "[/Metric]",
|
||||
"[Imperial Avoirdupois]", "Grain (gr)", "Dram (dr)", "Ounce (oz)", "Pound (lb)", "Nail", "Stone (st)", "Quarter (gr)", "Tod", "US hundredweight (cwt)", "Imperial hundredweight (cwt)", "US ton (t)", "Imperial ton (t)", "[/Imperial Avoirdupois]",
|
||||
"[Imperial Troy]", "Grain (gr)", "Pennyweight (dwt)", "Troy dram (dr t)", "Troy ounce (oz t)", "Troy pound (lb t)", "Mark", "[/Imperial Troy]",
|
||||
"[Archaic]", "Wey", "Wool wey", "Suffolk wey", "Wool sack", "Coal sack", "Load", "Last", "Flax or feather last", "Gunpowder last", "Picul", "Rice last", "[/Archaic]",
|
||||
"[Comparisons]", "Big Ben (14 tonnes)", "Blue whale (180 tonnes)", "International Space Station (417 tonnes)", "Space Shuttle (2,041 tonnes)", "RMS Titanic (52,000 tonnes)", "Great Pyramid of Giza (6,000,000 tonnes)", "Earth's oceans (1.4 yottagrams)", "[/Comparisons]",
|
||||
"[Astronomical]", "A teaspoon of neutron star (5,500 million tonnes)", "Lunar mass (ML)", "Earth mass (M⊕)", "Jupiter mass (MJ)", "Solar mass (M☉)", "Sagittarius A* (7.5 x 10^36 kgs-ish)", "Milky Way galaxy (1.2 x 10^42 kgs)", "The observable universe (1.45 x 10^53 kgs)", "[/Astronomical]",
|
||||
];
|
||||
|
||||
const MASS_FACTOR = { // Multiples of a gram
|
||||
// Metric
|
||||
"Yoctogram (yg)": 1e-24,
|
||||
"Zeptogram (zg)": 1e-21,
|
||||
"Attogram (ag)": 1e-18,
|
||||
"Femtogram (fg)": 1e-15,
|
||||
"Picogram (pg)": 1e-12,
|
||||
"Nanogram (ng)": 1e-9,
|
||||
"Microgram (μg)": 1e-6,
|
||||
"Milligram (mg)": 1e-3,
|
||||
"Centigram (cg)": 1e-2,
|
||||
"Decigram (dg)": 1e-1,
|
||||
"Gram (g)": 1,
|
||||
"Decagram (dag)": 10,
|
||||
"Hectogram (hg)": 100,
|
||||
"Kilogram (kg)": 1000,
|
||||
"Megagram (Mg)": 1e6,
|
||||
"Tonne (t)": 1e6,
|
||||
"Gigagram (Gg)": 1e9,
|
||||
"Teragram (Tg)": 1e12,
|
||||
"Petagram (Pg)": 1e15,
|
||||
"Exagram (Eg)": 1e18,
|
||||
"Zettagram (Zg)": 1e21,
|
||||
"Yottagram (Yg)": 1e24,
|
||||
|
||||
// Imperial Avoirdupois
|
||||
"Grain (gr)": 64.79891e-3,
|
||||
"Dram (dr)": 1.7718451953125,
|
||||
"Ounce (oz)": 28.349523125,
|
||||
"Pound (lb)": 453.59237,
|
||||
"Nail": 3175.14659,
|
||||
"Stone (st)": 6.35029318e3,
|
||||
"Quarter (gr)": 12700.58636,
|
||||
"Tod": 12700.58636,
|
||||
"US hundredweight (cwt)": 45.359237e3,
|
||||
"Imperial hundredweight (cwt)": 50.80234544e3,
|
||||
"US ton (t)": 907.18474e3,
|
||||
"Imperial ton (t)": 1016.0469088e3,
|
||||
|
||||
// Imperial Troy
|
||||
"Pennyweight (dwt)": 1.55517384,
|
||||
"Troy dram (dr t)": 3.8879346,
|
||||
"Troy ounce (oz t)": 31.1034768,
|
||||
"Troy pound (lb t)": 373.2417216,
|
||||
"Mark": 248.8278144,
|
||||
|
||||
// Archaic
|
||||
"Wey": 76.5e3,
|
||||
"Wool wey": 101.7e3,
|
||||
"Suffolk wey": 161.5e3,
|
||||
"Wool sack": 153000,
|
||||
"Coal sack": 50.80234544e3,
|
||||
"Load": 918000,
|
||||
"Last": 1836000,
|
||||
"Flax or feather last": 770e3,
|
||||
"Gunpowder last": 1090e3,
|
||||
"Picul": 60.478982e3,
|
||||
"Rice last": 1200e3,
|
||||
|
||||
// Comparisons
|
||||
"Big Ben (14 tonnes)": 14e6,
|
||||
"Blue whale (180 tonnes)": 180e6,
|
||||
"International Space Station (417 tonnes)": 417e6,
|
||||
"Space Shuttle (2,041 tonnes)": 2041e6,
|
||||
"RMS Titanic (52,000 tonnes)": 52000e6,
|
||||
"Great Pyramid of Giza (6,000,000 tonnes)": 6e12,
|
||||
"Earth's oceans (1.4 yottagrams)": 1.4e24,
|
||||
|
||||
// Astronomical
|
||||
"A teaspoon of neutron star (5,500 million tonnes)": 5.5e15,
|
||||
"Lunar mass (ML)": 7.342e25,
|
||||
"Earth mass (M⊕)": 5.97219e27,
|
||||
"Jupiter mass (MJ)": 1.8981411476999997e30,
|
||||
"Solar mass (M☉)": 1.98855e33,
|
||||
"Sagittarius A* (7.5 x 10^36 kgs-ish)": 7.5e39,
|
||||
"Milky Way galaxy (1.2 x 10^42 kgs)": 1.2e45,
|
||||
"The observable universe (1.45 x 10^53 kgs)": 1.45e56,
|
||||
};
|
||||
|
||||
|
||||
export default ConvertMass;
|
96
src/core/operations/ConvertSpeed.mjs
Normal file
96
src/core/operations/ConvertSpeed.mjs
Normal file
|
@ -0,0 +1,96 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
|
||||
/**
|
||||
* Convert speed operation
|
||||
*/
|
||||
class ConvertSpeed extends Operation {
|
||||
|
||||
/**
|
||||
* ConvertSpeed constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Convert speed";
|
||||
this.module = "Default";
|
||||
this.description = "Converts a unit of speed to another format.";
|
||||
this.inputType = "BigNumber";
|
||||
this.outputType = "BigNumber";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Input units",
|
||||
"type": "option",
|
||||
"value": SPEED_UNITS
|
||||
},
|
||||
{
|
||||
"name": "Output units",
|
||||
"type": "option",
|
||||
"value": SPEED_UNITS
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {BigNumber} input
|
||||
* @param {Object[]} args
|
||||
* @returns {BigNumber}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [inputUnits, outputUnits] = args;
|
||||
|
||||
input = input.times(SPEED_FACTOR[inputUnits]);
|
||||
return input.div(SPEED_FACTOR[outputUnits]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const SPEED_UNITS = [
|
||||
"[Metric]", "Metres per second (m/s)", "Kilometres per hour (km/h)", "[/Metric]",
|
||||
"[Imperial]", "Miles per hour (mph)", "Knots (kn)", "[/Imperial]",
|
||||
"[Comparisons]", "Human hair growth rate", "Bamboo growth rate", "World's fastest snail", "Usain Bolt's top speed", "Jet airliner cruising speed", "Concorde", "SR-71 Blackbird", "Space Shuttle", "International Space Station", "[/Comparisons]",
|
||||
"[Scientific]", "Sound in standard atmosphere", "Sound in water", "Lunar escape velocity", "Earth escape velocity", "Earth's solar orbit", "Solar system's Milky Way orbit", "Milky Way relative to the cosmic microwave background", "Solar escape velocity", "Neutron star escape velocity (0.3c)", "Light in a diamond (0.4136c)", "Signal in an optical fibre (0.667c)", "Light (c)", "[/Scientific]",
|
||||
];
|
||||
|
||||
const SPEED_FACTOR = { // Multiples of m/s
|
||||
// Metric
|
||||
"Metres per second (m/s)": 1,
|
||||
"Kilometres per hour (km/h)": 0.2778,
|
||||
|
||||
// Imperial
|
||||
"Miles per hour (mph)": 0.44704,
|
||||
"Knots (kn)": 0.5144,
|
||||
|
||||
// Comparisons
|
||||
"Human hair growth rate": 4.8e-9,
|
||||
"Bamboo growth rate": 1.4e-5,
|
||||
"World's fastest snail": 0.00275,
|
||||
"Usain Bolt's top speed": 12.42,
|
||||
"Jet airliner cruising speed": 250,
|
||||
"Concorde": 603,
|
||||
"SR-71 Blackbird": 981,
|
||||
"Space Shuttle": 1400,
|
||||
"International Space Station": 7700,
|
||||
|
||||
// Scientific
|
||||
"Sound in standard atmosphere": 340.3,
|
||||
"Sound in water": 1500,
|
||||
"Lunar escape velocity": 2375,
|
||||
"Earth escape velocity": 11200,
|
||||
"Earth's solar orbit": 29800,
|
||||
"Solar system's Milky Way orbit": 200000,
|
||||
"Milky Way relative to the cosmic microwave background": 552000,
|
||||
"Solar escape velocity": 617700,
|
||||
"Neutron star escape velocity (0.3c)": 100000000,
|
||||
"Light in a diamond (0.4136c)": 124000000,
|
||||
"Signal in an optical fibre (0.667c)": 200000000,
|
||||
"Light (c)": 299792458,
|
||||
};
|
||||
|
||||
|
||||
export default ConvertSpeed;
|
65
src/core/operations/CountOccurrences.mjs
Normal file
65
src/core/operations/CountOccurrences.mjs
Normal file
|
@ -0,0 +1,65 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
|
||||
/**
|
||||
* Count occurrences operation
|
||||
*/
|
||||
class CountOccurrences extends Operation {
|
||||
|
||||
/**
|
||||
* CountOccurrences constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Count occurrences";
|
||||
this.module = "Default";
|
||||
this.description = "Counts the number of times the provided string occurs in the input.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "number";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Search string",
|
||||
"type": "toggleString",
|
||||
"value": "",
|
||||
"toggleValues": ["Regex", "Extended (\\n, \\t, \\x...)", "Simple string"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {number}
|
||||
*/
|
||||
run(input, args) {
|
||||
let search = args[0].string;
|
||||
const type = args[0].option;
|
||||
|
||||
if (type === "Regex" && search) {
|
||||
try {
|
||||
const regex = new RegExp(search, "gi"),
|
||||
matches = input.match(regex);
|
||||
return matches.length;
|
||||
} catch (err) {
|
||||
return 0;
|
||||
}
|
||||
} else if (search) {
|
||||
if (type.indexOf("Extended") === 0) {
|
||||
search = Utils.parseEscapedChars(search);
|
||||
}
|
||||
return input.count(search);
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default CountOccurrences;
|
59
src/core/operations/DecodeNetBIOSName.mjs
Normal file
59
src/core/operations/DecodeNetBIOSName.mjs
Normal file
|
@ -0,0 +1,59 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
|
||||
/**
|
||||
* Decode NetBIOS Name operation
|
||||
*/
|
||||
class DecodeNetBIOSName extends Operation {
|
||||
|
||||
/**
|
||||
* DecodeNetBIOSName constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Decode NetBIOS Name";
|
||||
this.module = "Default";
|
||||
this.description = "NetBIOS names as seen across the client interface to NetBIOS are exactly 16 bytes long. Within the NetBIOS-over-TCP protocols, a longer representation is used.<br><br>There are two levels of encoding. The first level maps a NetBIOS name into a domain system name. The second level maps the domain system name into the 'compressed' representation required for interaction with the domain name system.<br><br>This operation decodes the first level of encoding. See RFC 1001 for full details.";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "byteArray";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Offset",
|
||||
"type": "number",
|
||||
"value": 65
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
run(input, args) {
|
||||
const output = [],
|
||||
offset = args[0];
|
||||
|
||||
if (input.length <= 32 && (input.length % 2) === 0) {
|
||||
for (let i = 0; i < input.length; i += 2) {
|
||||
output.push((((input[i] & 0xff) - offset) << 4) |
|
||||
(((input[i + 1] & 0xff) - offset) & 0xf));
|
||||
}
|
||||
for (let i = output.length - 1; i > 0; i--) {
|
||||
if (output[i] === 32) output.splice(i, i);
|
||||
else break;
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default DecodeNetBIOSName;
|
55
src/core/operations/DecodeText.mjs
Normal file
55
src/core/operations/DecodeText.mjs
Normal file
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import cptable from "../vendor/js-codepage/cptable.js";
|
||||
import {IO_FORMAT} from "../lib/ChrEnc";
|
||||
|
||||
/**
|
||||
* Decode text operation
|
||||
*/
|
||||
class DecodeText extends Operation {
|
||||
|
||||
/**
|
||||
* DecodeText constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Decode text";
|
||||
this.module = "CharEnc";
|
||||
this.description = [
|
||||
"Decodes text from the chosen character encoding.",
|
||||
"<br><br>",
|
||||
"Supported charsets are:",
|
||||
"<ul>",
|
||||
Object.keys(IO_FORMAT).map(e => `<li>${e}</li>`).join("\n"),
|
||||
"</ul>",
|
||||
].join("\n");
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Encoding",
|
||||
"type": "option",
|
||||
"value": Object.keys(IO_FORMAT)
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const format = IO_FORMAT[args[0]];
|
||||
return cptable.utils.decode(format, input);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default DecodeText;
|
144
src/core/operations/DeriveEVPKey.mjs
Normal file
144
src/core/operations/DeriveEVPKey.mjs
Normal file
|
@ -0,0 +1,144 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import CryptoJS from "crypto-js";
|
||||
|
||||
/**
|
||||
* Derive EVP key operation
|
||||
*/
|
||||
class DeriveEVPKey extends Operation {
|
||||
|
||||
/**
|
||||
* DeriveEVPKey constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Derive EVP key";
|
||||
this.module = "Ciphers";
|
||||
this.description = "EVP is a password-based key derivation function (PBKDF) used extensively in OpenSSL. In many applications of cryptography, user security is ultimately dependent on a password, and because a password usually can't be used directly as a cryptographic key, some processing is required.<br><br>A salt provides a large set of keys for any given password, and an iteration count increases the cost of producing keys from a password, thereby also increasing the difficulty of attack.<br><br>If you leave the salt argument empty, a random salt will be generated.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Passphrase",
|
||||
"type": "toggleString",
|
||||
"value": "",
|
||||
"toggleValues": ["UTF8", "Latin1", "Hex", "Base64"]
|
||||
},
|
||||
{
|
||||
"name": "Key size",
|
||||
"type": "number",
|
||||
"value": 128
|
||||
},
|
||||
{
|
||||
"name": "Iterations",
|
||||
"type": "number",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"name": "Hashing function",
|
||||
"type": "option",
|
||||
"value": ["SHA1", "SHA256", "SHA384", "SHA512", "MD5"]
|
||||
},
|
||||
{
|
||||
"name": "Salt",
|
||||
"type": "toggleString",
|
||||
"value": "",
|
||||
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const passphrase = Utils.convertToByteString(args[0].string, args[0].option),
|
||||
keySize = args[1] / 32,
|
||||
iterations = args[2],
|
||||
hasher = args[3],
|
||||
salt = Utils.convertToByteString(args[4].string, args[4].option),
|
||||
key = CryptoJS.EvpKDF(passphrase, salt, {
|
||||
keySize: keySize,
|
||||
hasher: CryptoJS.algo[hasher],
|
||||
iterations: iterations,
|
||||
});
|
||||
|
||||
return key.toString(CryptoJS.enc.Hex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default DeriveEVPKey;
|
||||
|
||||
/**
|
||||
* Overwriting the CryptoJS OpenSSL key derivation function so that it is possible to not pass a
|
||||
* salt in.
|
||||
|
||||
* @param {string} password - The password to derive from.
|
||||
* @param {number} keySize - The size in words of the key to generate.
|
||||
* @param {number} ivSize - The size in words of the IV to generate.
|
||||
* @param {WordArray|string} salt (Optional) A 64-bit salt to use. If omitted, a salt will be
|
||||
* generated randomly. If set to false, no salt will be added.
|
||||
*
|
||||
* @returns {CipherParams} A cipher params object with the key, IV, and salt.
|
||||
*
|
||||
* @static
|
||||
*
|
||||
* @example
|
||||
* // Randomly generates a salt
|
||||
* var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32);
|
||||
* // Uses the salt 'saltsalt'
|
||||
* var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32, 'saltsalt');
|
||||
* // Does not use a salt
|
||||
* var derivedParams = CryptoJS.kdf.OpenSSL.execute('Password', 256/32, 128/32, false);
|
||||
*/
|
||||
CryptoJS.kdf.OpenSSL.execute = function (password, keySize, ivSize, salt) {
|
||||
// Generate random salt if no salt specified and not set to false
|
||||
// This line changed from `if (!salt) {` to the following
|
||||
if (salt === undefined || salt === null) {
|
||||
salt = CryptoJS.lib.WordArray.random(64/8);
|
||||
}
|
||||
|
||||
// Derive key and IV
|
||||
const key = CryptoJS.algo.EvpKDF.create({ keySize: keySize + ivSize }).compute(password, salt);
|
||||
|
||||
// Separate key and IV
|
||||
const iv = CryptoJS.lib.WordArray.create(key.words.slice(keySize), ivSize * 4);
|
||||
key.sigBytes = keySize * 4;
|
||||
|
||||
// Return params
|
||||
return CryptoJS.lib.CipherParams.create({ key: key, iv: iv, salt: salt });
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Override for the CryptoJS Hex encoding parser to remove whitespace before attempting to parse
|
||||
* the hex string.
|
||||
*
|
||||
* @param {string} hexStr
|
||||
* @returns {CryptoJS.lib.WordArray}
|
||||
*/
|
||||
CryptoJS.enc.Hex.parse = function (hexStr) {
|
||||
// Remove whitespace
|
||||
hexStr = hexStr.replace(/\s/g, "");
|
||||
|
||||
// Shortcut
|
||||
const hexStrLength = hexStr.length;
|
||||
|
||||
// Convert
|
||||
const words = [];
|
||||
for (let i = 0; i < hexStrLength; i += 2) {
|
||||
words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4);
|
||||
}
|
||||
|
||||
return new CryptoJS.lib.WordArray.init(words, hexStrLength / 2);
|
||||
};
|
54
src/core/operations/DetectFileType.mjs
Normal file
54
src/core/operations/DetectFileType.mjs
Normal file
|
@ -0,0 +1,54 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Magic from "../lib/Magic";
|
||||
|
||||
/**
|
||||
* Detect File Type operation
|
||||
*/
|
||||
class DetectFileType extends Operation {
|
||||
|
||||
/**
|
||||
* DetectFileType constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Detect File Type";
|
||||
this.module = "Default";
|
||||
this.description = "Attempts to guess the MIME (Multipurpose Internet Mail Extensions) type of the data based on 'magic bytes'.<br><br>Currently supports the following file types: 7z, amr, avi, bmp, bz2, class, cr2, crx, dex, dmg, doc, elf, eot, epub, exe, flac, flv, gif, gz, ico, iso, jpg, jxr, m4a, m4v, mid, mkv, mov, mp3, mp4, mpg, ogg, otf, pdf, png, ppt, ps, psd, rar, rtf, sqlite, swf, tar, tar.z, tif, ttf, utf8, vmdk, wav, webm, webp, wmv, woff, woff2, xls, xz, zip.";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const data = new Uint8Array(input),
|
||||
type = Magic.magicFileType(data);
|
||||
|
||||
if (!type) {
|
||||
return "Unknown file type. Have you tried checking the entropy of this data to determine whether it might be encrypted or compressed?";
|
||||
} else {
|
||||
let output = "File extension: " + type.ext + "\n" +
|
||||
"MIME type: " + type.mime;
|
||||
|
||||
if (type.desc && type.desc.length) {
|
||||
output += "\nDescription: " + type.desc;
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default DetectFileType;
|
124
src/core/operations/Diff.mjs
Normal file
124
src/core/operations/Diff.mjs
Normal file
|
@ -0,0 +1,124 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import * as JsDiff from "diff";
|
||||
import OperationError from "../errors/OperationError";
|
||||
|
||||
/**
|
||||
* Diff operation
|
||||
*/
|
||||
class Diff extends Operation {
|
||||
|
||||
/**
|
||||
* Diff constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Diff";
|
||||
this.module = "Diff";
|
||||
this.description = "Compares two inputs (separated by the specified delimiter) and highlights the differences between them.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "html";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Sample delimiter",
|
||||
"type": "binaryString",
|
||||
"value": "\\n\\n"
|
||||
},
|
||||
{
|
||||
"name": "Diff by",
|
||||
"type": "option",
|
||||
"value": ["Character", "Word", "Line", "Sentence", "CSS", "JSON"]
|
||||
},
|
||||
{
|
||||
"name": "Show added",
|
||||
"type": "boolean",
|
||||
"value": true
|
||||
},
|
||||
{
|
||||
"name": "Show removed",
|
||||
"type": "boolean",
|
||||
"value": true
|
||||
},
|
||||
{
|
||||
"name": "Ignore whitespace (relevant for word and line)",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {html}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [
|
||||
sampleDelim,
|
||||
diffBy,
|
||||
showAdded,
|
||||
showRemoved,
|
||||
ignoreWhitespace
|
||||
] = args,
|
||||
samples = input.split(sampleDelim);
|
||||
let output = "",
|
||||
diff;
|
||||
|
||||
if (!samples || samples.length !== 2) {
|
||||
throw new OperationError("Incorrect number of samples, perhaps you need to modify the sample delimiter or add more samples?");
|
||||
}
|
||||
|
||||
switch (diffBy) {
|
||||
case "Character":
|
||||
diff = JsDiff.diffChars(samples[0], samples[1]);
|
||||
break;
|
||||
case "Word":
|
||||
if (ignoreWhitespace) {
|
||||
diff = JsDiff.diffWords(samples[0], samples[1]);
|
||||
} else {
|
||||
diff = JsDiff.diffWordsWithSpace(samples[0], samples[1]);
|
||||
}
|
||||
break;
|
||||
case "Line":
|
||||
if (ignoreWhitespace) {
|
||||
diff = JsDiff.diffTrimmedLines(samples[0], samples[1]);
|
||||
} else {
|
||||
diff = JsDiff.diffLines(samples[0], samples[1]);
|
||||
}
|
||||
break;
|
||||
case "Sentence":
|
||||
diff = JsDiff.diffSentences(samples[0], samples[1]);
|
||||
break;
|
||||
case "CSS":
|
||||
diff = JsDiff.diffCss(samples[0], samples[1]);
|
||||
break;
|
||||
case "JSON":
|
||||
diff = JsDiff.diffJson(samples[0], samples[1]);
|
||||
break;
|
||||
default:
|
||||
throw new OperationError("Invalid 'Diff by' option.");
|
||||
}
|
||||
|
||||
for (let i = 0; i < diff.length; i++) {
|
||||
if (diff[i].added) {
|
||||
if (showAdded) output += "<span class='hl5'>" + Utils.escapeHtml(diff[i].value) + "</span>";
|
||||
} else if (diff[i].removed) {
|
||||
if (showRemoved) output += "<span class='hl3'>" + Utils.escapeHtml(diff[i].value) + "</span>";
|
||||
} else {
|
||||
output += Utils.escapeHtml(diff[i].value);
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Diff;
|
133
src/core/operations/DisassembleX86.mjs
Normal file
133
src/core/operations/DisassembleX86.mjs
Normal file
|
@ -0,0 +1,133 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import * as disassemble from "../vendor/DisassembleX86-64";
|
||||
import OperationError from "../errors/OperationError";
|
||||
|
||||
/**
|
||||
* Disassemble x86 operation
|
||||
*/
|
||||
class DisassembleX86 extends Operation {
|
||||
|
||||
/**
|
||||
* DisassembleX86 constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Disassemble x86";
|
||||
this.module = "Shellcode";
|
||||
this.description = "Disassembly is the process of translating machine language into assembly language.<br><br>This operation supports 64-bit, 32-bit and 16-bit code written for Intel or AMD x86 processors. It is particularly useful for reverse engineering shellcode.<br><br>Input should be in hexadecimal.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Bit mode",
|
||||
"type": "option",
|
||||
"value": ["64", "32", "16"]
|
||||
},
|
||||
{
|
||||
"name": "Compatibility",
|
||||
"type": "option",
|
||||
"value": [
|
||||
"Full x86 architecture",
|
||||
"Knights Corner",
|
||||
"Larrabee",
|
||||
"Cyrix",
|
||||
"Geode",
|
||||
"Centaur",
|
||||
"X86/486"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Code Segment (CS)",
|
||||
"type": "number",
|
||||
"value": 16
|
||||
},
|
||||
{
|
||||
"name": "Offset (IP)",
|
||||
"type": "number",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"name": "Show instruction hex",
|
||||
"type": "boolean",
|
||||
"value": true
|
||||
},
|
||||
{
|
||||
"name": "Show instruction position",
|
||||
"type": "boolean",
|
||||
"value": true
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*
|
||||
* @throws {OperationError} if invalid mode value
|
||||
*/
|
||||
run(input, args) {
|
||||
const [
|
||||
mode,
|
||||
compatibility,
|
||||
codeSegment,
|
||||
offset,
|
||||
showInstructionHex,
|
||||
showInstructionPos
|
||||
] = args;
|
||||
|
||||
switch (mode) {
|
||||
case "64":
|
||||
disassemble.setBitMode(2);
|
||||
break;
|
||||
case "32":
|
||||
disassemble.setBitMode(1);
|
||||
break;
|
||||
case "16":
|
||||
disassemble.setBitMode(0);
|
||||
break;
|
||||
default:
|
||||
throw new OperationError("Invalid mode value");
|
||||
}
|
||||
|
||||
switch (compatibility) {
|
||||
case "Full x86 architecture":
|
||||
disassemble.CompatibilityMode(0);
|
||||
break;
|
||||
case "Knights Corner":
|
||||
disassemble.CompatibilityMode(1);
|
||||
break;
|
||||
case "Larrabee":
|
||||
disassemble.CompatibilityMode(2);
|
||||
break;
|
||||
case "Cyrix":
|
||||
disassemble.CompatibilityMode(3);
|
||||
break;
|
||||
case "Geode":
|
||||
disassemble.CompatibilityMode(4);
|
||||
break;
|
||||
case "Centaur":
|
||||
disassemble.CompatibilityMode(5);
|
||||
break;
|
||||
case "X86/486":
|
||||
disassemble.CompatibilityMode(6);
|
||||
break;
|
||||
}
|
||||
|
||||
disassemble.SetBasePosition(codeSegment + ":" + offset);
|
||||
disassemble.setShowInstructionHex(showInstructionHex);
|
||||
disassemble.setShowInstructionPos(showInstructionPos);
|
||||
disassemble.LoadBinCode(input.replace(/\s/g, ""));
|
||||
return disassemble.LDisassemble();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default DisassembleX86;
|
51
src/core/operations/Divide.mjs
Normal file
51
src/core/operations/Divide.mjs
Normal file
|
@ -0,0 +1,51 @@
|
|||
/**
|
||||
* @author bwhitn [brian.m.whitney@outlook.com]
|
||||
* @author d98762625 [d98762625@gmail.com]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import BigNumber from "bignumber.js";
|
||||
import Operation from "../Operation";
|
||||
import { div, createNumArray } from "../lib/Arithmetic";
|
||||
import { ARITHMETIC_DELIM_OPTIONS } from "../lib/Delim";
|
||||
|
||||
|
||||
/**
|
||||
* Divide operation
|
||||
*/
|
||||
class Divide extends Operation {
|
||||
|
||||
/**
|
||||
* Divide constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Divide";
|
||||
this.module = "Default";
|
||||
this.description = "Divides a list of numbers. If an item in the string is not a number it is excluded from the list.<br><br>e.g. <code>0x0a 8 .5</code> becomes <code>2.5</code>";
|
||||
this.inputType = "string";
|
||||
this.outputType = "BigNumber";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Delimiter",
|
||||
"type": "option",
|
||||
"value": ARITHMETIC_DELIM_OPTIONS,
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {BigNumber}
|
||||
*/
|
||||
run(input, args) {
|
||||
const val = div(createNumArray(input, args[0]));
|
||||
return val instanceof BigNumber ? val : new BigNumber(NaN);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Divide;
|
95
src/core/operations/DropBytes.mjs
Normal file
95
src/core/operations/DropBytes.mjs
Normal file
|
@ -0,0 +1,95 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
|
||||
/**
|
||||
* Drop bytes operation
|
||||
*/
|
||||
class DropBytes extends Operation {
|
||||
|
||||
/**
|
||||
* DropBytes constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Drop bytes";
|
||||
this.module = "Default";
|
||||
this.description = "Cuts a slice of the specified number of bytes out of the data.";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "ArrayBuffer";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Start",
|
||||
"type": "number",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"name": "Length",
|
||||
"type": "number",
|
||||
"value": 5
|
||||
},
|
||||
{
|
||||
"name": "Apply to each line",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {ArrayBuffer}
|
||||
*
|
||||
* @throws {OperationError} if invalid input
|
||||
*/
|
||||
run(input, args) {
|
||||
const start = args[0],
|
||||
length = args[1],
|
||||
applyToEachLine = args[2];
|
||||
|
||||
if (start < 0 || length < 0)
|
||||
throw new OperationError("Error: Invalid value");
|
||||
|
||||
if (!applyToEachLine) {
|
||||
const left = input.slice(0, start),
|
||||
right = input.slice(start + length, input.byteLength);
|
||||
const result = new Uint8Array(left.byteLength + right.byteLength);
|
||||
result.set(new Uint8Array(left), 0);
|
||||
result.set(new Uint8Array(right), left.byteLength);
|
||||
return result.buffer;
|
||||
}
|
||||
|
||||
// Split input into lines
|
||||
const data = new Uint8Array(input);
|
||||
const lines = [];
|
||||
let line = [],
|
||||
i;
|
||||
|
||||
for (i = 0; i < data.length; i++) {
|
||||
if (data[i] === 0x0a) {
|
||||
lines.push(line);
|
||||
line = [];
|
||||
} else {
|
||||
line.push(data[i]);
|
||||
}
|
||||
}
|
||||
lines.push(line);
|
||||
|
||||
let output = [];
|
||||
for (i = 0; i < lines.length; i++) {
|
||||
output = output.concat(lines[i].slice(0, start).concat(lines[i].slice(start+length, lines[i].length)));
|
||||
output.push(0x0a);
|
||||
}
|
||||
return new Uint8Array(output.slice(0, output.length-1)).buffer;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default DropBytes;
|
59
src/core/operations/EncodeNetBIOSName.mjs
Normal file
59
src/core/operations/EncodeNetBIOSName.mjs
Normal file
|
@ -0,0 +1,59 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
|
||||
/**
|
||||
* Encode NetBIOS Name operation
|
||||
*/
|
||||
class EncodeNetBIOSName extends Operation {
|
||||
|
||||
/**
|
||||
* EncodeNetBIOSName constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Encode NetBIOS Name";
|
||||
this.module = "Default";
|
||||
this.description = "NetBIOS names as seen across the client interface to NetBIOS are exactly 16 bytes long. Within the NetBIOS-over-TCP protocols, a longer representation is used.<br><br>There are two levels of encoding. The first level maps a NetBIOS name into a domain system name. The second level maps the domain system name into the 'compressed' representation required for interaction with the domain name system.<br><br>This operation carries out the first level of encoding. See RFC 1001 for full details.";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "byteArray";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Offset",
|
||||
"type": "number",
|
||||
"value": 65
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
run(input, args) {
|
||||
const output = [],
|
||||
offset = args[0];
|
||||
|
||||
if (input.length <= 16) {
|
||||
const len = input.length;
|
||||
input.length = 16;
|
||||
input.fill(32, len, 16);
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
output.push((input[i] >> 4) + offset);
|
||||
output.push((input[i] & 0xf) + offset);
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default EncodeNetBIOSName;
|
58
src/core/operations/EncodeText.mjs
Normal file
58
src/core/operations/EncodeText.mjs
Normal file
|
@ -0,0 +1,58 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import cptable from "../vendor/js-codepage/cptable.js";
|
||||
import {IO_FORMAT} from "../lib/ChrEnc";
|
||||
|
||||
/**
|
||||
* Encode text operation
|
||||
*/
|
||||
class EncodeText extends Operation {
|
||||
|
||||
/**
|
||||
* EncodeText constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Encode text";
|
||||
this.module = "CharEnc";
|
||||
this.description = [
|
||||
"Encodes text into the chosen character encoding.",
|
||||
"<br><br>",
|
||||
"Supported charsets are:",
|
||||
"<ul>",
|
||||
Object.keys(IO_FORMAT).map(e => `<li>${e}</li>`).join("\n"),
|
||||
"</ul>",
|
||||
].join("\n");
|
||||
this.inputType = "string";
|
||||
this.outputType = "byteArray";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Encoding",
|
||||
"type": "option",
|
||||
"value": Object.keys(IO_FORMAT)
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
run(input, args) {
|
||||
const format = IO_FORMAT[args[0]];
|
||||
let encoded = cptable.utils.encode(format, input);
|
||||
encoded = Array.from(encoded);
|
||||
return encoded;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
export default EncodeText;
|
96
src/core/operations/Entropy.mjs
Normal file
96
src/core/operations/Entropy.mjs
Normal file
|
@ -0,0 +1,96 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
|
||||
/**
|
||||
* Entropy operation
|
||||
*/
|
||||
class Entropy extends Operation {
|
||||
|
||||
/**
|
||||
* Entropy constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Entropy";
|
||||
this.module = "Default";
|
||||
this.description = "Calculates the Shannon entropy of the input data which gives an idea of its randomness. 8 is the maximum.";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "number";
|
||||
this.presentType = "html";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {number}
|
||||
*/
|
||||
run(input, args) {
|
||||
const prob = [],
|
||||
uniques = input.unique(),
|
||||
str = Utils.byteArrayToChars(input);
|
||||
let i;
|
||||
|
||||
for (i = 0; i < uniques.length; i++) {
|
||||
prob.push(str.count(Utils.chr(uniques[i])) / input.length);
|
||||
}
|
||||
|
||||
let entropy = 0,
|
||||
p;
|
||||
|
||||
for (i = 0; i < prob.length; i++) {
|
||||
p = prob[i];
|
||||
entropy += p * Math.log(p) / Math.log(2);
|
||||
}
|
||||
|
||||
return -entropy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the entropy as a scale bar for web apps.
|
||||
*
|
||||
* @param {number} entropy
|
||||
* @returns {html}
|
||||
*/
|
||||
present(entropy) {
|
||||
return `Shannon entropy: ${entropy}
|
||||
<br><canvas id='chart-area'></canvas><br>
|
||||
- 0 represents no randomness (i.e. all the bytes in the data have the same value) whereas 8, the maximum, represents a completely random string.
|
||||
- Standard English text usually falls somewhere between 3.5 and 5.
|
||||
- Properly encrypted or compressed data of a reasonable length should have an entropy of over 7.5.
|
||||
|
||||
The following results show the entropy of chunks of the input data. Chunks with particularly high entropy could suggest encrypted or compressed sections.
|
||||
|
||||
<br><script>
|
||||
var canvas = document.getElementById("chart-area"),
|
||||
parentRect = canvas.parentNode.getBoundingClientRect(),
|
||||
entropy = ${entropy},
|
||||
height = parentRect.height * 0.25;
|
||||
|
||||
canvas.width = parentRect.width * 0.95;
|
||||
canvas.height = height > 150 ? 150 : height;
|
||||
|
||||
CanvasComponents.drawScaleBar(canvas, entropy, 8, [
|
||||
{
|
||||
label: "English text",
|
||||
min: 3.5,
|
||||
max: 5
|
||||
},{
|
||||
label: "Encrypted/compressed",
|
||||
min: 7.5,
|
||||
max: 8
|
||||
}
|
||||
]);
|
||||
</script>`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Entropy;
|
87
src/core/operations/EscapeString.mjs
Normal file
87
src/core/operations/EscapeString.mjs
Normal file
|
@ -0,0 +1,87 @@
|
|||
/**
|
||||
* @author Vel0x [dalemy@microsoft.com]
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import jsesc from "jsesc";
|
||||
|
||||
/**
|
||||
* Escape string operation
|
||||
*/
|
||||
class EscapeString extends Operation {
|
||||
|
||||
/**
|
||||
* EscapeString constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Escape string";
|
||||
this.module = "Default";
|
||||
this.description = "Escapes special characters in a string so that they do not cause conflicts. For example, <code>Don't stop me now</code> becomes <code>Don\\'t stop me now</code>.<br><br>Supports the following escape sequences:<ul><li><code>\\n</code> (Line feed/newline)</li><li><code>\\r</code> (Carriage return)</li><li><code>\\t</code> (Horizontal tab)</li><li><code>\\b</code> (Backspace)</li><li><code>\\f</code> (Form feed)</li><li><code>\\xnn</code> (Hex, where n is 0-f)</li><li><code>\\\\</code> (Backslash)</li><li><code>\\'</code> (Single quote)</li><li><code>\\"</code> (Double quote)</li><li><code>\\unnnn</code> (Unicode character)</li><li><code>\\u{nnnnnn}</code> (Unicode code point)</li></ul>";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Escape level",
|
||||
"type": "option",
|
||||
"value": ["Special chars", "Everything", "Minimal"]
|
||||
},
|
||||
{
|
||||
"name": "Escape quote",
|
||||
"type": "option",
|
||||
"value": ["Single", "Double", "Backtick"]
|
||||
},
|
||||
{
|
||||
"name": "JSON compatible",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
},
|
||||
{
|
||||
"name": "ES6 compatible",
|
||||
"type": "boolean",
|
||||
"value": true
|
||||
},
|
||||
{
|
||||
"name": "Uppercase hex",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*
|
||||
* @example
|
||||
* EscapeString.run("Don't do that", [])
|
||||
* > "Don\'t do that"
|
||||
* EscapeString.run(`Hello
|
||||
* World`, [])
|
||||
* > "Hello\nWorld"
|
||||
*/
|
||||
run(input, args) {
|
||||
const level = args[0],
|
||||
quotes = args[1],
|
||||
jsonCompat = args[2],
|
||||
es6Compat = args[3],
|
||||
lowercaseHex = !args[4];
|
||||
|
||||
return jsesc(input, {
|
||||
quotes: quotes.toLowerCase(),
|
||||
es6: es6Compat,
|
||||
escapeEverything: level === "Everything",
|
||||
minimal: level === "Minimal",
|
||||
json: jsonCompat,
|
||||
lowercaseHex: lowercaseHex,
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default EscapeString;
|
96
src/core/operations/EscapeUnicodeCharacters.mjs
Normal file
96
src/core/operations/EscapeUnicodeCharacters.mjs
Normal file
|
@ -0,0 +1,96 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
|
||||
/**
|
||||
* Escape Unicode Characters operation
|
||||
*/
|
||||
class EscapeUnicodeCharacters extends Operation {
|
||||
|
||||
/**
|
||||
* EscapeUnicodeCharacters constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Escape Unicode Characters";
|
||||
this.module = "Default";
|
||||
this.description = "Converts characters to their unicode-escaped notations.<br><br>Supports the prefixes:<ul><li><code>\\u</code></li><li><code>%u</code></li><li><code>U+</code></li></ul>e.g. <code>σου</code> becomes <code>\\u03C3\\u03BF\\u03C5</code>";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Prefix",
|
||||
"type": "option",
|
||||
"value": ["\\u", "%u", "U+"]
|
||||
},
|
||||
{
|
||||
"name": "Encode all chars",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
},
|
||||
{
|
||||
"name": "Padding",
|
||||
"type": "number",
|
||||
"value": 4
|
||||
},
|
||||
{
|
||||
"name": "Uppercase hex",
|
||||
"type": "boolean",
|
||||
"value": true
|
||||
}
|
||||
];
|
||||
this.patterns = [
|
||||
{
|
||||
match: "\\\\u(?:[\\da-f]{4,6})",
|
||||
flags: "i",
|
||||
args: ["\\u"]
|
||||
},
|
||||
{
|
||||
match: "%u(?:[\\da-f]{4,6})",
|
||||
flags: "i",
|
||||
args: ["%u"]
|
||||
},
|
||||
{
|
||||
match: "U\\+(?:[\\da-f]{4,6})",
|
||||
flags: "i",
|
||||
args: ["U+"]
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const regexWhitelist = /[ -~]/i,
|
||||
[prefix, encodeAll, padding, uppercaseHex] = args;
|
||||
|
||||
let output = "",
|
||||
character = "";
|
||||
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
character = input[i];
|
||||
if (!encodeAll && regexWhitelist.test(character)) {
|
||||
// It’s a printable ASCII character so don’t escape it.
|
||||
output += character;
|
||||
continue;
|
||||
}
|
||||
|
||||
let cp = character.codePointAt(0).toString(16);
|
||||
if (uppercaseHex) cp = cp.toUpperCase();
|
||||
output += prefix + cp.padStart(padding, "0");
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default EscapeUnicodeCharacters;
|
46
src/core/operations/ExpandAlphabetRange.mjs
Normal file
46
src/core/operations/ExpandAlphabetRange.mjs
Normal file
|
@ -0,0 +1,46 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
|
||||
/**
|
||||
* Expand alphabet range operation
|
||||
*/
|
||||
class ExpandAlphabetRange extends Operation {
|
||||
|
||||
/**
|
||||
* ExpandAlphabetRange constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Expand alphabet range";
|
||||
this.module = "Default";
|
||||
this.description = "Expand an alphabet range string into a list of the characters in that range.<br><br>e.g. <code>a-z</code> becomes <code>abcdefghijklmnopqrstuvwxyz</code>.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Delimiter",
|
||||
"type": "binaryString",
|
||||
"value": ""
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
return Utils.expandAlphRange(input).join(args[0]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ExpandAlphabetRange;
|
52
src/core/operations/ExtractDates.mjs
Normal file
52
src/core/operations/ExtractDates.mjs
Normal file
|
@ -0,0 +1,52 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import { search } from "../lib/Extract";
|
||||
|
||||
/**
|
||||
* Extract dates operation
|
||||
*/
|
||||
class ExtractDates extends Operation {
|
||||
|
||||
/**
|
||||
* ExtractDates constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Extract dates";
|
||||
this.module = "Regex";
|
||||
this.description = "Extracts dates in the following formats<ul><li><code>yyyy-mm-dd</code></li><li><code>dd/mm/yyyy</code></li><li><code>mm/dd/yyyy</code></li></ul>Dividers can be any of /, -, . or space";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Display total",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const displayTotal = args[0],
|
||||
date1 = "(?:19|20)\\d\\d[- /.](?:0[1-9]|1[012])[- /.](?:0[1-9]|[12][0-9]|3[01])", // yyyy-mm-dd
|
||||
date2 = "(?:0[1-9]|[12][0-9]|3[01])[- /.](?:0[1-9]|1[012])[- /.](?:19|20)\\d\\d", // dd/mm/yyyy
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ExtractDates;
|
49
src/core/operations/ExtractDomains.mjs
Normal file
49
src/core/operations/ExtractDomains.mjs
Normal file
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import { search } from "../lib/Extract";
|
||||
|
||||
/**
|
||||
* Extract domains operation
|
||||
*/
|
||||
class ExtractDomains extends Operation {
|
||||
|
||||
/**
|
||||
* ExtractDomains constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Extract domains";
|
||||
this.module = "Regex";
|
||||
this.description = "Extracts domain names.<br>Note that this will not include paths. Use <strong>Extract URLs</strong> to find entire URLs.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Display total",
|
||||
"type": "boolean",
|
||||
"value": "Extract.DISPLAY_TOTAL"
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const displayTotal = args[0],
|
||||
regex = /\b((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,63}\b/ig;
|
||||
|
||||
return search(input, regex, null, displayTotal);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ExtractDomains;
|
49
src/core/operations/ExtractEmailAddresses.mjs
Normal file
49
src/core/operations/ExtractEmailAddresses.mjs
Normal file
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import { search } from "../lib/Extract";
|
||||
|
||||
/**
|
||||
* Extract email addresses operation
|
||||
*/
|
||||
class ExtractEmailAddresses extends Operation {
|
||||
|
||||
/**
|
||||
* ExtractEmailAddresses constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Extract email addresses";
|
||||
this.module = "Regex";
|
||||
this.description = "Extracts all email addresses from the input.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Display total",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const displayTotal = args[0],
|
||||
regex = /\b\w[-.\w]*@[-\w]+(?:\.[-\w]+)*\.[A-Z]{2,4}\b/ig;
|
||||
|
||||
return search(input, regex, null, displayTotal);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ExtractEmailAddresses;
|
78
src/core/operations/ExtractFilePaths.mjs
Normal file
78
src/core/operations/ExtractFilePaths.mjs
Normal file
|
@ -0,0 +1,78 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import { search } from "../lib/Extract";
|
||||
|
||||
/**
|
||||
* Extract file paths operation
|
||||
*/
|
||||
class ExtractFilePaths extends Operation {
|
||||
|
||||
/**
|
||||
* ExtractFilePaths constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Extract file paths";
|
||||
this.module = "Regex";
|
||||
this.description = "Extracts anything that looks like a Windows or UNIX file path.<br><br>Note that if UNIX is selected, there will likely be a lot of false positives.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Windows",
|
||||
"type": "boolean",
|
||||
"value": true
|
||||
},
|
||||
{
|
||||
"name": "UNIX",
|
||||
"type": "boolean",
|
||||
"value": true
|
||||
},
|
||||
{
|
||||
"name": "Display total",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [includeWinPath, includeUnixPath, displayTotal] = args,
|
||||
winDrive = "[A-Z]:\\\\",
|
||||
winName = "[A-Z\\d][A-Z\\d\\- '_\\(\\)~]{0,61}",
|
||||
winExt = "[A-Z\\d]{1,6}",
|
||||
winPath = winDrive + "(?:" + winName + "\\\\?)*" + winName +
|
||||
"(?:\\." + winExt + ")?",
|
||||
unixPath = "(?:/[A-Z\\d.][A-Z\\d\\-.]{0,61})+";
|
||||
let filePaths = "";
|
||||
|
||||
if (includeWinPath && includeUnixPath) {
|
||||
filePaths = winPath + "|" + unixPath;
|
||||
} else if (includeWinPath) {
|
||||
filePaths = winPath;
|
||||
} else if (includeUnixPath) {
|
||||
filePaths = unixPath;
|
||||
}
|
||||
|
||||
if (filePaths) {
|
||||
const regex = new RegExp(filePaths, "ig");
|
||||
return search(input, regex, null, displayTotal);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ExtractFilePaths;
|
91
src/core/operations/ExtractIPAddresses.mjs
Normal file
91
src/core/operations/ExtractIPAddresses.mjs
Normal file
|
@ -0,0 +1,91 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import { search } from "../lib/Extract";
|
||||
|
||||
/**
|
||||
* Extract IP addresses operation
|
||||
*/
|
||||
class ExtractIPAddresses extends Operation {
|
||||
|
||||
/**
|
||||
* ExtractIPAddresses constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Extract IP addresses";
|
||||
this.module = "Regex";
|
||||
this.description = "Extracts all IPv4 and IPv6 addresses.<br><br>Warning: Given a string <code>710.65.0.456</code>, this will match <code>10.65.0.45</code> so always check the original input!";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "IPv4",
|
||||
"type": "boolean",
|
||||
"value": true
|
||||
},
|
||||
{
|
||||
"name": "IPv6",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
},
|
||||
{
|
||||
"name": "Remove local IPv4 addresses",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
},
|
||||
{
|
||||
"name": "Display total",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [includeIpv4, includeIpv6, removeLocal, displayTotal] = 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 = "";
|
||||
|
||||
if (includeIpv4 && includeIpv6) {
|
||||
ips = ipv4 + "|" + ipv6;
|
||||
} else if (includeIpv4) {
|
||||
ips = ipv4;
|
||||
} else if (includeIpv6) {
|
||||
ips = ipv6;
|
||||
}
|
||||
|
||||
if (ips) {
|
||||
const regex = new RegExp(ips, "ig");
|
||||
|
||||
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 + ")");
|
||||
|
||||
return search(input, regex, removeRegex, displayTotal);
|
||||
} else {
|
||||
return search(input, regex, null, displayTotal);
|
||||
}
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ExtractIPAddresses;
|
49
src/core/operations/ExtractMACAddresses.mjs
Normal file
49
src/core/operations/ExtractMACAddresses.mjs
Normal file
|
@ -0,0 +1,49 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import { search } from "../lib/Extract";
|
||||
|
||||
/**
|
||||
* Extract MAC addresses operation
|
||||
*/
|
||||
class ExtractMACAddresses extends Operation {
|
||||
|
||||
/**
|
||||
* ExtractMACAddresses constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Extract MAC addresses";
|
||||
this.module = "Regex";
|
||||
this.description = "Extracts all Media Access Control (MAC) addresses from the input.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Display total",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const displayTotal = args[0],
|
||||
regex = /[A-F\d]{2}(?:[:-][A-F\d]{2}){5}/ig;
|
||||
|
||||
return search(input, regex, null, displayTotal);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ExtractMACAddresses;
|
55
src/core/operations/ExtractURLs.mjs
Normal file
55
src/core/operations/ExtractURLs.mjs
Normal file
|
@ -0,0 +1,55 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import { search } from "../lib/Extract";
|
||||
|
||||
/**
|
||||
* Extract URLs operation
|
||||
*/
|
||||
class ExtractURLs extends Operation {
|
||||
|
||||
/**
|
||||
* ExtractURLs constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Extract URLs";
|
||||
this.module = "Regex";
|
||||
this.description = "Extracts Uniform Resource Locators (URLs) from the input. The protocol (http, ftp etc.) is required otherwise there will be far too many false positives.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Display total",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const displayTotal = args[0],
|
||||
protocol = "[A-Z]+://",
|
||||
hostname = "[-\\w]+(?:\\.\\w[-\\w]*)+",
|
||||
port = ":\\d+";
|
||||
let path = "/[^.!,?\"<>\\[\\]{}\\s\\x7F-\\xFF]*";
|
||||
|
||||
path += "(?:[.!,?]+[^.!,?\"<>\\[\\]{}\\s\\x7F-\\xFF]+)*";
|
||||
const regex = new RegExp(protocol + hostname + "(?:" + port +
|
||||
")?(?:" + path + ")?", "ig");
|
||||
return search(input, regex, null, displayTotal);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ExtractURLs;
|
72
src/core/operations/Filter.mjs
Normal file
72
src/core/operations/Filter.mjs
Normal file
|
@ -0,0 +1,72 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import {INPUT_DELIM_OPTIONS} from "../lib/Delim";
|
||||
import OperationError from "../errors/OperationError";
|
||||
|
||||
/**
|
||||
* Filter operation
|
||||
*/
|
||||
class Filter extends Operation {
|
||||
|
||||
/**
|
||||
* Filter constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Filter";
|
||||
this.module = "Default";
|
||||
this.description = "Splits up the input using the specified delimiter and then filters each branch based on a regular expression.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Delimiter",
|
||||
"type": "option",
|
||||
"value": INPUT_DELIM_OPTIONS
|
||||
},
|
||||
{
|
||||
"name": "Regex",
|
||||
"type": "string",
|
||||
"value": ""
|
||||
},
|
||||
{
|
||||
"name": "Invert condition",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const delim = Utils.charRep(args[0]),
|
||||
reverse = args[2];
|
||||
let regex;
|
||||
|
||||
try {
|
||||
regex = new RegExp(args[1]);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Invalid regex. Details: ${err.message}`);
|
||||
}
|
||||
|
||||
const regexFilter = function(value) {
|
||||
return reverse ^ regex.test(value);
|
||||
};
|
||||
|
||||
return input.split(delim).filter(regexFilter).join(delim);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Filter;
|
48
src/core/operations/Fletcher16Checksum.mjs
Normal file
48
src/core/operations/Fletcher16Checksum.mjs
Normal file
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
|
||||
/**
|
||||
* Fletcher-16 Checksum operation
|
||||
*/
|
||||
class Fletcher16Checksum extends Operation {
|
||||
|
||||
/**
|
||||
* Fletcher16Checksum constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Fletcher-16 Checksum";
|
||||
this.module = "Hashing";
|
||||
this.description = "The Fletcher checksum is an algorithm for computing a position-dependent checksum devised by John Gould Fletcher at Lawrence Livermore Labs in the late 1970s.<br><br>The objective of the Fletcher checksum was to provide error-detection properties approaching those of a cyclic redundancy check but with the lower computational effort associated with summation techniques.";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
let a = 0,
|
||||
b = 0;
|
||||
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
a = (a + input[i]) % 0xff;
|
||||
b = (b + a) % 0xff;
|
||||
}
|
||||
|
||||
return Utils.hex(((b << 8) | a) >>> 0, 4);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Fletcher16Checksum;
|
48
src/core/operations/Fletcher32Checksum.mjs
Normal file
48
src/core/operations/Fletcher32Checksum.mjs
Normal file
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
|
||||
/**
|
||||
* Fletcher-32 Checksum operation
|
||||
*/
|
||||
class Fletcher32Checksum extends Operation {
|
||||
|
||||
/**
|
||||
* Fletcher32Checksum constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Fletcher-32 Checksum";
|
||||
this.module = "Hashing";
|
||||
this.description = "The Fletcher checksum is an algorithm for computing a position-dependent checksum devised by John Gould Fletcher at Lawrence Livermore Labs in the late 1970s.<br><br>The objective of the Fletcher checksum was to provide error-detection properties approaching those of a cyclic redundancy check but with the lower computational effort associated with summation techniques.";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
let a = 0,
|
||||
b = 0;
|
||||
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
a = (a + input[i]) % 0xffff;
|
||||
b = (b + a) % 0xffff;
|
||||
}
|
||||
|
||||
return Utils.hex(((b << 16) | a) >>> 0, 8);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Fletcher32Checksum;
|
48
src/core/operations/Fletcher64Checksum.mjs
Normal file
48
src/core/operations/Fletcher64Checksum.mjs
Normal file
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
|
||||
/**
|
||||
* Fletcher-64 Checksum operation
|
||||
*/
|
||||
class Fletcher64Checksum extends Operation {
|
||||
|
||||
/**
|
||||
* Fletcher64Checksum constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Fletcher-64 Checksum";
|
||||
this.module = "Hashing";
|
||||
this.description = "The Fletcher checksum is an algorithm for computing a position-dependent checksum devised by John Gould Fletcher at Lawrence Livermore Labs in the late 1970s.<br><br>The objective of the Fletcher checksum was to provide error-detection properties approaching those of a cyclic redundancy check but with the lower computational effort associated with summation techniques.";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
let a = 0,
|
||||
b = 0;
|
||||
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
a = (a + input[i]) % 0xffffffff;
|
||||
b = (b + a) % 0xffffffff;
|
||||
}
|
||||
|
||||
return Utils.hex(b >>> 0, 8) + Utils.hex(a >>> 0, 8);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Fletcher64Checksum;
|
48
src/core/operations/Fletcher8Checksum.mjs
Normal file
48
src/core/operations/Fletcher8Checksum.mjs
Normal file
|
@ -0,0 +1,48 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
|
||||
/**
|
||||
* Fletcher-8 Checksum operation
|
||||
*/
|
||||
class Fletcher8Checksum extends Operation {
|
||||
|
||||
/**
|
||||
* Fletcher8Checksum constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Fletcher-8 Checksum";
|
||||
this.module = "Hashing";
|
||||
this.description = "The Fletcher checksum is an algorithm for computing a position-dependent checksum devised by John Gould Fletcher at Lawrence Livermore Labs in the late 1970s.<br><br>The objective of the Fletcher checksum was to provide error-detection properties approaching those of a cyclic redundancy check but with the lower computational effort associated with summation techniques.";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
let a = 0,
|
||||
b = 0;
|
||||
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
a = (a + input[i]) % 0xf;
|
||||
b = (b + a) % 0xf;
|
||||
}
|
||||
|
||||
return Utils.hex(((b << 4) | a) >>> 0, 2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Fletcher8Checksum;
|
117
src/core/operations/Fork.mjs
Normal file
117
src/core/operations/Fork.mjs
Normal file
|
@ -0,0 +1,117 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Recipe from "../Recipe";
|
||||
import Dish from "../Dish";
|
||||
|
||||
/**
|
||||
* Fork operation
|
||||
*/
|
||||
class Fork extends Operation {
|
||||
|
||||
/**
|
||||
* Fork constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Fork";
|
||||
this.flowControl = true;
|
||||
this.module = "Default";
|
||||
this.description = "Split the input data up based on the specified delimiter and run all subsequent operations on each branch separately.<br><br>For example, to decode multiple Base64 strings, enter them all on separate lines then add the 'Fork' and 'From Base64' operations to the recipe. Each string will be decoded separately.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Split delimiter",
|
||||
"type": "binaryShortString",
|
||||
"value": "\\n"
|
||||
},
|
||||
{
|
||||
"name": "Merge delimiter",
|
||||
"type": "binaryShortString",
|
||||
"value": "\\n"
|
||||
},
|
||||
{
|
||||
"name": "Ignore errors",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Object} state - The current state of the recipe.
|
||||
* @param {number} state.progress - The current position in the recipe.
|
||||
* @param {Dish} state.dish - The Dish being operated on.
|
||||
* @param {Operation[]} state.opList - The list of operations in the recipe.
|
||||
* @returns {Object} The updated state of the recipe.
|
||||
*/
|
||||
async run(state) {
|
||||
const opList = state.opList,
|
||||
inputType = opList[state.progress].inputType,
|
||||
outputType = opList[state.progress].outputType,
|
||||
input = await state.dish.get(inputType),
|
||||
ings = opList[state.progress].ingValues,
|
||||
[splitDelim, mergeDelim, ignoreErrors] = ings,
|
||||
subOpList = [];
|
||||
let inputs = [],
|
||||
i;
|
||||
|
||||
if (input)
|
||||
inputs = input.split(splitDelim);
|
||||
|
||||
// Create subOpList for each tranche to operate on
|
||||
// (all remaining operations unless we encounter a Merge)
|
||||
for (i = state.progress + 1; i < opList.length; i++) {
|
||||
if (opList[i].name === "Merge" && !opList[i].disabled) {
|
||||
break;
|
||||
} else {
|
||||
subOpList.push(opList[i]);
|
||||
}
|
||||
}
|
||||
|
||||
const recipe = new Recipe();
|
||||
let output = "",
|
||||
progress = 0;
|
||||
|
||||
state.forkOffset += state.progress + 1;
|
||||
|
||||
recipe.addOperations(subOpList);
|
||||
|
||||
// Take a deep(ish) copy of the ingredient values
|
||||
const ingValues = subOpList.map(op => JSON.parse(JSON.stringify(op.ingValues)));
|
||||
|
||||
// Run recipe over each tranche
|
||||
for (i = 0; i < inputs.length; i++) {
|
||||
// Baseline ing values for each tranche so that registers are reset
|
||||
subOpList.forEach((op, i) => {
|
||||
op.ingValues = JSON.parse(JSON.stringify(ingValues[i]));
|
||||
});
|
||||
|
||||
const dish = new Dish();
|
||||
dish.set(inputs[i], inputType);
|
||||
|
||||
try {
|
||||
progress = await recipe.execute(dish, 0, state);
|
||||
} catch (err) {
|
||||
if (!ignoreErrors) {
|
||||
throw err;
|
||||
}
|
||||
progress = err.progress + 1;
|
||||
}
|
||||
output += await dish.get(outputType) + mergeDelim;
|
||||
}
|
||||
|
||||
state.dish.set(output, outputType);
|
||||
state.progress += progress;
|
||||
return state;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Fork;
|
121
src/core/operations/FormatMACAddresses.mjs
Normal file
121
src/core/operations/FormatMACAddresses.mjs
Normal file
|
@ -0,0 +1,121 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
|
||||
/**
|
||||
* Format MAC addresses operation
|
||||
*/
|
||||
class FormatMACAddresses extends Operation {
|
||||
|
||||
/**
|
||||
* FormatMACAddresses constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Format MAC addresses";
|
||||
this.module = "Default";
|
||||
this.description = "Displays given MAC addresses in multiple different formats.<br><br>Expects addresses in a list separated by newlines, spaces or commas.<br><br>WARNING: There are no validity checks.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Output case",
|
||||
"type": "option",
|
||||
"value": ["Both", "Upper only", "Lower only"]
|
||||
},
|
||||
{
|
||||
"name": "No delimiter",
|
||||
"type": "boolean",
|
||||
"value": true
|
||||
},
|
||||
{
|
||||
"name": "Dash delimiter",
|
||||
"type": "boolean",
|
||||
"value": true
|
||||
},
|
||||
{
|
||||
"name": "Colon delimiter",
|
||||
"type": "boolean",
|
||||
"value": true
|
||||
},
|
||||
{
|
||||
"name": "Cisco style",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
},
|
||||
{
|
||||
"name": "IPv6 interface ID",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
if (!input) return "";
|
||||
|
||||
const [
|
||||
outputCase,
|
||||
noDelim,
|
||||
dashDelim,
|
||||
colonDelim,
|
||||
ciscoStyle,
|
||||
ipv6IntID
|
||||
] = args,
|
||||
outputList = [],
|
||||
macs = input.toLowerCase().split(/[,\s\r\n]+/);
|
||||
|
||||
macs.forEach(function(mac) {
|
||||
const cleanMac = mac.replace(/[:.-]+/g, ""),
|
||||
macHyphen = cleanMac.replace(/(.{2}(?=.))/g, "$1-"),
|
||||
macColon = cleanMac.replace(/(.{2}(?=.))/g, "$1:"),
|
||||
macCisco = cleanMac.replace(/(.{4}(?=.))/g, "$1.");
|
||||
let macIPv6 = cleanMac.slice(0, 6) + "fffe" + cleanMac.slice(6);
|
||||
|
||||
macIPv6 = macIPv6.replace(/(.{4}(?=.))/g, "$1:");
|
||||
let bite = parseInt(macIPv6.slice(0, 2), 16) ^ 2;
|
||||
bite = bite.toString(16).padStart(2, "0");
|
||||
macIPv6 = bite + macIPv6.slice(2);
|
||||
|
||||
if (outputCase === "Lower only") {
|
||||
if (noDelim) outputList.push(cleanMac);
|
||||
if (dashDelim) outputList.push(macHyphen);
|
||||
if (colonDelim) outputList.push(macColon);
|
||||
if (ciscoStyle) outputList.push(macCisco);
|
||||
if (ipv6IntID) outputList.push(macIPv6);
|
||||
} else if (outputCase === "Upper only") {
|
||||
if (noDelim) outputList.push(cleanMac.toUpperCase());
|
||||
if (dashDelim) outputList.push(macHyphen.toUpperCase());
|
||||
if (colonDelim) outputList.push(macColon.toUpperCase());
|
||||
if (ciscoStyle) outputList.push(macCisco.toUpperCase());
|
||||
if (ipv6IntID) outputList.push(macIPv6.toUpperCase());
|
||||
} else {
|
||||
if (noDelim) outputList.push(cleanMac, cleanMac.toUpperCase());
|
||||
if (dashDelim) outputList.push(macHyphen, macHyphen.toUpperCase());
|
||||
if (colonDelim) outputList.push(macColon, macColon.toUpperCase());
|
||||
if (ciscoStyle) outputList.push(macCisco, macCisco.toUpperCase());
|
||||
if (ipv6IntID) outputList.push(macIPv6, macIPv6.toUpperCase());
|
||||
}
|
||||
|
||||
outputList.push(
|
||||
"" // Empty line to delimit groups
|
||||
);
|
||||
});
|
||||
|
||||
// Return the data as a string
|
||||
return outputList.join("\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default FormatMACAddresses;
|
110
src/core/operations/FrequencyDistribution.mjs
Normal file
110
src/core/operations/FrequencyDistribution.mjs
Normal file
|
@ -0,0 +1,110 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import OperationError from "../errors/OperationError";
|
||||
|
||||
/**
|
||||
* Frequency distribution operation
|
||||
*/
|
||||
class FrequencyDistribution extends Operation {
|
||||
|
||||
/**
|
||||
* FrequencyDistribution constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Frequency distribution";
|
||||
this.module = "Default";
|
||||
this.description = "Displays the distribution of bytes in the data as a graph.";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "json";
|
||||
this.presentType = "html";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Show 0%s",
|
||||
"type": "boolean",
|
||||
"value": "Entropy.FREQ_ZEROS"
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {json}
|
||||
*/
|
||||
run(input, args) {
|
||||
const data = new Uint8Array(input);
|
||||
if (!data.length) throw new OperationError("No data");
|
||||
|
||||
const distrib = new Array(256).fill(0),
|
||||
percentages = new Array(256),
|
||||
len = data.length;
|
||||
let i;
|
||||
|
||||
// Count bytes
|
||||
for (i = 0; i < len; i++) {
|
||||
distrib[data[i]]++;
|
||||
}
|
||||
|
||||
// Calculate percentages
|
||||
let repr = 0;
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (distrib[i] > 0) repr++;
|
||||
percentages[i] = distrib[i] / len * 100;
|
||||
}
|
||||
|
||||
return {
|
||||
"dataLength": len,
|
||||
"percentages": percentages,
|
||||
"distribution": distrib,
|
||||
"bytesRepresented": repr
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the frequency distribution as a bar chart for web apps.
|
||||
*
|
||||
* @param {json} freq
|
||||
* @returns {html}
|
||||
*/
|
||||
present(freq, args) {
|
||||
const showZeroes = args[0];
|
||||
// Print
|
||||
let output = `<canvas id='chart-area'></canvas><br>
|
||||
Total data length: ${freq.dataLength}
|
||||
Number of bytes represented: ${freq.bytesRepresented}
|
||||
Number of bytes not represented: ${256 - freq.bytesRepresented}
|
||||
|
||||
Byte Percentage
|
||||
<script>
|
||||
var canvas = document.getElementById("chart-area"),
|
||||
parentRect = canvas.parentNode.getBoundingClientRect(),
|
||||
scores = ${JSON.stringify(freq.percentages)};
|
||||
|
||||
canvas.width = parentRect.width * 0.95;
|
||||
canvas.height = parentRect.height * 0.9;
|
||||
|
||||
CanvasComponents.drawBarChart(canvas, scores, "Byte", "Frequency %", 16, 6);
|
||||
</script>`;
|
||||
|
||||
for (let i = 0; i < 256; i++) {
|
||||
if (freq.distribution[i] || showZeroes) {
|
||||
output += " " + Utils.hex(i, 2) + " (" +
|
||||
(freq.percentages[i].toFixed(2).replace(".00", "") + "%)").padEnd(8, " ") +
|
||||
Array(Math.ceil(freq.percentages[i])+1).join("|") + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default FrequencyDistribution;
|
122
src/core/operations/FromBCD.mjs
Normal file
122
src/core/operations/FromBCD.mjs
Normal file
|
@ -0,0 +1,122 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import {ENCODING_SCHEME, ENCODING_LOOKUP, FORMAT} from "../lib/BCD";
|
||||
import BigNumber from "bignumber.js";
|
||||
|
||||
/**
|
||||
* From BCD operation
|
||||
*/
|
||||
class FromBCD extends Operation {
|
||||
|
||||
/**
|
||||
* FromBCD constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "From BCD";
|
||||
this.module = "Default";
|
||||
this.description = "Binary-Coded Decimal (BCD) is a class of binary encodings of decimal numbers where each decimal digit is represented by a fixed number of bits, usually four or eight. Special bit patterns are sometimes used for a sign.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "BigNumber";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Scheme",
|
||||
"type": "option",
|
||||
"value": ENCODING_SCHEME
|
||||
},
|
||||
{
|
||||
"name": "Packed",
|
||||
"type": "boolean",
|
||||
"value": true
|
||||
},
|
||||
{
|
||||
"name": "Signed",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
},
|
||||
{
|
||||
"name": "Input format",
|
||||
"type": "option",
|
||||
"value": FORMAT
|
||||
}
|
||||
];
|
||||
this.patterns = [
|
||||
{
|
||||
match: "^(?:\\d{4} ){3,}\\d{4}$",
|
||||
flags: "",
|
||||
args: ["8 4 2 1", true, false, "Nibbles"]
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {BigNumber}
|
||||
*/
|
||||
run(input, args) {
|
||||
const encoding = ENCODING_LOOKUP[args[0]],
|
||||
packed = args[1],
|
||||
signed = args[2],
|
||||
inputFormat = args[3],
|
||||
nibbles = [];
|
||||
|
||||
let output = "",
|
||||
byteArray;
|
||||
|
||||
// Normalise the input
|
||||
switch (inputFormat) {
|
||||
case "Nibbles":
|
||||
case "Bytes":
|
||||
input = input.replace(/\s/g, "");
|
||||
for (let i = 0; i < input.length; i += 4) {
|
||||
nibbles.push(parseInt(input.substr(i, 4), 2));
|
||||
}
|
||||
break;
|
||||
case "Raw":
|
||||
default:
|
||||
byteArray = Utils.strToByteArray(input);
|
||||
byteArray.forEach(b => {
|
||||
nibbles.push(b >>> 4);
|
||||
nibbles.push(b & 15);
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
if (!packed) {
|
||||
// Discard each high nibble
|
||||
for (let i = 0; i < nibbles.length; i++) {
|
||||
nibbles.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (signed) {
|
||||
const sign = nibbles.pop();
|
||||
if (sign === 13 ||
|
||||
sign === 11) {
|
||||
// Negative
|
||||
output += "-";
|
||||
}
|
||||
}
|
||||
|
||||
nibbles.forEach(n => {
|
||||
if (isNaN(n)) throw new OperationError("Invalid input");
|
||||
const val = encoding.indexOf(n);
|
||||
if (val < 0) throw new OperationError(`Value ${Utils.bin(n, 4)} is not in the encoding scheme`);
|
||||
output += val.toString();
|
||||
});
|
||||
|
||||
return new BigNumber(output);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default FromBCD;
|
63
src/core/operations/FromBase.mjs
Normal file
63
src/core/operations/FromBase.mjs
Normal file
|
@ -0,0 +1,63 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import BigNumber from "bignumber.js";
|
||||
import OperationError from "../errors/OperationError";
|
||||
|
||||
/**
|
||||
* From Base operation
|
||||
*/
|
||||
class FromBase extends Operation {
|
||||
|
||||
/**
|
||||
* FromBase constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "From Base";
|
||||
this.module = "Default";
|
||||
this.description = "Converts a number to decimal from a given numerical base.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "BigNumber";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Radix",
|
||||
"type": "number",
|
||||
"value": 36
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {BigNumber}
|
||||
*/
|
||||
run(input, args) {
|
||||
const radix = args[0];
|
||||
if (radix < 2 || radix > 36) {
|
||||
throw new OperationError("Error: Radix argument must be between 2 and 36");
|
||||
}
|
||||
|
||||
const number = input.replace(/\s/g, "").split(".");
|
||||
let result = new BigNumber(number[0], radix) || 0;
|
||||
|
||||
if (number.length === 1) return result;
|
||||
|
||||
// Fractional part
|
||||
for (let i = 0; i < number[1].length; i++) {
|
||||
const digit = new BigNumber(number[1][i], radix);
|
||||
result += digit.div(Math.pow(radix, i+1));
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default FromBase;
|
|
@ -35,6 +35,13 @@ class FromBase32 extends Operation {
|
|||
value: true
|
||||
}
|
||||
];
|
||||
this.patterns = [
|
||||
{
|
||||
match: "^(?:[A-Z2-7]{8})+(?:[A-Z2-7]{2}={6}|[A-Z2-7]{4}={4}|[A-Z2-7]{5}={3}|[A-Z2-7]{7}={1})?$",
|
||||
flags: "",
|
||||
args: ["A-Z2-7=", false]
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
105
src/core/operations/FromBase58.mjs
Normal file
105
src/core/operations/FromBase58.mjs
Normal file
|
@ -0,0 +1,105 @@
|
|||
/**
|
||||
* @author tlwr [toby@toby.codes]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import {ALPHABET_OPTIONS} from "../lib/Base58";
|
||||
|
||||
/**
|
||||
* From Base58 operation
|
||||
*/
|
||||
class FromBase58 extends Operation {
|
||||
|
||||
/**
|
||||
* FromBase58 constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "From Base58";
|
||||
this.module = "Default";
|
||||
this.description = "Base58 (similar to Base64) is a notation for encoding arbitrary byte data. It differs from Base64 by removing easily misread characters (i.e. l, I, 0 and O) to improve human readability.<br><br>This operation decodes data from an ASCII string (with an alphabet of your choosing, presets included) back into its raw form.<br><br>e.g. <code>StV1DL6CwTryKyV</code> becomes <code>hello world</code><br><br>Base58 is commonly used in cryptocurrencies (Bitcoin, Ripple, etc).";
|
||||
this.inputType = "string";
|
||||
this.outputType = "byteArray";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Alphabet",
|
||||
"type": "editableOption",
|
||||
"value": ALPHABET_OPTIONS
|
||||
},
|
||||
{
|
||||
"name": "Remove non-alphabet chars",
|
||||
"type": "boolean",
|
||||
"value": true
|
||||
}
|
||||
];
|
||||
this.patterns = [
|
||||
{
|
||||
match: "^[1-9A-HJ-NP-Za-km-z]{20,}$",
|
||||
flags: "",
|
||||
args: ["123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz", false]
|
||||
},
|
||||
{
|
||||
match: "^[1-9A-HJ-NP-Za-km-z]{20,}$",
|
||||
flags: "",
|
||||
args: ["rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz", false]
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
run(input, args) {
|
||||
let alphabet = args[0] || ALPHABET_OPTIONS[0].value;
|
||||
const removeNonAlphaChars = args[1] === undefined ? true : args[1],
|
||||
result = [0];
|
||||
|
||||
alphabet = Utils.expandAlphRange(alphabet).join("");
|
||||
|
||||
if (alphabet.length !== 58 ||
|
||||
[].unique.call(alphabet).length !== 58) {
|
||||
throw new OperationError("Alphabet must be of length 58");
|
||||
}
|
||||
|
||||
if (input.length === 0) return [];
|
||||
|
||||
[].forEach.call(input, function(c, charIndex) {
|
||||
const index = alphabet.indexOf(c);
|
||||
|
||||
if (index === -1) {
|
||||
if (removeNonAlphaChars) {
|
||||
return;
|
||||
} else {
|
||||
throw new OperationError(`Char '${c}' at position ${charIndex} not in alphabet`);
|
||||
}
|
||||
}
|
||||
|
||||
let carry = result[0] * 58 + index;
|
||||
result[0] = carry & 0xFF;
|
||||
carry = carry >> 8;
|
||||
|
||||
for (let i = 1; i < result.length; i++) {
|
||||
carry += result[i] * 58;
|
||||
result[i] = carry & 0xFF;
|
||||
carry = carry >> 8;
|
||||
}
|
||||
|
||||
while (carry > 0) {
|
||||
result.push(carry & 0xFF);
|
||||
carry = carry >> 8;
|
||||
}
|
||||
});
|
||||
|
||||
return result.reverse();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default FromBase58;
|
|
@ -35,6 +35,73 @@ class FromBase64 extends Operation {
|
|||
value: true
|
||||
}
|
||||
];
|
||||
this.patterns = [
|
||||
{
|
||||
match: "^(?:[A-Z\\d+/]{4})+(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?$",
|
||||
flags: "i",
|
||||
args: ["A-Za-z0-9+/=", false]
|
||||
},
|
||||
{
|
||||
match: "^[A-Z\\d\\-_]{20,}$",
|
||||
flags: "i",
|
||||
args: ["A-Za-z0-9-_", false]
|
||||
},
|
||||
{
|
||||
match: "^(?:[A-Z\\d+\\-]{4}){5,}(?:[A-Z\\d+\\-]{2}==|[A-Z\\d+\\-]{3}=)?$",
|
||||
flags: "i",
|
||||
args: ["A-Za-z0-9+\\-=", false]
|
||||
},
|
||||
{
|
||||
match: "^(?:[A-Z\\d./]{4}){5,}(?:[A-Z\\d./]{2}==|[A-Z\\d./]{3}=)?$",
|
||||
flags: "i",
|
||||
args: ["./0-9A-Za-z=", false]
|
||||
},
|
||||
{
|
||||
match: "^[A-Z\\d_.]{20,}$",
|
||||
flags: "i",
|
||||
args: ["A-Za-z0-9_.", false]
|
||||
},
|
||||
{
|
||||
match: "^(?:[A-Z\\d._]{4}){5,}(?:[A-Z\\d._]{2}--|[A-Z\\d._]{3}-)?$",
|
||||
flags: "i",
|
||||
args: ["A-Za-z0-9._-", false]
|
||||
},
|
||||
{
|
||||
match: "^(?:[A-Z\\d+/]{4}){5,}(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?$",
|
||||
flags: "i",
|
||||
args: ["0-9a-zA-Z+/=", false]
|
||||
},
|
||||
{
|
||||
match: "^(?:[A-Z\\d+/]{4}){5,}(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?$",
|
||||
flags: "i",
|
||||
args: ["0-9A-Za-z+/=", false]
|
||||
},
|
||||
{
|
||||
match: "^[ !\"#$%&'()*+,\\-./\\d:;<=>?@A-Z[\\\\\\]^_]{20,}$",
|
||||
flags: "",
|
||||
args: [" -_", false]
|
||||
},
|
||||
{
|
||||
match: "^[A-Z\\d+\\-]{20,}$",
|
||||
flags: "i",
|
||||
args: ["+\\-0-9A-Za-z", false]
|
||||
},
|
||||
{
|
||||
match: "^[!\"#$%&'()*+,\\-0-689@A-NP-VX-Z[`a-fh-mp-r]{20,}$",
|
||||
flags: "",
|
||||
args: ["!-,-0-689@A-NP-VX-Z[`a-fh-mp-r", false]
|
||||
},
|
||||
{
|
||||
match: "^(?:[N-ZA-M\\d+/]{4}){5,}(?:[N-ZA-M\\d+/]{2}==|[N-ZA-M\\d+/]{3}=)?$",
|
||||
flags: "i",
|
||||
args: ["N-ZA-Mn-za-m0-9+/=", false]
|
||||
},
|
||||
{
|
||||
match: "^[A-Z\\d./]{20,}$",
|
||||
flags: "i",
|
||||
args: ["./0-9A-Za-z", false]
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
124
src/core/operations/FromBinary.mjs
Normal file
124
src/core/operations/FromBinary.mjs
Normal file
|
@ -0,0 +1,124 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import {BIN_DELIM_OPTIONS} from "../lib/Delim";
|
||||
|
||||
/**
|
||||
* From Binary operation
|
||||
*/
|
||||
class FromBinary extends Operation {
|
||||
|
||||
/**
|
||||
* FromBinary constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "From Binary";
|
||||
this.module = "Default";
|
||||
this.description = "Converts a binary string back into its raw form.<br><br>e.g. <code>01001000 01101001</code> becomes <code>Hi</code>";
|
||||
this.inputType = "string";
|
||||
this.outputType = "byteArray";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Delimiter",
|
||||
"type": "option",
|
||||
"value": BIN_DELIM_OPTIONS
|
||||
}
|
||||
];
|
||||
this.patterns = [
|
||||
{
|
||||
match: "^(?:[01]{8})+$",
|
||||
flags: "",
|
||||
args: ["None"]
|
||||
},
|
||||
{
|
||||
match: "^(?:[01]{8})(?: [01]{8})*$",
|
||||
flags: "",
|
||||
args: ["Space"]
|
||||
},
|
||||
{
|
||||
match: "^(?:[01]{8})(?:,[01]{8})*$",
|
||||
flags: "",
|
||||
args: ["Comma"]
|
||||
},
|
||||
{
|
||||
match: "^(?:[01]{8})(?:;[01]{8})*$",
|
||||
flags: "",
|
||||
args: ["Semi-colon"]
|
||||
},
|
||||
{
|
||||
match: "^(?:[01]{8})(?::[01]{8})*$",
|
||||
flags: "",
|
||||
args: ["Colon"]
|
||||
},
|
||||
{
|
||||
match: "^(?:[01]{8})(?:\\n[01]{8})*$",
|
||||
flags: "",
|
||||
args: ["Line feed"]
|
||||
},
|
||||
{
|
||||
match: "^(?:[01]{8})(?:\\r\\n[01]{8})*$",
|
||||
flags: "",
|
||||
args: ["CRLF"]
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
run(input, args) {
|
||||
const delimRegex = Utils.regexRep(args[0] || "Space");
|
||||
input = input.replace(delimRegex, "");
|
||||
|
||||
const output = [];
|
||||
const byteLen = 8;
|
||||
for (let i = 0; i < input.length; i += byteLen) {
|
||||
output.push(parseInt(input.substr(i, byteLen), 2));
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight From Binary
|
||||
*
|
||||
* @param {Object[]} pos
|
||||
* @param {number} pos[].start
|
||||
* @param {number} pos[].end
|
||||
* @param {Object[]} args
|
||||
* @returns {Object[]} pos
|
||||
*/
|
||||
highlight(pos, args) {
|
||||
const delim = Utils.charRep(args[0] || "Space");
|
||||
pos[0].start = pos[0].start === 0 ? 0 : Math.floor(pos[0].start / (8 + delim.length));
|
||||
pos[0].end = pos[0].end === 0 ? 0 : Math.ceil(pos[0].end / (8 + delim.length));
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight From Binary in reverse
|
||||
*
|
||||
* @param {Object[]} pos
|
||||
* @param {number} pos[].start
|
||||
* @param {number} pos[].end
|
||||
* @param {Object[]} args
|
||||
* @returns {Object[]} pos
|
||||
*/
|
||||
highlightReverse(pos, args) {
|
||||
const delim = Utils.charRep(args[0] || "Space");
|
||||
pos[0].start = pos[0].start * (8 + delim.length);
|
||||
pos[0].end = pos[0].end * (8 + delim.length) - delim.length;
|
||||
return pos;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default FromBinary;
|
83
src/core/operations/FromCharcode.mjs
Normal file
83
src/core/operations/FromCharcode.mjs
Normal file
|
@ -0,0 +1,83 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import {DELIM_OPTIONS} from "../lib/Delim";
|
||||
import OperationError from "../errors/OperationError";
|
||||
|
||||
/**
|
||||
* From Charcode operation
|
||||
*/
|
||||
class FromCharcode extends Operation {
|
||||
|
||||
/**
|
||||
* FromCharcode constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "From Charcode";
|
||||
this.module = "Default";
|
||||
this.description = "Converts unicode character codes back into text.<br><br>e.g. <code>0393 03b5 03b9 03ac 20 03c3 03bf 03c5</code> becomes <code>Γειά σου</code>";
|
||||
this.inputType = "string";
|
||||
this.outputType = "byteArray";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Delimiter",
|
||||
"type": "option",
|
||||
"value": DELIM_OPTIONS
|
||||
},
|
||||
{
|
||||
"name": "Base",
|
||||
"type": "number",
|
||||
"value": 16
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
*
|
||||
* @throws {OperationError} if base out of range
|
||||
*/
|
||||
run(input, args) {
|
||||
const delim = Utils.charRep(args[0] || "Space"),
|
||||
base = args[1];
|
||||
let bites = input.split(delim),
|
||||
i = 0;
|
||||
|
||||
if (base < 2 || base > 36) {
|
||||
throw new OperationError("Error: Base argument must be between 2 and 36");
|
||||
}
|
||||
|
||||
if (input.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
if (base !== 16 && ENVIRONMENT_IS_WORKER()) self.setOption("attemptHighlight", false);
|
||||
|
||||
// Split into groups of 2 if the whole string is concatenated and
|
||||
// too long to be a single character
|
||||
if (bites.length === 1 && input.length > 17) {
|
||||
bites = [];
|
||||
for (i = 0; i < input.length; i += 2) {
|
||||
bites.push(input.slice(i, i+2));
|
||||
}
|
||||
}
|
||||
|
||||
let latin1 = "";
|
||||
for (i = 0; i < bites.length; i++) {
|
||||
latin1 += Utils.chr(parseInt(bites[i], base));
|
||||
}
|
||||
return Utils.strToByteArray(latin1);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default FromCharcode;
|
88
src/core/operations/FromDecimal.mjs
Normal file
88
src/core/operations/FromDecimal.mjs
Normal file
|
@ -0,0 +1,88 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import {DELIM_OPTIONS} from "../lib/Delim";
|
||||
|
||||
/**
|
||||
* From Decimal operation
|
||||
*/
|
||||
class FromDecimal extends Operation {
|
||||
|
||||
/**
|
||||
* FromDecimal constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "From Decimal";
|
||||
this.module = "Default";
|
||||
this.description = "Converts the data from an ordinal integer array back into its raw form.<br><br>e.g. <code>72 101 108 108 111</code> becomes <code>Hello</code>";
|
||||
this.inputType = "string";
|
||||
this.outputType = "byteArray";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Delimiter",
|
||||
"type": "option",
|
||||
"value": DELIM_OPTIONS
|
||||
}
|
||||
];
|
||||
this.patterns = [
|
||||
{
|
||||
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?: (?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
||||
flags: "",
|
||||
args: ["Space"]
|
||||
},
|
||||
{
|
||||
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:,(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
||||
flags: "",
|
||||
args: ["Comma"]
|
||||
},
|
||||
{
|
||||
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:;(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
||||
flags: "",
|
||||
args: ["Semi-colon"]
|
||||
},
|
||||
{
|
||||
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?::(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
||||
flags: "",
|
||||
args: ["Colon"]
|
||||
},
|
||||
{
|
||||
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:\\n(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
||||
flags: "",
|
||||
args: ["Line feed"]
|
||||
},
|
||||
{
|
||||
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:\\r\\n(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
||||
flags: "",
|
||||
args: ["CRLF"]
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
run(input, args) {
|
||||
const delim = Utils.charRep(args[0]),
|
||||
output = [];
|
||||
let byteStr = input.split(delim);
|
||||
if (byteStr[byteStr.length-1] === "")
|
||||
byteStr = byteStr.slice(0, byteStr.length-1);
|
||||
|
||||
for (let i = 0; i < byteStr.length; i++) {
|
||||
output[i] = parseInt(byteStr[i], 10);
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default FromDecimal;
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue