add formatter

This commit is contained in:
Hare Sudhan 2024-02-24 22:59:51 -05:00
parent c4e7c41a6e
commit ce30989adc
693 changed files with 51226 additions and 26671 deletions

View file

@ -21,6 +21,9 @@ jobs:
npm install
npm run setheapsize
- name: Format
run: npx @biomejs/biome format . --write
- name: Lint
run: npx grunt lint

View file

@ -2,11 +2,13 @@
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
const BundleAnalyzerPlugin =
require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
const glob = require("glob");
const path = require("path");
const nodeFlags = "--experimental-modules --experimental-json-modules --experimental-specifier-resolution=node --no-warnings --no-deprecation";
const nodeFlags =
"--experimental-modules --experimental-json-modules --experimental-specifier-resolution=node --no-warnings --no-deprecation";
/**
* Grunt configuration for building the app in various formats.
@ -21,56 +23,100 @@ module.exports = function (grunt) {
grunt.file.preserveBOM = false;
// Tasks
grunt.registerTask("dev",
grunt.registerTask(
"dev",
"A persistent task which creates a development build whenever source files are modified.",
["clean:dev", "clean:config", "exec:generateConfig", "concurrent:dev"]);
["clean:dev", "clean:config", "exec:generateConfig", "concurrent:dev"],
);
grunt.registerTask("prod",
grunt.registerTask(
"prod",
"Creates a production-ready build. Use the --msg flag to add a compile message.",
[
"eslint", "clean:prod", "clean:config", "exec:generateConfig", "findModules", "webpack:web",
"copy:standalone", "zip:standalone", "clean:standalone", "exec:calcDownloadHash", "chmod"
]);
"eslint",
"clean:prod",
"clean:config",
"exec:generateConfig",
"findModules",
"webpack:web",
"copy:standalone",
"zip:standalone",
"clean:standalone",
"exec:calcDownloadHash",
"chmod",
],
);
grunt.registerTask("node",
grunt.registerTask(
"node",
"Compiles CyberChef into a single NodeJS module.",
[
"clean:node", "clean:config", "clean:nodeConfig", "exec:generateConfig", "exec:generateNodeIndex"
]);
"clean:node",
"clean:config",
"clean:nodeConfig",
"exec:generateConfig",
"exec:generateNodeIndex",
],
);
grunt.registerTask("configTests",
grunt.registerTask(
"configTests",
"A task which configures config files in preparation for tests to be run. Use `npm test` to run tests.",
[
"clean:config", "clean:nodeConfig", "exec:generateConfig", "exec:generateNodeIndex"
"clean:config",
"clean:nodeConfig",
"exec:generateConfig",
"exec:generateNodeIndex",
],
);
grunt.registerTask(
"testui",
"A task which runs all the UI tests in the tests directory. The prod task must already have been run.",
["connect:prod", "exec:browserTests"],
);
grunt.registerTask(
"testnodeconsumer",
"A task which checks whether consuming CJS and ESM apps work with the CyberChef build",
[
"exec:setupNodeConsumers",
"exec:testCJSNodeConsumer",
"exec:testESMNodeConsumer",
"exec:teardownNodeConsumers",
],
);
grunt.registerTask("default", "Lints the code base", [
"prettier",
"eslint",
"exec:repoSize",
]);
grunt.registerTask("testui",
"A task which runs all the UI tests in the tests directory. The prod task must already have been run.",
["connect:prod", "exec:browserTests"]);
grunt.registerTask("testnodeconsumer",
"A task which checks whether consuming CJS and ESM apps work with the CyberChef build",
["exec:setupNodeConsumers", "exec:testCJSNodeConsumer", "exec:testESMNodeConsumer", "exec:teardownNodeConsumers"]);
grunt.registerTask("default",
"Lints the code base",
["eslint", "exec:repoSize"]);
grunt.registerTask("lint", "eslint");
grunt.registerTask("format", ["prettier"]);
grunt.registerTask("findModules",
grunt.registerTask(
"findModules",
"Finds all generated modules and updates the entry point list for Webpack",
function (arg1, arg2) {
const moduleEntryPoints = listEntryModules();
grunt.log.writeln(`Found ${Object.keys(moduleEntryPoints).length} modules.`);
grunt.config.set("webpack.web.entry",
Object.assign({
main: "./src/web/index.js"
}, moduleEntryPoints));
});
grunt.log.writeln(
`Found ${Object.keys(moduleEntryPoints).length} modules.`,
);
grunt.config.set(
"webpack.web.entry",
Object.assign(
{
main: "./src/web/index.js",
},
moduleEntryPoints,
),
);
},
);
// Load tasks provided by each plugin
grunt.loadNpmTasks("grunt-eslint");
@ -83,15 +129,18 @@ module.exports = function (grunt) {
grunt.loadNpmTasks("grunt-concurrent");
grunt.loadNpmTasks("grunt-contrib-connect");
grunt.loadNpmTasks("grunt-zip");
grunt.loadNpmTasks("grunt-prettier");
// Project configuration
const compileTime = grunt.template.today("UTC:dd/mm/yyyy HH:MM:ss") + " UTC",
const compileTime =
grunt.template.today("UTC:dd/mm/yyyy HH:MM:ss") + " UTC",
pkg = grunt.file.readJSON("package.json"),
webpackConfig = require("./webpack.config.js"),
BUILD_CONSTANTS = {
COMPILE_TIME: JSON.stringify(compileTime),
COMPILE_MSG: JSON.stringify(grunt.option("compile-msg") || grunt.option("msg") || ""),
COMPILE_MSG: JSON.stringify(
grunt.option("compile-msg") || grunt.option("msg") || "",
),
PKG_VERSION: JSON.stringify(pkg.version),
},
moduleEntryPoints = listEntryModules(),
@ -104,20 +153,26 @@ module.exports = function (grunt) {
return {
mode: "production",
target: "web",
entry: Object.assign({
main: "./src/web/index.js"
}, moduleEntryPoints),
entry: Object.assign(
{
main: "./src/web/index.js",
},
moduleEntryPoints,
),
output: {
path: __dirname + "/build/prod",
filename: chunkData => {
return chunkData.chunk.name === "main" ? "assets/[name].js": "[name].js";
filename: (chunkData) => {
return chunkData.chunk.name === "main"
? "assets/[name].js"
: "[name].js";
},
globalObject: "this"
globalObject: "this",
},
resolve: {
alias: {
"./config/modules/OpModules.mjs": "./config/modules/Default.mjs"
}
"./config/modules/OpModules.mjs":
"./config/modules/Default.mjs",
},
},
plugins: [
new webpack.DefinePlugin(BUILD_CONSTANTS),
@ -131,29 +186,29 @@ module.exports = function (grunt) {
removeComments: true,
collapseWhitespace: true,
minifyJS: true,
minifyCSS: true
}
minifyCSS: true,
},
}),
new BundleAnalyzerPlugin({
analyzerMode: "static",
reportFilename: "BundleAnalyzerReport.html",
openAnalyzer: false
openAnalyzer: false,
}),
]
],
};
};
/**
* Generates an entry list for all the modules.
*/
function listEntryModules() {
const entryModules = {};
glob.sync("./src/core/config/modules/*.mjs").forEach(file => {
glob.sync("./src/core/config/modules/*.mjs").forEach((file) => {
const basename = path.basename(file);
if (basename !== "Default.mjs" && basename !== "OpModules.mjs")
entryModules["modules/" + basename.split(".mjs")[0]] = path.resolve(file);
entryModules["modules/" + basename.split(".mjs")[0]] =
path.resolve(file);
});
return entryModules;
@ -171,12 +226,14 @@ module.exports = function (grunt) {
if (!win) {
return cmds.join(";");
}
return cmds
return (
cmds
// && means that subsequent commands will not be executed if the
// previous one fails. & would coninue on a fail
.join("&&")
// Windows does not support \n properly
.replace(/\n/g, "\\n");
.replace(/\n/g, "\\n")
);
}
grunt.initConfig({
@ -184,17 +241,36 @@ module.exports = function (grunt) {
dev: ["build/dev/*"],
prod: ["build/prod/*"],
node: ["build/node/*"],
config: ["src/core/config/OperationConfig.json", "src/core/config/modules/*", "src/code/operations/index.mjs"],
nodeConfig: ["src/node/index.mjs", "src/node/config/OperationConfig.json"],
standalone: ["build/prod/CyberChef*.html"]
config: [
"src/core/config/OperationConfig.json",
"src/core/config/modules/*",
"src/code/operations/index.mjs",
],
nodeConfig: [
"src/node/index.mjs",
"src/node/config/OperationConfig.json",
],
standalone: ["build/prod/CyberChef*.html"],
},
eslint: {
configs: ["*.{js,mjs}"],
core: ["src/core/**/*.{js,mjs}", "!src/core/vendor/**/*", "!src/core/operations/legacy/**/*"],
core: [
"src/core/**/*.{js,mjs}",
"!src/core/vendor/**/*",
"!src/core/operations/legacy/**/*",
],
web: ["src/web/**/*.{js,mjs}", "!src/web/static/**/*"],
node: ["src/node/**/*.{js,mjs}"],
tests: ["tests/**/*.{js,mjs}"],
},
prettier: {
options: {
progress: false,
},
files: {
src: ["*.{js,mjs}", "src/**/*.{js,mjs}", "tests/**/*.{js,mjs}"],
},
},
webpack: {
options: webpackConfig,
myConfig: webpackConfig,
@ -205,21 +281,25 @@ module.exports = function (grunt) {
start: {
mode: "development",
target: "web",
entry: Object.assign({
main: "./src/web/index.js"
}, moduleEntryPoints),
entry: Object.assign(
{
main: "./src/web/index.js",
},
moduleEntryPoints,
),
resolve: {
alias: {
"./config/modules/OpModules.mjs": "./config/modules/Default.mjs"
}
"./config/modules/OpModules.mjs":
"./config/modules/Default.mjs",
},
},
devServer: {
port: grunt.option("port") || 8080,
client: {
logging: "error",
overlay: true
overlay: true,
},
hot: "only"
hot: "only",
},
plugins: [
new webpack.DefinePlugin(BUILD_CONSTANTS),
@ -229,9 +309,9 @@ module.exports = function (grunt) {
chunks: ["main"],
compileTime: compileTime,
version: pkg.version,
})
]
}
}),
],
},
},
zip: {
standalone: {
@ -241,16 +321,16 @@ module.exports = function (grunt) {
"!build/prod/index.html",
"!build/prod/BundleAnalyzerReport.html",
],
dest: `build/prod/CyberChef_v${pkg.version}.zip`
}
dest: `build/prod/CyberChef_v${pkg.version}.zip`,
},
},
connect: {
prod: {
options: {
port: grunt.option("port") || 8000,
base: "build/prod/"
}
}
base: "build/prod/",
},
},
},
copy: {
ghPages: {
@ -258,70 +338,86 @@ module.exports = function (grunt) {
process: function (content, srcpath) {
if (srcpath.indexOf("index.html") >= 0) {
// Add Google Analytics code to index.html
content = content.replace("</body></html>",
grunt.file.read("src/web/static/ga.html") + "</body></html>");
content = content.replace(
"</body></html>",
grunt.file.read("src/web/static/ga.html") +
"</body></html>",
);
// Add Structured Data for SEO
content = content.replace("</head>",
content = content.replace(
"</head>",
"<script type='application/ld+json'>" +
JSON.stringify(JSON.parse(grunt.file.read("src/web/static/structuredData.json"))) +
"</script></head>");
JSON.stringify(
JSON.parse(
grunt.file.read(
"src/web/static/structuredData.json",
),
),
) +
"</script></head>",
);
return grunt.template.process(content, srcpath);
} else {
return content;
}
},
noProcess: ["**", "!**/*.html"]
noProcess: ["**", "!**/*.html"],
},
files: [
{
src: ["build/prod/index.html"],
dest: "build/prod/index.html"
}
]
dest: "build/prod/index.html",
},
],
},
standalone: {
options: {
process: function (content, srcpath) {
if (srcpath.indexOf("index.html") >= 0) {
// Replace download link with version number
content = content.replace(/<a [^>]+>Download CyberChef.+?<\/a>/,
`<span>Version ${pkg.version}</span>`);
content = content.replace(
/<a [^>]+>Download CyberChef.+?<\/a>/,
`<span>Version ${pkg.version}</span>`,
);
return grunt.template.process(content, srcpath);
} else {
return content;
}
},
noProcess: ["**", "!**/*.html"]
noProcess: ["**", "!**/*.html"],
},
files: [
{
src: ["build/prod/index.html"],
dest: `build/prod/CyberChef_v${pkg.version}.html`
}
]
}
dest: `build/prod/CyberChef_v${pkg.version}.html`,
},
],
},
},
chmod: {
build: {
options: {
mode: "755",
},
src: ["build/**/*", "build/"]
}
src: ["build/**/*", "build/"],
},
},
watch: {
config: {
files: ["src/core/operations/**/*", "!src/core/operations/index.mjs"],
tasks: ["exec:generateNodeIndex", "exec:generateConfig"]
}
files: [
"src/core/operations/**/*",
"!src/core/operations/index.mjs",
],
tasks: ["exec:generateNodeIndex", "exec:generateConfig"],
},
},
concurrent: {
dev: ["watch:config", "webpack-dev-server:start"],
options: {
logConcurrentOutput: true
}
logConcurrentOutput: true,
},
},
exec: {
calcDownloadHash: {
@ -330,12 +426,12 @@ module.exports = function (grunt) {
case "darwin":
return chainCommands([
`shasum -a 256 build/prod/CyberChef_v${pkg.version}.zip | awk '{print $1;}' > build/prod/sha256digest.txt`,
`sed -i '' -e "s/DOWNLOAD_HASH_PLACEHOLDER/$(cat build/prod/sha256digest.txt)/" build/prod/index.html`
`sed -i '' -e "s/DOWNLOAD_HASH_PLACEHOLDER/$(cat build/prod/sha256digest.txt)/" build/prod/index.html`,
]);
default:
return chainCommands([
`sha256sum build/prod/CyberChef_v${pkg.version}.zip | awk '{print $1;}' > build/prod/sha256digest.txt`,
`sed -i -e "s/DOWNLOAD_HASH_PLACEHOLDER/$(cat build/prod/sha256digest.txt)/" build/prod/index.html`
`sed -i -e "s/DOWNLOAD_HASH_PLACEHOLDER/$(cat build/prod/sha256digest.txt)/" build/prod/index.html`,
]);
}
},
@ -343,16 +439,16 @@ module.exports = function (grunt) {
repoSize: {
command: chainCommands([
"git ls-files | wc -l | xargs printf '\n%b\ttracked files\n'",
"du -hs | egrep -o '^[^\t]*' | xargs printf '%b\trepository size\n'"
"du -hs | egrep -o '^[^\t]*' | xargs printf '%b\trepository size\n'",
]),
stderr: false
stderr: false,
},
cleanGit: {
command: "git gc --prune=now --aggressive"
command: "git gc --prune=now --aggressive",
},
sitemap: {
command: `node ${nodeFlags} src/web/static/sitemap.mjs > build/prod/sitemap.xml`,
sync: true
sync: true,
},
generateConfig: {
command: chainCommands([
@ -360,20 +456,20 @@ module.exports = function (grunt) {
"echo [] > src/core/config/OperationConfig.json",
`node ${nodeFlags} src/core/config/scripts/generateOpsIndex.mjs`,
`node ${nodeFlags} src/core/config/scripts/generateConfig.mjs`,
"echo '--- Config scripts finished. ---\n'"
"echo '--- Config scripts finished. ---\n'",
]),
sync: true
sync: true,
},
generateNodeIndex: {
command: chainCommands([
"echo '\n--- Regenerating node index ---'",
`node ${nodeFlags} src/node/config/scripts/generateNodeIndex.mjs`,
"echo '--- Node index generated. ---\n'"
"echo '--- Node index generated. ---\n'",
]),
sync: true
sync: true,
},
browserTests: {
command: "./node_modules/.bin/nightwatch --env prod"
command: "./node_modules/.bin/nightwatch --env prod",
},
setupNodeConsumers: {
command: chainCommands([
@ -382,14 +478,14 @@ module.exports = function (grunt) {
`mkdir ${nodeConsumerTestPath}`,
`cp tests/node/consumers/* ${nodeConsumerTestPath}`,
`cd ${nodeConsumerTestPath}`,
"npm link cyberchef"
"npm link cyberchef",
]),
sync: true
sync: true,
},
teardownNodeConsumers: {
command: chainCommands([
`rm -rf ${nodeConsumerTestPath}`,
"echo '\n--- Node consumer tests complete ---'"
"echo '\n--- Node consumer tests complete ---'",
]),
},
testCJSNodeConsumer: {
@ -415,7 +511,7 @@ module.exports = function (grunt) {
return `find ./node_modules/crypto-api/src/ \\( -type d -name .git -prune \\) -o -type f -print0 | xargs -0 sed -i -e '/\\.mjs/!s/\\(from "\\.[^"]*\\)";/\\1.mjs";/g'`;
}
},
stdout: false
stdout: false,
},
fixSnackbarMarkup: {
command: function () {
@ -426,8 +522,8 @@ module.exports = function (grunt) {
return `sed -i 's/<div id=snackbar-container\\/>/<div id=snackbar-container>/g' ./node_modules/snackbarjs/src/snackbar.js`;
}
},
stdout: false
}
stdout: false,
},
},
});
};

View file

@ -2,26 +2,31 @@ module.exports = function(api) {
api.cache.forever();
return {
"presets": [
["@babel/preset-env", {
"modules": false,
"useBuiltIns": "entry",
"corejs": 3
}]
presets: [
[
"@babel/preset-env",
{
modules: false,
useBuiltIns: "entry",
corejs: 3,
},
],
"plugins": [
],
plugins: [
"dynamic-import-node",
"@babel/plugin-syntax-import-assertions",
[
"babel-plugin-transform-builtin-extend", {
"globals": ["Error"]
}
"babel-plugin-transform-builtin-extend",
{
globals: ["Error"],
},
],
[
"@babel/plugin-transform-runtime", {
"regenerator": true
}
]
]
"@babel/plugin-transform-runtime",
{
regenerator: true,
},
],
],
};
};

20
biome.json Normal file
View file

@ -0,0 +1,20 @@
{
"$schema": "https://biomejs.dev/schemas/1.5.3/schema.json",
"organizeImports": {
"enabled": true
},
"linter": {
"enabled": false
},
"formatter": {
"enabled": true,
"formatWithErrors": false,
"indentStyle": "space",
"indentWidth": 4,
"lineWidth": 80,
"ignore": []
},
"files": {
"include": ["**/*.*js"]
}
}

38
package-lock.json generated
View file

@ -130,6 +130,7 @@
"grunt-contrib-watch": "^1.1.0",
"grunt-eslint": "^24.3.0",
"grunt-exec": "~3.0.0",
"grunt-prettier": "^2.2.0",
"grunt-webpack": "^6.0.0",
"grunt-zip": "^1.0.0",
"html-webpack-plugin": "^5.6.0",
@ -8117,6 +8118,28 @@
"node": ">=10"
}
},
"node_modules/grunt-prettier": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/grunt-prettier/-/grunt-prettier-2.2.0.tgz",
"integrity": "sha512-kl6+1sYEM7HezxZS0DEFYYpD7JtwsToD8ZK2kDpAd3SvHINbz2iwsghpPsmdGihUJ2FVo8XBIzACmNxBBCytqQ==",
"dev": true,
"dependencies": {
"prettier": "^2.0.5",
"progress": "^2.0.0"
},
"engines": {
"node": ">= 10.0.0"
}
},
"node_modules/grunt-prettier/node_modules/progress": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
"dev": true,
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/grunt-retro": {
"version": "0.6.4",
"dev": true,
@ -12174,6 +12197,21 @@
"node": ">= 0.8.0"
}
},
"node_modules/prettier": {
"version": "2.8.8",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz",
"integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==",
"dev": true,
"bin": {
"prettier": "bin-prettier.js"
},
"engines": {
"node": ">=10.13.0"
},
"funding": {
"url": "https://github.com/prettier/prettier?sponsor=1"
}
},
"node_modules/pretty-error": {
"version": "4.0.0",
"dev": true,

View file

@ -189,6 +189,7 @@
"testui": "npx grunt testui",
"testuidev": "npx nightwatch --env=dev",
"lint": "npx grunt lint",
"format": "npx @biomejs/biome format . --write",
"postinstall": "npx grunt exec:fixCryptoApiImports && npx grunt exec:fixSnackbarMarkup",
"newop": "node --experimental-modules --experimental-json-modules src/core/config/scripts/newOperation.mjs",
"minor": "node --experimental-modules --experimental-json-modules src/core/config/scripts/newMinorVersion.mjs",

View file

@ -3,7 +3,7 @@ module.exports = {
require("postcss-import"),
require("autoprefixer"),
require("postcss-css-variables")({
preserve: true
preserve: true,
}),
]
],
};

View file

@ -13,7 +13,6 @@ import { isWorkerEnvironment } from "./Utils.mjs";
* The main controller for CyberChef.
*/
class Chef {
/**
* Chef constructor
*/
@ -21,7 +20,6 @@ class Chef {
this.dish = new Dish();
}
/**
* Runs the recipe over the input.
*
@ -45,10 +43,12 @@ class Chef {
let error = false,
progress = 0;
if (containsFc && isWorkerEnvironment()) self.setOption("attemptHighlight", false);
if (containsFc && isWorkerEnvironment())
self.setOption("attemptHighlight", false);
// Load data
const type = input instanceof ArrayBuffer ? Dish.ARRAY_BUFFER : Dish.STRING;
const type =
input instanceof ArrayBuffer ? Dish.ARRAY_BUFFER : Dish.STRING;
this.dish.set(input, type);
try {
@ -68,8 +68,11 @@ class Chef {
await recipe.present(this.dish);
const returnType =
this.dish.type === Dish.HTML ? Dish.HTML :
options?.returnType ? options.returnType : Dish.ARRAY_BUFFER;
this.dish.type === Dish.HTML
? Dish.HTML
: options?.returnType
? options.returnType
: Dish.ARRAY_BUFFER;
return {
dish: rawDish,
@ -77,11 +80,10 @@ class Chef {
type: Dish.enumLookup(this.dish.type),
progress: progress,
duration: Date.now() - startTime,
error: error
error: error,
};
}
/**
* When a browser tab is unfocused and the browser has to run lots of dynamic content in other tabs,
* it swaps out the memory for that tab. If the CyberChef tab has been unfocused for more than a
@ -114,7 +116,6 @@ class Chef {
return Date.now() - startTime;
}
/**
* Calculates highlight offsets if possible.
*
@ -135,7 +136,8 @@ class Chef {
// Remove multiple highlights before processing again
pos = [pos[0]];
const func = direction === "forward" ? highlights[i].f : highlights[i].b;
const func =
direction === "forward" ? highlights[i].f : highlights[i].b;
if (typeof func == "function") {
try {
@ -149,11 +151,10 @@ class Chef {
return {
pos: pos,
direction: direction
direction: direction,
};
}
/**
* Translates the dish to a specified type and returns it.
*
@ -177,7 +178,6 @@ class Chef {
const newDish = new Dish(dish);
return await newDish.getTitle(maxLength);
}
}
export default Chef;

View file

@ -7,11 +7,12 @@
*/
import Chef from "./Chef.mjs";
import OperationConfig from "./config/OperationConfig.json" assert {type: "json"};
import OperationConfig from "./config/OperationConfig.json" assert {
type: "json",
};
import OpModules from "./config/modules/OpModules.mjs";
import loglevelMessagePrefix from "loglevel-message-prefix";
// Set up Chef instance
self.chef = new Chef();
@ -19,11 +20,10 @@ self.OpModules = OpModules;
self.OperationConfig = OperationConfig;
self.inputNum = -1;
// Tell the app that the worker has loaded and is ready to operate
self.postMessage({
action: "workerLoaded",
data: {}
data: {},
});
/**
@ -72,7 +72,7 @@ self.addEventListener("message", function(e) {
calculateHighlights(
r.data.recipeConfig,
r.data.direction,
r.data.pos
r.data.pos,
);
break;
case "setLogLevel":
@ -81,7 +81,7 @@ self.addEventListener("message", function(e) {
case "setLogPrefix":
loglevelMessagePrefix(log, {
prefixes: [],
staticPrefixes: [r.data]
staticPrefixes: [r.data],
});
break;
default:
@ -89,7 +89,6 @@ self.addEventListener("message", function(e) {
}
});
/**
* Baking handler
*
@ -103,36 +102,38 @@ async function bake(data) {
const response = await self.chef.bake(
data.input, // The user's input
data.recipeConfig, // The configuration of the recipe
data.options // Options set by the user
data.options, // Options set by the user
);
const transferable = (response.dish.value instanceof ArrayBuffer) ?
[response.dish.value] :
undefined;
const transferable =
response.dish.value instanceof ArrayBuffer
? [response.dish.value]
: undefined;
self.postMessage({
self.postMessage(
{
action: "bakeComplete",
data: Object.assign(response, {
id: data.id,
inputNum: data.inputNum,
bakeId: data.bakeId
})
}, transferable);
bakeId: data.bakeId,
}),
},
transferable,
);
} catch (err) {
self.postMessage({
action: "bakeError",
data: {
error: err.message || err,
id: data.id,
inputNum: data.inputNum
}
inputNum: data.inputNum,
},
});
}
self.inputNum = -1;
}
/**
* Silent baking handler
*/
@ -141,26 +142,27 @@ function silentBake(data) {
self.postMessage({
action: "silentBakeComplete",
data: duration
data: duration,
});
}
/**
* Translates the dish to a given type.
*/
async function getDishAs(data) {
const value = await self.chef.getDishAs(data.dish, data.type);
const transferable = (data.type === "ArrayBuffer") ? [value] : undefined;
self.postMessage({
const transferable = data.type === "ArrayBuffer" ? [value] : undefined;
self.postMessage(
{
action: "dishReturned",
data: {
value: value,
id: data.id
id: data.id,
},
},
transferable,
);
}
}, transferable);
}
/**
* Gets the dish title
@ -176,12 +178,11 @@ async function getDishTitle(data) {
action: "dishReturned",
data: {
value: title,
id: data.id
}
id: data.id,
},
});
}
/**
* Calculates highlight offsets if possible.
*
@ -196,18 +197,17 @@ async function calculateHighlights(recipeConfig, direction, pos) {
self.postMessage({
action: "highlightsCalculated",
data: pos
data: pos,
});
}
/**
* Checks that all required modules are loaded and loads them if not.
*
* @param {Object} recipeConfig
*/
self.loadRequiredModules = function (recipeConfig) {
recipeConfig.forEach(op => {
recipeConfig.forEach((op) => {
const module = self.OperationConfig[op.op].module;
if (!(module in OpModules)) {
@ -219,7 +219,6 @@ self.loadRequiredModules = function(recipeConfig) {
});
};
/**
* Send status update to the app.
*
@ -230,12 +229,11 @@ self.sendStatusMessage = function(msg) {
action: "statusMessage",
data: {
message: msg,
inputNum: self.inputNum
}
inputNum: self.inputNum,
},
});
};
/**
* Send progress update to the app.
*
@ -248,12 +246,11 @@ self.sendProgressMessage = function(progress, total) {
data: {
progress: progress,
total: total,
inputNum: self.inputNum
}
inputNum: self.inputNum,
},
});
};
/**
* Send an option value update to the app.
*
@ -265,12 +262,11 @@ self.setOption = function(option, value) {
action: "optionUpdate",
data: {
option: option,
value: value
}
value: value,
},
});
};
/**
* Send register values back to the app.
*
@ -284,7 +280,7 @@ self.setRegisters = function(opIndex, numPrevRegisters, registers) {
data: {
opIndex: opIndex,
numPrevRegisters: numPrevRegisters,
registers: registers
}
registers: registers,
},
});
};

View file

@ -20,12 +20,10 @@ import DishListFile from "./dishTypes/DishListFile.mjs";
import DishNumber from "./dishTypes/DishNumber.mjs";
import DishString from "./dishTypes/DishString.mjs";
/**
* The data being operated on by each operation.
*/
class Dish {
/**
* Dish constructor
*
@ -39,9 +37,11 @@ class Dish {
this.type = Dish.ARRAY_BUFFER;
// Case: dishOrInput is dish object
if (dishOrInput &&
if (
dishOrInput &&
Object.prototype.hasOwnProperty.call(dishOrInput, "value") &&
Object.prototype.hasOwnProperty.call(dishOrInput, "type")) {
Object.prototype.hasOwnProperty.call(dishOrInput, "type")
) {
this.set(dishOrInput.value, dishOrInput.type);
// input and type defined separately
} else if (dishOrInput && type !== null) {
@ -53,7 +53,6 @@ class Dish {
}
}
/**
* Returns the data type enum for the given type string.
*
@ -85,11 +84,12 @@ class Dish {
case "list<file>":
return Dish.LIST_FILE;
default:
throw new DishError("Invalid data type string. No matching enum.");
throw new DishError(
"Invalid data type string. No matching enum.",
);
}
}
/**
* Returns the data type string for the given type enum.
*
@ -117,11 +117,12 @@ class Dish {
case Dish.LIST_FILE:
return "List<File>";
default:
throw new DishError("Invalid data type enum. No matching type.");
throw new DishError(
"Invalid data type enum. No matching type.",
);
}
}
/**
* Returns the value of the data in the type format specified.
*
@ -136,7 +137,6 @@ class Dish {
}
if (this.type !== type) {
// Node environment => _translate is sync
if (isNodeEnvironment()) {
this._translate(type);
@ -157,7 +157,6 @@ class Dish {
return this.value;
}
/**
* Sets the data value and type and then validates them.
*
@ -177,7 +176,9 @@ class Dish {
if (!this.valid()) {
const sample = Utils.truncate(JSON.stringify(this.value), 25);
throw new DishError(`Data is not a valid ${Dish.enumLookup(type)}: ${sample}`);
throw new DishError(
`Data is not a valid ${Dish.enumLookup(type)}: ${sample}`,
);
}
}
@ -196,7 +197,6 @@ class Dish {
return clone.get(type);
}
/**
* Detects the MIME type of the current dish
* @returns {string}
@ -205,14 +205,17 @@ class Dish {
const data = new Uint8Array(this.value.slice(0, 2048)),
types = detectFileType(data);
if (!types.length || !types[0].mime || !(types[0].mime === "text/plain")) {
if (
!types.length ||
!types[0].mime ||
!(types[0].mime === "text/plain")
) {
return null;
} else {
return types[0].mime;
}
}
/**
* Returns the title of the data up to the specified length
*
@ -248,7 +251,11 @@ class Dish {
cloned.value = cloned.value.slice(0, 256);
title = await cloned.get(Dish.STRING);
} catch (err) {
log.error(`${Dish.enumLookup(this.type)} cannot be sliced. ${err}`);
log.error(
`${Dish.enumLookup(
this.type,
)} cannot be sliced. ${err}`,
);
}
}
@ -264,15 +271,20 @@ class Dish {
valid() {
switch (this.type) {
case Dish.BYTE_ARRAY:
if (!(this.value instanceof Uint8Array) && !(this.value instanceof Array)) {
if (
!(this.value instanceof Uint8Array) &&
!(this.value instanceof Array)
) {
return false;
}
// Check that every value is a number between 0 - 255
for (let i = 0; i < this.value.length; i++) {
if (typeof this.value[i] !== "number" ||
if (
typeof this.value[i] !== "number" ||
this.value[i] < 0 ||
this.value[i] > 255) {
this.value[i] > 255
) {
return false;
}
}
@ -306,14 +318,18 @@ class Dish {
case Dish.FILE:
return this.value instanceof File;
case Dish.LIST_FILE:
return this.value instanceof Array &&
this.value.reduce((acc, curr) => acc && curr instanceof File, true);
return (
this.value instanceof Array &&
this.value.reduce(
(acc, curr) => acc && curr instanceof File,
true,
)
);
default:
return false;
}
}
/**
* Determines how much space the Dish takes up.
* Numbers in JavaScript are 64-bit floating point, however for the purposes of the Dish,
@ -343,7 +359,6 @@ class Dish {
}
}
/**
* Returns a deep clone of the current Dish.
*
@ -358,45 +373,37 @@ class Dish {
case Dish.NUMBER:
case Dish.BIG_NUMBER:
// These data types are immutable so it is acceptable to copy them by reference
newDish.set(
this.value,
this.type
);
newDish.set(this.value, this.type);
break;
case Dish.BYTE_ARRAY:
case Dish.JSON:
// These data types are mutable so they need to be copied by value
newDish.set(
JSON.parse(JSON.stringify(this.value)),
this.type
);
newDish.set(JSON.parse(JSON.stringify(this.value)), this.type);
break;
case Dish.ARRAY_BUFFER:
// Slicing an ArrayBuffer returns a new ArrayBuffer with a copy its contents
newDish.set(
this.value.slice(0),
this.type
);
newDish.set(this.value.slice(0), this.type);
break;
case Dish.FILE:
// A new file can be created by copying over all the values from the original
newDish.set(
new File([this.value], this.value.name, {
"type": this.value.type,
"lastModified": this.value.lastModified
type: this.value.type,
lastModified: this.value.lastModified,
}),
this.type
this.type,
);
break;
case Dish.LIST_FILE:
newDish.set(
this.value.map(f =>
this.value.map(
(f) =>
new File([f], f.name, {
"type": f.type,
"lastModified": f.lastModified
})
type: f.type,
lastModified: f.lastModified,
}),
),
this.type
this.type,
);
break;
default:
@ -415,7 +422,11 @@ class Dish {
* @returns {Promise || undefined}
*/
_translate(toType) {
log.debug(`Translating Dish from ${Dish.enumLookup(this.type)} to ${Dish.enumLookup(toType)}`);
log.debug(
`Translating Dish from ${Dish.enumLookup(
this.type,
)} to ${Dish.enumLookup(toType)}`,
);
// Node environment => translate is sync
if (isNodeEnvironment()) {
@ -427,7 +438,7 @@ class Dish {
} else {
return new Promise((resolve, reject) => {
this._toArrayBuffer()
.then(() => this.type = Dish.ARRAY_BUFFER)
.then(() => (this.type = Dish.ARRAY_BUFFER))
.then(() => {
this._fromArrayBuffer(toType);
resolve();
@ -435,7 +446,6 @@ class Dish {
.catch(reject);
});
}
}
/**
@ -449,33 +459,48 @@ class Dish {
// Using 'bind' here to allow this.value to be mutated within translation functions
const toByteArrayFuncs = {
browser: {
[Dish.STRING]: () => Promise.resolve(DishString.toArrayBuffer.bind(this)()),
[Dish.NUMBER]: () => Promise.resolve(DishNumber.toArrayBuffer.bind(this)()),
[Dish.HTML]: () => Promise.resolve(DishHTML.toArrayBuffer.bind(this)()),
[Dish.STRING]: () =>
Promise.resolve(DishString.toArrayBuffer.bind(this)()),
[Dish.NUMBER]: () =>
Promise.resolve(DishNumber.toArrayBuffer.bind(this)()),
[Dish.HTML]: () =>
Promise.resolve(DishHTML.toArrayBuffer.bind(this)()),
[Dish.ARRAY_BUFFER]: () => Promise.resolve(),
[Dish.BIG_NUMBER]: () => Promise.resolve(DishBigNumber.toArrayBuffer.bind(this)()),
[Dish.JSON]: () => Promise.resolve(DishJSON.toArrayBuffer.bind(this)()),
[Dish.BIG_NUMBER]: () =>
Promise.resolve(DishBigNumber.toArrayBuffer.bind(this)()),
[Dish.JSON]: () =>
Promise.resolve(DishJSON.toArrayBuffer.bind(this)()),
[Dish.FILE]: () => DishFile.toArrayBuffer.bind(this)(),
[Dish.LIST_FILE]: () => Promise.resolve(DishListFile.toArrayBuffer.bind(this)()),
[Dish.BYTE_ARRAY]: () => Promise.resolve(DishByteArray.toArrayBuffer.bind(this)()),
[Dish.LIST_FILE]: () =>
Promise.resolve(DishListFile.toArrayBuffer.bind(this)()),
[Dish.BYTE_ARRAY]: () =>
Promise.resolve(DishByteArray.toArrayBuffer.bind(this)()),
},
node: {
[Dish.STRING]: () => DishString.toArrayBuffer.bind(this)(),
[Dish.NUMBER]: () => DishNumber.toArrayBuffer.bind(this)(),
[Dish.HTML]: () => DishHTML.toArrayBuffer.bind(this)(),
[Dish.ARRAY_BUFFER]: () => {},
[Dish.BIG_NUMBER]: () => DishBigNumber.toArrayBuffer.bind(this)(),
[Dish.BIG_NUMBER]: () =>
DishBigNumber.toArrayBuffer.bind(this)(),
[Dish.JSON]: () => DishJSON.toArrayBuffer.bind(this)(),
[Dish.FILE]: () => DishFile.toArrayBuffer.bind(this)(),
[Dish.LIST_FILE]: () => DishListFile.toArrayBuffer.bind(this)(),
[Dish.BYTE_ARRAY]: () => DishByteArray.toArrayBuffer.bind(this)(),
}
[Dish.BYTE_ARRAY]: () =>
DishByteArray.toArrayBuffer.bind(this)(),
},
};
try {
return toByteArrayFuncs[isNodeEnvironment() && "node" || "browser"][this.type]();
return toByteArrayFuncs[
(isNodeEnvironment() && "node") || "browser"
][this.type]();
} catch (err) {
throw new DishError(`Error translating from ${Dish.enumLookup(this.type)} to ArrayBuffer: ${err}`);
throw new DishError(
`Error translating from ${Dish.enumLookup(
this.type,
)} to ArrayBuffer: ${err}`,
);
}
}
@ -485,7 +510,6 @@ class Dish {
* @param {number} toType - the Dish enum to convert to
*/
_fromArrayBuffer(toType) {
// Using 'bind' here to allow this.value to be mutated within translation functions
const toTypeFunctions = {
[Dish.STRING]: () => DishString.fromArrayBuffer.bind(this)(),
@ -503,13 +527,15 @@ class Dish {
toTypeFunctions[toType]();
this.type = toType;
} catch (err) {
throw new DishError(`Error translating from ArrayBuffer to ${Dish.enumLookup(toType)}: ${err}`);
throw new DishError(
`Error translating from ArrayBuffer to ${Dish.enumLookup(
toType,
)}: ${err}`,
);
}
}
}
/**
* Dish data type enum for byte arrays.
* @readonly
@ -565,5 +591,4 @@ Dish.FILE = 7;
*/
Dish.LIST_FILE = 8;
export default Dish;

View file

@ -11,7 +11,6 @@ import {fromHex} from "./lib/Hex.mjs";
* The arguments to operations.
*/
class Ingredient {
/**
* Ingredient constructor
*
@ -37,7 +36,6 @@ class Ingredient {
}
}
/**
* Reads and parses the given config.
*
@ -52,15 +50,20 @@ class Ingredient {
this.hint = ingredientConfig.hint || false;
this.rows = ingredientConfig.rows || false;
this.toggleValues = ingredientConfig.toggleValues;
this.target = typeof ingredientConfig.target !== "undefined" ? ingredientConfig.target : null;
this.defaultIndex = typeof ingredientConfig.defaultIndex !== "undefined" ? ingredientConfig.defaultIndex : 0;
this.target =
typeof ingredientConfig.target !== "undefined"
? ingredientConfig.target
: null;
this.defaultIndex =
typeof ingredientConfig.defaultIndex !== "undefined"
? ingredientConfig.defaultIndex
: 0;
this.maxLength = ingredientConfig.maxLength || null;
this.min = ingredientConfig.min;
this.max = ingredientConfig.max;
this.step = ingredientConfig.step;
}
/**
* Returns the value of the Ingredient as it should be displayed in a recipe config.
*
@ -70,7 +73,6 @@ class Ingredient {
return this._value;
}
/**
* Sets the value of the Ingredient.
*
@ -80,7 +82,6 @@ class Ingredient {
this._value = Ingredient.prepare(value, this.type);
}
/**
* Gets the value of the Ingredient.
*
@ -90,7 +91,6 @@ class Ingredient {
return this._value;
}
/**
* Most values will be strings when they are entered. This function converts them to the correct
* type.
@ -126,7 +126,6 @@ class Ingredient {
return data;
}
}
}
export default Ingredient;

View file

@ -11,7 +11,6 @@ import Ingredient from "./Ingredient.mjs";
* The Operation specified by the user to be run.
*/
class Operation {
/**
* Operation constructor
*/
@ -33,7 +32,6 @@ class Operation {
this.infoURL = null;
}
/**
* Interface for operation runner
*
@ -45,7 +43,6 @@ class Operation {
return input;
}
/**
* Interface for forward highlighter
*
@ -59,7 +56,6 @@ class Operation {
return false;
}
/**
* Interface for reverse highlighter
*
@ -73,7 +69,6 @@ class Operation {
return false;
}
/**
* Method to be called when displaying the result of an operation in a human-readable
* format. This allows operations to return usable data from their run() method and
@ -90,7 +85,6 @@ class Operation {
return data;
}
/**
* Sets the input type as a Dish enum.
*
@ -100,7 +94,6 @@ class Operation {
this._inputType = Dish.typeEnum(typeStr);
}
/**
* Gets the input type as a readable string.
*
@ -110,7 +103,6 @@ class Operation {
return Dish.enumLookup(this._inputType);
}
/**
* Sets the output type as a Dish enum.
*
@ -121,7 +113,6 @@ class Operation {
if (this._presentType < 0) this._presentType = this._outputType;
}
/**
* Gets the output type as a readable string.
*
@ -131,7 +122,6 @@ class Operation {
return Dish.enumLookup(this._outputType);
}
/**
* Sets the presentation type as a Dish enum.
*
@ -141,7 +131,6 @@ class Operation {
this._presentType = Dish.typeEnum(typeStr);
}
/**
* Gets the presentation type as a readable string.
*
@ -151,31 +140,29 @@ class Operation {
return Dish.enumLookup(this._presentType);
}
/**
* Sets the args for the current operation.
*
* @param {Object[]} conf
*/
set args(conf) {
conf.forEach(arg => {
conf.forEach((arg) => {
const ingredient = new Ingredient(arg);
this.addIngredient(ingredient);
});
}
/**
* Gets the args for the current operation.
*
* @param {Object[]} conf
*/
get args() {
return this._ingList.map(ing => {
return this._ingList.map((ing) => {
const conf = {
name: ing.name,
type: ing.type,
value: ing.defaultValue
value: ing.defaultValue,
};
if (ing.toggleValues) conf.toggleValues = ing.toggleValues;
@ -192,7 +179,6 @@ class Operation {
});
}
/**
* Returns the value of the Operation as it should be displayed in a recipe config.
*
@ -200,12 +186,11 @@ class Operation {
*/
get config() {
return {
"op": this.name,
"args": this._ingList.map(ing => ing.config)
op: this.name,
args: this._ingList.map((ing) => ing.config),
};
}
/**
* Adds a new Ingredient to this Operation.
*
@ -215,7 +200,6 @@ class Operation {
this._ingList.push(ingredient);
}
/**
* Set the Ingredient values for this Operation.
*
@ -227,17 +211,15 @@ class Operation {
});
}
/**
* Get the Ingredient values for this Operation.
*
* @returns {Object[]}
*/
get ingValues() {
return this._ingList.map(ing => ing.value);
return this._ingList.map((ing) => ing.value);
}
/**
* Set whether this Operation has a breakpoint.
*
@ -247,7 +229,6 @@ class Operation {
this._breakpoint = !!value;
}
/**
* Returns true if this Operation has a breakpoint set.
*
@ -257,7 +238,6 @@ class Operation {
return this._breakpoint;
}
/**
* Set whether this Operation is disabled.
*
@ -267,7 +247,6 @@ class Operation {
this._disabled = !!value;
}
/**
* Returns true if this Operation is disabled.
*
@ -277,7 +256,6 @@ class Operation {
return this._disabled;
}
/**
* Returns true if this Operation is a flow control.
*
@ -287,7 +265,6 @@ class Operation {
return this._flowControl;
}
/**
* Set whether this Operation is a flowcontrol op.
*
@ -297,7 +274,6 @@ class Operation {
this._flowControl = !!value;
}
/**
* Returns true if this Operation should not trigger AutoBake.
*
@ -307,7 +283,6 @@ class Operation {
return this._manualBake;
}
/**
* Set whether this Operation should trigger AutoBake.
*
@ -316,7 +291,6 @@ class Operation {
set manualBake(value) {
this._manualBake = !!value;
}
}
export default Operation;

View file

@ -4,7 +4,9 @@
* @license Apache-2.0
*/
import OperationConfig from "./config/OperationConfig.json" assert {type: "json"};
import OperationConfig from "./config/OperationConfig.json" assert {
type: "json",
};
import OperationError from "./errors/OperationError.mjs";
import Operation from "./Operation.mjs";
import DishError from "./errors/DishError.mjs";
@ -18,7 +20,6 @@ let modules = null;
* The Recipe controls a list of Operations and the Dish they operate on.
*/
class Recipe {
/**
* Recipe constructor
*
@ -32,7 +33,6 @@ class Recipe {
}
}
/**
* Reads and parses the given config.
*
@ -40,7 +40,7 @@ class Recipe {
* @param {Object} recipeConfig
*/
_parseConfig(recipeConfig) {
recipeConfig.forEach(c => {
recipeConfig.forEach((c) => {
this.opList.push({
name: c.op,
module: OperationConfig[c.op].module,
@ -51,7 +51,6 @@ class Recipe {
});
}
/**
* Populate elements of opList with operation instances.
* Dynamic import here removes top-level cyclic dependency issue.
@ -62,11 +61,13 @@ class Recipe {
if (!modules) {
// Using Webpack Magic Comments to force the dynamic import to be included in the main chunk
// https://webpack.js.org/api/module-methods/
modules = await import(/* webpackMode: "eager" */ "./config/modules/OpModules.mjs");
modules = await import(
/* webpackMode: "eager" */ "./config/modules/OpModules.mjs"
);
modules = modules.default;
}
this.opList = this.opList.map(o => {
this.opList = this.opList.map((o) => {
if (o instanceof Operation) {
return o;
} else {
@ -79,20 +80,18 @@ class Recipe {
});
}
/**
* Returns the value of the Recipe as it should be displayed in a recipe config.
*
* @returns {Object[]}
*/
get config() {
return this.opList.map(op => ({
return this.opList.map((op) => ({
op: op.name,
args: op.ingValues,
}));
}
/**
* Adds a new Operation to this Recipe.
*
@ -102,14 +101,13 @@ class Recipe {
this.opList.push(operation);
}
/**
* Adds a list of Operations to this Recipe.
*
* @param {Operation[]} operations
*/
addOperations(operations) {
operations.forEach(o => {
operations.forEach((o) => {
if (o instanceof Operation) {
this.opList.push(o);
} else {
@ -124,7 +122,6 @@ class Recipe {
});
}
/**
* Set a breakpoint on a specified Operation.
*
@ -139,7 +136,6 @@ class Recipe {
}
}
/**
* Remove breakpoints on all Operations in the Recipe up to the specified position. Used by Flow
* Control Fork operation.
@ -152,7 +148,6 @@ class Recipe {
}
}
/**
* Returns true if there is a Flow Control Operation in this Recipe.
*
@ -164,7 +159,6 @@ class Recipe {
}, false);
}
/**
* Executes each operation in the recipe over the given Dish.
*
@ -177,7 +171,9 @@ class Recipe {
* - The final progress through the recipe
*/
async execute(dish, startFrom = 0, forkState = {}) {
let op, input, output,
let op,
input,
output,
numJumps = 0,
numRegisters = forkState.numRegisters || 0;
@ -185,7 +181,9 @@ class Recipe {
await this._hydrateOpList();
log.debug(`[*] Executing recipe of ${this.opList.length} operations, starting at ${startFrom}`);
log.debug(
`[*] Executing recipe of ${this.opList.length} operations, starting at ${startFrom}`,
);
for (let i = startFrom; i < this.opList.length; i++) {
op = this.opList[i];
@ -204,19 +202,21 @@ class Recipe {
log.debug(`Executing operation '${op.name}'`);
if (isWorkerEnvironment()) {
self.sendStatusMessage(`Baking... (${i+1}/${this.opList.length})`);
self.sendStatusMessage(
`Baking... (${i + 1}/${this.opList.length})`,
);
self.sendProgressMessage(i + 1, this.opList.length);
}
if (op.flowControl) {
// Package up the current state
let state = {
"progress": i,
"dish": dish,
"opList": this.opList,
"numJumps": numJumps,
"numRegisters": numRegisters,
"forkOffset": forkState.forkOffset || 0
progress: i,
dish: dish,
opList: this.opList,
numJumps: numJumps,
numRegisters: numRegisters,
forkOffset: forkState.forkOffset || 0,
};
state = await op.run(state);
@ -230,12 +230,18 @@ class Recipe {
this.lastRunOp = op;
} catch (err) {
// Return expected errors as output
if (err instanceof OperationError || err?.type === "OperationError") {
if (
err instanceof OperationError ||
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 if (err instanceof DishError || err?.type === "DishError") {
} else if (
err instanceof DishError ||
err?.type === "DishError"
) {
dish.set(err.message, "string");
return i;
} else {
@ -243,10 +249,15 @@ class Recipe {
e.progress = i;
if (e.fileName) {
e.displayStr = `${op.name} - ${e.name} in ${e.fileName} on line ` +
`${e.lineNumber}.<br><br>Message: ${e.displayStr || e.message}`;
e.displayStr =
`${op.name} - ${e.name} in ${e.fileName} on line ` +
`${e.lineNumber}.<br><br>Message: ${
e.displayStr || e.message
}`;
} else {
e.displayStr = `${op.name} - ${e.displayStr || e.message}`;
e.displayStr = `${op.name} - ${
e.displayStr || e.message
}`;
}
throw e;
@ -258,7 +269,6 @@ class Recipe {
return this.opList.length;
}
/**
* Present the results of the final operation.
*
@ -269,12 +279,11 @@ class Recipe {
const output = await this.lastRunOp.present(
await dish.get(this.lastRunOp.outputType),
this.lastRunOp.ingValues
this.lastRunOp.ingValues,
);
dish.set(output, this.lastRunOp.presentType);
}
/**
* Returns the recipe configuration in string format.
*
@ -284,7 +293,6 @@ class Recipe {
return JSON.stringify(this.config);
}
/**
* Creates a Recipe from a given configuration string.
*
@ -295,7 +303,6 @@ class Recipe {
this._parseConfig(recipeConfig);
}
/**
* Generates a list of all the highlight functions assigned to operations in the recipe, if the
* entire recipe supports highlighting.
@ -317,19 +324,19 @@ class Recipe {
if (op.breakpoint) return false;
// If any of the operations do not support highlighting, fail immediately.
if (op.highlight === false || op.highlight === undefined) return false;
if (op.highlight === false || op.highlight === undefined)
return false;
highlights.push({
f: op.highlight,
b: op.highlightReverse,
args: op.ingValues
args: op.ingValues,
});
}
return highlights;
}
/**
* Determines whether the previous operation has a different presentation type to its normal output.
*
@ -338,9 +345,11 @@ class Recipe {
*/
lastOpPresented(progress) {
if (progress < 1) return false;
return this.opList[progress-1].presentType !== this.opList[progress-1].outputType;
return (
this.opList[progress - 1].presentType !==
this.opList[progress - 1].outputType
);
}
}
export default Recipe;

View file

@ -16,7 +16,6 @@ import {fromBinary} from "./lib/Binary.mjs";
* Utility functions for use in operations, the core framework and the stage.
*/
class Utils {
/**
* Translates an ordinal into a character.
*
@ -33,15 +32,14 @@ class Utils {
// https://mathiasbynens.be/notes/javascript-unicode
if (o > 0xffff) {
o -= 0x10000;
const high = String.fromCharCode(o >>> 10 & 0x3ff | 0xd800);
o = 0xdc00 | o & 0x3ff;
const high = String.fromCharCode(((o >>> 10) & 0x3ff) | 0xd800);
o = 0xdc00 | (o & 0x3ff);
return high + String.fromCharCode(o);
}
return String.fromCharCode(o);
}
/**
* Translates a character into an ordinal.
*
@ -59,8 +57,12 @@ class Utils {
if (c.length === 2) {
const high = c.charCodeAt(0);
const low = c.charCodeAt(1);
if (high >= 0xd800 && high < 0xdc00 &&
low >= 0xdc00 && low < 0xe000) {
if (
high >= 0xd800 &&
high < 0xdc00 &&
low >= 0xdc00 &&
low < 0xe000
) {
return (high - 0xd800) * 0x400 + low - 0xdc00 + 0x10000;
}
}
@ -68,7 +70,6 @@ class Utils {
return c.charCodeAt(0);
}
/**
* Adds trailing bytes to a byteArray.
*
@ -103,7 +104,6 @@ class Utils {
return paddedBytes;
}
/**
* Truncates a long string to max length and adds suffix.
*
@ -126,7 +126,6 @@ class Utils {
return str;
}
/**
* Converts a character or number to its hex representation.
*
@ -146,7 +145,6 @@ class Utils {
return c.toString(16).padStart(length, "0");
}
/**
* Converts a character or number to its binary representation.
*
@ -166,7 +164,6 @@ class Utils {
return c.toString(2).padStart(length, "0");
}
/**
* Returns a string with all non-printable chars as dots, optionally preserving whitespace.
*
@ -181,7 +178,8 @@ class Utils {
}
// eslint-disable-next-line no-misleading-character-class
const re = /[\0-\x08\x0B-\x0C\x0E-\x1F\x7F-\x9F\xAD\u0378\u0379\u037F-\u0383\u038B\u038D\u03A2\u0528-\u0530\u0557\u0558\u0560\u0588\u058B-\u058E\u0590\u05C8-\u05CF\u05EB-\u05EF\u05F5-\u0605\u061C\u061D\u06DD\u070E\u070F\u074B\u074C\u07B2-\u07BF\u07FB-\u07FF\u082E\u082F\u083F\u085C\u085D\u085F-\u089F\u08A1\u08AD-\u08E3\u08FF\u0978\u0980\u0984\u098D\u098E\u0991\u0992\u09A9\u09B1\u09B3-\u09B5\u09BA\u09BB\u09C5\u09C6\u09C9\u09CA\u09CF-\u09D6\u09D8-\u09DB\u09DE\u09E4\u09E5\u09FC-\u0A00\u0A04\u0A0B-\u0A0E\u0A11\u0A12\u0A29\u0A31\u0A34\u0A37\u0A3A\u0A3B\u0A3D\u0A43-\u0A46\u0A49\u0A4A\u0A4E-\u0A50\u0A52-\u0A58\u0A5D\u0A5F-\u0A65\u0A76-\u0A80\u0A84\u0A8E\u0A92\u0AA9\u0AB1\u0AB4\u0ABA\u0ABB\u0AC6\u0ACA\u0ACE\u0ACF\u0AD1-\u0ADF\u0AE4\u0AE5\u0AF2-\u0B00\u0B04\u0B0D\u0B0E\u0B11\u0B12\u0B29\u0B31\u0B34\u0B3A\u0B3B\u0B45\u0B46\u0B49\u0B4A\u0B4E-\u0B55\u0B58-\u0B5B\u0B5E\u0B64\u0B65\u0B78-\u0B81\u0B84\u0B8B-\u0B8D\u0B91\u0B96-\u0B98\u0B9B\u0B9D\u0BA0-\u0BA2\u0BA5-\u0BA7\u0BAB-\u0BAD\u0BBA-\u0BBD\u0BC3-\u0BC5\u0BC9\u0BCE\u0BCF\u0BD1-\u0BD6\u0BD8-\u0BE5\u0BFB-\u0C00\u0C04\u0C0D\u0C11\u0C29\u0C34\u0C3A-\u0C3C\u0C45\u0C49\u0C4E-\u0C54\u0C57\u0C5A-\u0C5F\u0C64\u0C65\u0C70-\u0C77\u0C80\u0C81\u0C84\u0C8D\u0C91\u0CA9\u0CB4\u0CBA\u0CBB\u0CC5\u0CC9\u0CCE-\u0CD4\u0CD7-\u0CDD\u0CDF\u0CE4\u0CE5\u0CF0\u0CF3-\u0D01\u0D04\u0D0D\u0D11\u0D3B\u0D3C\u0D45\u0D49\u0D4F-\u0D56\u0D58-\u0D5F\u0D64\u0D65\u0D76-\u0D78\u0D80\u0D81\u0D84\u0D97-\u0D99\u0DB2\u0DBC\u0DBE\u0DBF\u0DC7-\u0DC9\u0DCB-\u0DCE\u0DD5\u0DD7\u0DE0-\u0DF1\u0DF5-\u0E00\u0E3B-\u0E3E\u0E5C-\u0E80\u0E83\u0E85\u0E86\u0E89\u0E8B\u0E8C\u0E8E-\u0E93\u0E98\u0EA0\u0EA4\u0EA6\u0EA8\u0EA9\u0EAC\u0EBA\u0EBE\u0EBF\u0EC5\u0EC7\u0ECE\u0ECF\u0EDA\u0EDB\u0EE0-\u0EFF\u0F48\u0F6D-\u0F70\u0F98\u0FBD\u0FCD\u0FDB-\u0FFF\u10C6\u10C8-\u10CC\u10CE\u10CF\u1249\u124E\u124F\u1257\u1259\u125E\u125F\u1289\u128E\u128F\u12B1\u12B6\u12B7\u12BF\u12C1\u12C6\u12C7\u12D7\u1311\u1316\u1317\u135B\u135C\u137D-\u137F\u139A-\u139F\u13F5-\u13FF\u169D-\u169F\u16F1-\u16FF\u170D\u1715-\u171F\u1737-\u173F\u1754-\u175F\u176D\u1771\u1774-\u177F\u17DE\u17DF\u17EA-\u17EF\u17FA-\u17FF\u180F\u181A-\u181F\u1878-\u187F\u18AB-\u18AF\u18F6-\u18FF\u191D-\u191F\u192C-\u192F\u193C-\u193F\u1941-\u1943\u196E\u196F\u1975-\u197F\u19AC-\u19AF\u19CA-\u19CF\u19DB-\u19DD\u1A1C\u1A1D\u1A5F\u1A7D\u1A7E\u1A8A-\u1A8F\u1A9A-\u1A9F\u1AAE-\u1AFF\u1B4C-\u1B4F\u1B7D-\u1B7F\u1BF4-\u1BFB\u1C38-\u1C3A\u1C4A-\u1C4C\u1C80-\u1CBF\u1CC8-\u1CCF\u1CF7-\u1CFF\u1DE7-\u1DFB\u1F16\u1F17\u1F1E\u1F1F\u1F46\u1F47\u1F4E\u1F4F\u1F58\u1F5A\u1F5C\u1F5E\u1F7E\u1F7F\u1FB5\u1FC5\u1FD4\u1FD5\u1FDC\u1FF0\u1FF1\u1FF5\u1FFF\u200B-\u200F\u202A-\u202E\u2060-\u206F\u2072\u2073\u208F\u209D-\u209F\u20BB-\u20CF\u20F1-\u20FF\u218A-\u218F\u23F4-\u23FF\u2427-\u243F\u244B-\u245F\u2700\u2B4D-\u2B4F\u2B5A-\u2BFF\u2C2F\u2C5F\u2CF4-\u2CF8\u2D26\u2D28-\u2D2C\u2D2E\u2D2F\u2D68-\u2D6E\u2D71-\u2D7E\u2D97-\u2D9F\u2DA7\u2DAF\u2DB7\u2DBF\u2DC7\u2DCF\u2DD7\u2DDF\u2E3C-\u2E7F\u2E9A\u2EF4-\u2EFF\u2FD6-\u2FEF\u2FFC-\u2FFF\u3040\u3097\u3098\u3100-\u3104\u312E-\u3130\u318F\u31BB-\u31BF\u31E4-\u31EF\u321F\u32FF\u4DB6-\u4DBF\u9FCD-\u9FFF\uA48D-\uA48F\uA4C7-\uA4CF\uA62C-\uA63F\uA698-\uA69E\uA6F8-\uA6FF\uA78F\uA794-\uA79F\uA7AB-\uA7F7\uA82C-\uA82F\uA83A-\uA83F\uA878-\uA87F\uA8C5-\uA8CD\uA8DA-\uA8DF\uA8FC-\uA8FF\uA954-\uA95E\uA97D-\uA97F\uA9CE\uA9DA-\uA9DD\uA9E0-\uA9FF\uAA37-\uAA3F\uAA4E\uAA4F\uAA5A\uAA5B\uAA7C-\uAA7F\uAAC3-\uAADA\uAAF7-\uAB00\uAB07\uAB08\uAB0F\uAB10\uAB17-\uAB1F\uAB27\uAB2F-\uABBF\uABEE\uABEF\uABFA-\uABFF\uD7A4-\uD7AF\uD7C7-\uD7CA\uD7FC-\uD7FF\uE000-\uF8FF\uFA6E\uFA6F\uFADA-\uFAFF\uFB07-\uFB12\uFB18-\uFB1C\uFB37\uFB3D\uFB3F\uFB42\uFB45\uFBC2-\uFBD2\uFD40-\uFD4F\uFD90\uFD91\uFDC8-\uFDEF\uFDFE\uFDFF\uFE1A-\uFE1F\uFE27-\uFE2F\uFE53\uFE67\uFE6C-\uFE6F\uFE75\uFEFD-\uFF00\uFFBF-\uFFC1\uFFC8\uFFC9\uFFD0\uFFD1\uFFD8\uFFD9\uFFDD-\uFFDF\uFFE7\uFFEF-\uFFFB\uFFFE\uFFFF]/g;
const re =
/[\0-\x08\x0B-\x0C\x0E-\x1F\x7F-\x9F\xAD\u0378\u0379\u037F-\u0383\u038B\u038D\u03A2\u0528-\u0530\u0557\u0558\u0560\u0588\u058B-\u058E\u0590\u05C8-\u05CF\u05EB-\u05EF\u05F5-\u0605\u061C\u061D\u06DD\u070E\u070F\u074B\u074C\u07B2-\u07BF\u07FB-\u07FF\u082E\u082F\u083F\u085C\u085D\u085F-\u089F\u08A1\u08AD-\u08E3\u08FF\u0978\u0980\u0984\u098D\u098E\u0991\u0992\u09A9\u09B1\u09B3-\u09B5\u09BA\u09BB\u09C5\u09C6\u09C9\u09CA\u09CF-\u09D6\u09D8-\u09DB\u09DE\u09E4\u09E5\u09FC-\u0A00\u0A04\u0A0B-\u0A0E\u0A11\u0A12\u0A29\u0A31\u0A34\u0A37\u0A3A\u0A3B\u0A3D\u0A43-\u0A46\u0A49\u0A4A\u0A4E-\u0A50\u0A52-\u0A58\u0A5D\u0A5F-\u0A65\u0A76-\u0A80\u0A84\u0A8E\u0A92\u0AA9\u0AB1\u0AB4\u0ABA\u0ABB\u0AC6\u0ACA\u0ACE\u0ACF\u0AD1-\u0ADF\u0AE4\u0AE5\u0AF2-\u0B00\u0B04\u0B0D\u0B0E\u0B11\u0B12\u0B29\u0B31\u0B34\u0B3A\u0B3B\u0B45\u0B46\u0B49\u0B4A\u0B4E-\u0B55\u0B58-\u0B5B\u0B5E\u0B64\u0B65\u0B78-\u0B81\u0B84\u0B8B-\u0B8D\u0B91\u0B96-\u0B98\u0B9B\u0B9D\u0BA0-\u0BA2\u0BA5-\u0BA7\u0BAB-\u0BAD\u0BBA-\u0BBD\u0BC3-\u0BC5\u0BC9\u0BCE\u0BCF\u0BD1-\u0BD6\u0BD8-\u0BE5\u0BFB-\u0C00\u0C04\u0C0D\u0C11\u0C29\u0C34\u0C3A-\u0C3C\u0C45\u0C49\u0C4E-\u0C54\u0C57\u0C5A-\u0C5F\u0C64\u0C65\u0C70-\u0C77\u0C80\u0C81\u0C84\u0C8D\u0C91\u0CA9\u0CB4\u0CBA\u0CBB\u0CC5\u0CC9\u0CCE-\u0CD4\u0CD7-\u0CDD\u0CDF\u0CE4\u0CE5\u0CF0\u0CF3-\u0D01\u0D04\u0D0D\u0D11\u0D3B\u0D3C\u0D45\u0D49\u0D4F-\u0D56\u0D58-\u0D5F\u0D64\u0D65\u0D76-\u0D78\u0D80\u0D81\u0D84\u0D97-\u0D99\u0DB2\u0DBC\u0DBE\u0DBF\u0DC7-\u0DC9\u0DCB-\u0DCE\u0DD5\u0DD7\u0DE0-\u0DF1\u0DF5-\u0E00\u0E3B-\u0E3E\u0E5C-\u0E80\u0E83\u0E85\u0E86\u0E89\u0E8B\u0E8C\u0E8E-\u0E93\u0E98\u0EA0\u0EA4\u0EA6\u0EA8\u0EA9\u0EAC\u0EBA\u0EBE\u0EBF\u0EC5\u0EC7\u0ECE\u0ECF\u0EDA\u0EDB\u0EE0-\u0EFF\u0F48\u0F6D-\u0F70\u0F98\u0FBD\u0FCD\u0FDB-\u0FFF\u10C6\u10C8-\u10CC\u10CE\u10CF\u1249\u124E\u124F\u1257\u1259\u125E\u125F\u1289\u128E\u128F\u12B1\u12B6\u12B7\u12BF\u12C1\u12C6\u12C7\u12D7\u1311\u1316\u1317\u135B\u135C\u137D-\u137F\u139A-\u139F\u13F5-\u13FF\u169D-\u169F\u16F1-\u16FF\u170D\u1715-\u171F\u1737-\u173F\u1754-\u175F\u176D\u1771\u1774-\u177F\u17DE\u17DF\u17EA-\u17EF\u17FA-\u17FF\u180F\u181A-\u181F\u1878-\u187F\u18AB-\u18AF\u18F6-\u18FF\u191D-\u191F\u192C-\u192F\u193C-\u193F\u1941-\u1943\u196E\u196F\u1975-\u197F\u19AC-\u19AF\u19CA-\u19CF\u19DB-\u19DD\u1A1C\u1A1D\u1A5F\u1A7D\u1A7E\u1A8A-\u1A8F\u1A9A-\u1A9F\u1AAE-\u1AFF\u1B4C-\u1B4F\u1B7D-\u1B7F\u1BF4-\u1BFB\u1C38-\u1C3A\u1C4A-\u1C4C\u1C80-\u1CBF\u1CC8-\u1CCF\u1CF7-\u1CFF\u1DE7-\u1DFB\u1F16\u1F17\u1F1E\u1F1F\u1F46\u1F47\u1F4E\u1F4F\u1F58\u1F5A\u1F5C\u1F5E\u1F7E\u1F7F\u1FB5\u1FC5\u1FD4\u1FD5\u1FDC\u1FF0\u1FF1\u1FF5\u1FFF\u200B-\u200F\u202A-\u202E\u2060-\u206F\u2072\u2073\u208F\u209D-\u209F\u20BB-\u20CF\u20F1-\u20FF\u218A-\u218F\u23F4-\u23FF\u2427-\u243F\u244B-\u245F\u2700\u2B4D-\u2B4F\u2B5A-\u2BFF\u2C2F\u2C5F\u2CF4-\u2CF8\u2D26\u2D28-\u2D2C\u2D2E\u2D2F\u2D68-\u2D6E\u2D71-\u2D7E\u2D97-\u2D9F\u2DA7\u2DAF\u2DB7\u2DBF\u2DC7\u2DCF\u2DD7\u2DDF\u2E3C-\u2E7F\u2E9A\u2EF4-\u2EFF\u2FD6-\u2FEF\u2FFC-\u2FFF\u3040\u3097\u3098\u3100-\u3104\u312E-\u3130\u318F\u31BB-\u31BF\u31E4-\u31EF\u321F\u32FF\u4DB6-\u4DBF\u9FCD-\u9FFF\uA48D-\uA48F\uA4C7-\uA4CF\uA62C-\uA63F\uA698-\uA69E\uA6F8-\uA6FF\uA78F\uA794-\uA79F\uA7AB-\uA7F7\uA82C-\uA82F\uA83A-\uA83F\uA878-\uA87F\uA8C5-\uA8CD\uA8DA-\uA8DF\uA8FC-\uA8FF\uA954-\uA95E\uA97D-\uA97F\uA9CE\uA9DA-\uA9DD\uA9E0-\uA9FF\uAA37-\uAA3F\uAA4E\uAA4F\uAA5A\uAA5B\uAA7C-\uAA7F\uAAC3-\uAADA\uAAF7-\uAB00\uAB07\uAB08\uAB0F\uAB10\uAB17-\uAB1F\uAB27\uAB2F-\uABBF\uABEE\uABEF\uABFA-\uABFF\uD7A4-\uD7AF\uD7C7-\uD7CA\uD7FC-\uD7FF\uE000-\uF8FF\uFA6E\uFA6F\uFADA-\uFAFF\uFB07-\uFB12\uFB18-\uFB1C\uFB37\uFB3D\uFB3F\uFB42\uFB45\uFBC2-\uFBD2\uFD40-\uFD4F\uFD90\uFD91\uFDC8-\uFDEF\uFDFE\uFDFF\uFE1A-\uFE1F\uFE27-\uFE2F\uFE53\uFE67\uFE6C-\uFE6F\uFE75\uFEFD-\uFF00\uFFBF-\uFFC1\uFFC8\uFFC9\uFFD0\uFFD1\uFFD8\uFFD9\uFFDD-\uFFDF\uFFE7\uFFEF-\uFFFB\uFFFE\uFFFF]/g;
const wsRe = /[\x09-\x10\u2028\u2029]/g;
str = str.replace(re, ".");
@ -189,7 +187,6 @@ class Utils {
return str;
}
/**
* Returns a string with whitespace represented as special characters from the
* Unicode Private Use Area, which CyberChef will display as control characters.
@ -204,7 +201,6 @@ class Utils {
});
}
/**
* Parse a string entered by a user and replace escaped chars with the bytes they represent.
*
@ -219,7 +215,9 @@ class Utils {
* Utils.parseEscapedChars("\\n");
*/
static parseEscapedChars(str) {
return str.replace(/\\([abfnrtv'"]|[0-3][0-7]{2}|[0-7]{1,2}|x[\da-fA-F]{2}|u[\da-fA-F]{4}|u\{[\da-fA-F]{1,6}\}|\\)/g, function(m, a) {
return str.replace(
/\\([abfnrtv'"]|[0-3][0-7]{2}|[0-7]{1,2}|x[\da-fA-F]{2}|u[\da-fA-F]{4}|u\{[\da-fA-F]{1,6}\}|\\)/g,
function (m, a) {
switch (a[0]) {
case "\\":
return "\\";
@ -254,14 +252,18 @@ class Utils {
return String.fromCharCode(parseInt(a.substr(1), 16));
case "u":
if (a[1] === "{")
return String.fromCodePoint(parseInt(a.slice(2, -1), 16));
return String.fromCodePoint(
parseInt(a.slice(2, -1), 16),
);
else
return String.fromCharCode(parseInt(a.substr(1), 16));
return String.fromCharCode(
parseInt(a.substr(1), 16),
);
}
});
},
);
}
/**
* Escape a string containing regex control characters so that it can be safely
* used in a regex without causing unintended behaviours.
@ -277,7 +279,6 @@ class Utils {
return str.replace(/([.*+?^=!:${}()|[\]/\\])/g, "\\$1");
}
/**
* Expand an alphabet range string into a list of the characters in that range.
*
@ -298,9 +299,11 @@ class Utils {
const alphArr = [];
for (let i = 0; i < alphStr.length; i++) {
if (i < alphStr.length - 2 &&
if (
i < alphStr.length - 2 &&
alphStr[i + 1] === "-" &&
alphStr[i] !== "\\") {
alphStr[i] !== "\\"
) {
const start = Utils.ord(alphStr[i]),
end = Utils.ord(alphStr[i + 2]);
@ -308,9 +311,11 @@ class Utils {
alphArr.push(Utils.chr(j));
}
i += 2;
} else if (i < alphStr.length - 2 &&
} else if (
i < alphStr.length - 2 &&
alphStr[i] === "\\" &&
alphStr[i+1] === "-") {
alphStr[i + 1] === "-"
) {
alphArr.push("-");
i++;
} else {
@ -320,7 +325,6 @@ class Utils {
return alphArr;
}
/**
* Coverts data of varying types to a byteArray.
* Accepts hex, Base64, UTF8 and Latin1 strings.
@ -357,7 +361,6 @@ class Utils {
}
}
/**
* Coverts data of varying types to a byte string.
* Accepts hex, Base64, UTF8 and Latin1 strings.
@ -385,7 +388,9 @@ class Utils {
case "decimal":
return Utils.byteArrayToChars(fromDecimal(str));
case "base64":
return Utils.byteArrayToChars(fromBase64(str, null, "byteArray"));
return Utils.byteArrayToChars(
fromBase64(str, null, "byteArray"),
);
case "utf8":
return utf8.encode(str);
case "latin1":
@ -394,7 +399,6 @@ class Utils {
}
}
/**
* Converts a byte array to an integer.
*
@ -413,17 +417,16 @@ class Utils {
let value = 0;
if (byteorder === "big") {
for (let i = 0; i < byteArray.length; i++) {
value = (value * 256) + byteArray[i];
value = value * 256 + byteArray[i];
}
} else {
for (let i = byteArray.length - 1; i >= 0; i--) {
value = (value * 256) + byteArray[i];
value = value * 256 + byteArray[i];
}
}
return value;
}
/**
* Converts an integer to a byte array of {length} bytes.
*
@ -446,19 +449,18 @@ class Utils {
const arr = new Array(length);
if (byteorder === "little") {
for (let i = 0; i < length; i++) {
arr[i] = value & 0xFF;
arr[i] = value & 0xff;
value = value >>> 8;
}
} else {
for (let i = length - 1; i >= 0; i--) {
arr[i] = value & 0xFF;
arr[i] = value & 0xff;
value = value >>> 8;
}
}
return arr;
}
/**
* Converts a string to an ArrayBuffer.
* Treats the string as UTF-8 if any values are over 255.
@ -475,10 +477,11 @@ class Utils {
*/
static strToArrayBuffer(str) {
log.debug(`Converting string[${str?.length}] to array buffer`);
if (!str) return new ArrayBuffer;
if (!str) return new ArrayBuffer();
const arr = new Uint8Array(str.length);
let i = str.length, b;
let i = str.length,
b;
while (i--) {
b = str.charCodeAt(i);
arr[i] = b;
@ -488,7 +491,6 @@ class Utils {
return arr.buffer;
}
/**
* Converts a string to a UTF-8 ArrayBuffer.
*
@ -504,12 +506,16 @@ class Utils {
*/
static strToUtf8ArrayBuffer(str) {
log.debug(`Converting string[${str?.length}] to UTF8 array buffer`);
if (!str) return new ArrayBuffer;
if (!str) return new ArrayBuffer();
const buffer = new TextEncoder("utf-8").encode(str);
if (str.length !== buffer.length) {
if (isWorkerEnvironment() && self && typeof self.setOption === "function") {
if (
isWorkerEnvironment() &&
self &&
typeof self.setOption === "function"
) {
self.setOption("attemptHighlight", false);
} else if (isWebEnvironment()) {
window.app.options.attemptHighlight = false;
@ -519,7 +525,6 @@ class Utils {
return buffer.buffer;
}
/**
* Converts a string to a byte array.
* Treats the string as UTF-8 if any values are over 255.
@ -538,7 +543,8 @@ class Utils {
log.debug(`Converting string[${str?.length}] to byte array`);
if (!str) return [];
const byteArray = new Array(str.length);
let i = str.length, b;
let i = str.length,
b;
while (i--) {
b = str.charCodeAt(i);
byteArray[i] = b;
@ -548,7 +554,6 @@ class Utils {
return byteArray;
}
/**
* Converts a string to a UTF-8 byte array.
*
@ -578,7 +583,6 @@ class Utils {
return Utils.strToByteArray(utf8Str);
}
/**
* Converts a string to a unicode charcode array
*
@ -614,7 +618,6 @@ class Utils {
return charcode;
}
/**
* Attempts to convert a byte array to a UTF-8 string.
*
@ -635,7 +638,9 @@ class Utils {
byteArray = new Uint8Array(byteArray);
try {
const str = new TextDecoder("utf-8", {fatal: true}).decode(byteArray);
const str = new TextDecoder("utf-8", { fatal: true }).decode(
byteArray,
);
if (str.length !== byteArray.length) {
if (isWorkerEnvironment()) {
@ -652,7 +657,6 @@ class Utils {
}
}
/**
* Converts a charcode array to a string.
*
@ -673,12 +677,11 @@ class Utils {
// Maxiumum arg length for fromCharCode is 65535, but the stack may already be fairly deep,
// so don't get too near it.
for (let i = 0; i < byteArray.length; i += 20000) {
str += String.fromCharCode(...(byteArray.slice(i, i+20000)));
str += String.fromCharCode(...byteArray.slice(i, i + 20000));
}
return str;
}
/**
* Converts an ArrayBuffer to a string.
*
@ -729,13 +732,12 @@ class Utils {
for (i = 0; i < prob.length; i++) {
p = prob[i];
entropy += p * Math.log(p) / Math.log(2);
entropy += (p * Math.log(p)) / Math.log(2);
}
return -entropy;
}
/**
* Parses CSV data and returns it as a two dimensional array or strings.
*
@ -766,10 +768,10 @@ class Utils {
if (renderNext) {
cell += b;
renderNext = false;
} else if (b === "\"" && !inString) {
} else if (b === '"' && !inString) {
inString = true;
} else if (b === "\"" && inString) {
if (next === "\"") renderNext = true;
} else if (b === '"' && inString) {
if (next === '"') renderNext = true;
else inString = false;
} else if (!inString && cellDelims.indexOf(b) >= 0) {
line.push(cell);
@ -796,7 +798,6 @@ class Utils {
return lines;
}
/**
* Removes all HTML (or XML) tags from the input string.
*
@ -820,17 +821,24 @@ class Utils {
*/
function recursiveRemove(pattern, str) {
const newStr = str.replace(pattern, "");
return newStr.length === str.length ? newStr : recursiveRemove(pattern, newStr);
return newStr.length === str.length
? newStr
: recursiveRemove(pattern, newStr);
}
if (removeScriptAndStyle) {
htmlStr = recursiveRemove(/<script[^>]*>(\s|\S)*?<\/script[^>]*>/gi, htmlStr);
htmlStr = recursiveRemove(/<style[^>]*>(\s|\S)*?<\/style[^>]*>/gi, htmlStr);
htmlStr = recursiveRemove(
/<script[^>]*>(\s|\S)*?<\/script[^>]*>/gi,
htmlStr,
);
htmlStr = recursiveRemove(
/<style[^>]*>(\s|\S)*?<\/style[^>]*>/gi,
htmlStr,
);
}
return recursiveRemove(/<[^>]+>/g, htmlStr);
}
/**
* Escapes HTML tags in a string to stop them being rendered.
* https://www.owasp.org/index.php/XSS_(Cross_Site_Scripting)_Prevention_Cheat_Sheet
@ -855,15 +863,16 @@ class Utils {
'"': "&quot;",
"'": "&#x27;", // &apos; not recommended because it's not in the HTML spec
"`": "&#x60;",
"\u0000": "\ue000"
"\u0000": "\ue000",
};
return str ? str.replace(/[&<>"'`\u0000]/g, function (match) {
return str
? str.replace(/[&<>"'`\u0000]/g, function (match) {
return HTML_CHARS[match];
}) : str;
})
: str;
}
/**
* Unescapes HTML tags in a string to make them render again.
*
@ -883,15 +892,14 @@ class Utils {
"&#x27;": "'",
"&#x2F;": "/",
"&#x60;": "`",
"\ue000": "\u0000"
"\ue000": "\u0000",
};
return str.replace(/(&#?x?[a-z0-9]{2,4};|\ue000)/ig, function (match) {
return str.replace(/(&#?x?[a-z0-9]{2,4};|\ue000)/gi, function (match) {
return HTML_CHARS[match] || match;
});
}
/**
* Converts a string to it's title case equivalent.
*
@ -908,7 +916,6 @@ class Utils {
});
}
/**
* Encodes a URI fragment (#) or query (?) using a minimal amount of percent-encoding.
*
@ -951,7 +958,7 @@ class Utils {
"%3A": ":",
"%40": "@",
"%2F": "/",
"%3F": "?"
"%3F": "?",
};
str = encodeURIComponent(str);
@ -960,7 +967,6 @@ class Utils {
});
}
/**
* Generates a "pretty" recipe format from a recipeConfig object.
*
@ -982,7 +988,7 @@ class Utils {
disabled = "",
bp = "";
recipeConfig.forEach(op => {
recipeConfig.forEach((op) => {
name = op.op.replace(/ /g, "_");
args = JSON.stringify(op.args)
.slice(1, -1) // Remove [ and ] as they are implied
@ -1000,7 +1006,6 @@ class Utils {
return prettyConfig;
}
/**
* Converts a recipe string to the JSON representation of the recipe.
* Accepts either stringified JSON or the bespoke "pretty" recipe format.
@ -1016,7 +1021,8 @@ class Utils {
// Parse bespoke recipe format
recipe = recipe.replace(/\n/g, "");
let m, args;
const recipeRegex = /([^(]+)\(((?:'[^'\\]*(?:\\.[^'\\]*)*'|[^)/'])*)(\/[^)]+)?\)/g,
const recipeRegex =
/([^(]+)\(((?:'[^'\\]*(?:\\.[^'\\]*)*'|[^)/'])*)(\/[^)]+)?\)/g,
recipeConfig = [];
while ((m = recipeRegex.exec(recipe))) {
@ -1030,7 +1036,7 @@ class Utils {
const op = {
op: m[1].replace(/_/g, " "),
args: JSON.parse(args)
args: JSON.parse(args),
};
if (m[3] && m[3].indexOf("disabled") > 0) op.disabled = true;
if (m[3] && m[3].indexOf("breakpoint") > 0) op.breakpoint = true;
@ -1039,7 +1045,6 @@ class Utils {
return recipeConfig;
}
/**
* Formats a list of files or directories.
*
@ -1068,16 +1073,17 @@ class Utils {
dataURI += "base64," + toBase64(buff);
return "<img style='max-width: 100%;' src='" + dataURI + "'>";
} else {
return `<pre>${Utils.escapeHtml(Utils.arrayBufferToStr(buff.buffer))}</pre>`;
return `<pre>${Utils.escapeHtml(
Utils.arrayBufferToStr(buff.buffer),
)}</pre>`;
}
};
const formatFile = async function (file, i) {
const buff = await Utils.readFile(file);
const blob = new Blob(
[buff],
{type: file.type || "octet/stream"}
);
const blob = new Blob([buff], {
type: file.type || "octet/stream",
});
const blobURL = URL.createObjectURL(blob);
const html = `<div class='card' style='white-space: normal;'>
@ -1088,11 +1094,15 @@ class Utils {
href='#collapse${i}'
aria-expanded='false'
aria-controls='collapse${i}'
title="Show/hide contents of '${Utils.escapeHtml(file.name)}'">
title="Show/hide contents of '${Utils.escapeHtml(
file.name,
)}'">
${Utils.escapeHtml(file.name)}</a>
<span class='float-right' style="margin-top: -3px">
${file.size.toLocaleString()} bytes
<a title="Download ${Utils.escapeHtml(file.name)}"
<a title="Download ${Utils.escapeHtml(
file.name,
)}"
href="${blobURL}"
download="${Utils.escapeHtml(file.name)}"
data-toggle="tooltip">
@ -1130,10 +1140,9 @@ class Utils {
}
}
return html += "</div>";
return (html += "</div>");
}
/**
* Parses URI parameters into a JSON object.
*
@ -1149,8 +1158,7 @@ class Utils {
if (paramStr === "") return {};
// Cut off ? or # and split on &
if (paramStr[0] === "?" ||
paramStr[0] === "#") {
if (paramStr[0] === "?" || paramStr[0] === "#") {
paramStr = paramStr.substr(1);
}
@ -1162,14 +1170,15 @@ class Utils {
if (param.length !== 2) {
result[params[i]] = true;
} else {
result[param[0]] = decodeURIComponent(param[1].replace(/\+/g, " "));
result[param[0]] = decodeURIComponent(
param[1].replace(/\+/g, " "),
);
}
}
return result;
}
/**
* Reads a File and returns the data as a Uint8Array.
*
@ -1181,10 +1190,8 @@ class Utils {
* await Utils.readFile(new File(["hello"], "test"))
*/
static readFile(file) {
if (isNodeEnvironment()) {
return Buffer.from(file).buffer;
} else {
return new Promise((resolve, reject) => {
const reader = new FileReader();
@ -1227,14 +1234,15 @@ class Utils {
*/
static readFileSync(file) {
if (!isNodeEnvironment()) {
throw new TypeError("Browser environment cannot support readFileSync");
throw new TypeError(
"Browser environment cannot support readFileSync",
);
}
const arrayBuffer = Uint8Array.from(file.data);
return arrayBuffer.buffer;
}
/**
* Actual modulo function, since % is actually the remainder function in JS.
*
@ -1247,7 +1255,6 @@ class Utils {
return ((x % y) + y) % y;
}
/**
* Finds the greatest common divisor of two numbers.
*
@ -1263,7 +1270,6 @@ class Utils {
return Utils.gcd(y, x % y);
}
/**
* Finds the modular inverse of two values.
*
@ -1281,7 +1287,6 @@ class Utils {
}
}
/**
* A mapping of names of delimiter characters to their symbols.
*
@ -1290,24 +1295,23 @@ class Utils {
*/
static charRep(token) {
return {
"Space": " ",
"Percent": "%",
"Comma": ",",
Space: " ",
Percent: "%",
Comma: ",",
"Semi-colon": ";",
"Colon": ":",
"Tab": "\t",
Colon: ":",
Tab: "\t",
"Line feed": "\n",
"CRLF": "\r\n",
CRLF: "\r\n",
"Forward slash": "/",
"Backslash": "\\",
Backslash: "\\",
"0x": "0x",
"\\x": "\\x",
"Nothing (separate chars)": "",
"None": "",
None: "",
}[token];
}
/**
* A mapping of names of delimiter characters to regular expressions which can select them.
*
@ -1316,19 +1320,19 @@ class Utils {
*/
static regexRep(token) {
return {
"Space": /\s+/g,
"Percent": /%/g,
"Comma": /,/g,
Space: /\s+/g,
Percent: /%/g,
Comma: /,/g,
"Semi-colon": /;/g,
"Colon": /:/g,
Colon: /:/g,
"Line feed": /\n/g,
"CRLF": /\r\n/g,
CRLF: /\r\n/g,
"Forward slash": /\//g,
"Backslash": /\\/g,
Backslash: /\\/g,
"0x with comma": /,?0x/g,
"0x": /0x/g,
"\\x": /\\x/g,
"None": /\s+/g // Included here to remove whitespace when there shouldn't be any
None: /\s+/g, // Included here to remove whitespace when there shouldn't be any
}[token];
}
@ -1363,7 +1367,11 @@ class Utils {
* @returns {boolean}
*/
export function isNodeEnvironment() {
return typeof process !== "undefined" && process.versions != null && process.versions.node != null;
return (
typeof process !== "undefined" &&
process.versions != null &&
process.versions.node != null
);
}
/**
@ -1384,7 +1392,6 @@ export function isWorkerEnvironment() {
export default Utils;
/**
* Removes all duplicates from an array.
*
@ -1398,7 +1405,8 @@ export default Utils;
* ["One", "Two", "Three", "One"].unique();
*/
Array.prototype.unique = function () {
const u = {}, a = [];
const u = {},
a = [];
for (let i = 0, l = this.length; i < l; i++) {
if (Object.prototype.hasOwnProperty.call(u, this[i])) {
continue;
@ -1409,7 +1417,6 @@ Array.prototype.unique = function() {
return a;
};
/**
* Returns the largest value in the array.
*
@ -1423,7 +1430,6 @@ Array.prototype.max = function() {
return Math.max.apply(null, this);
};
/**
* Returns the smallest value in the array.
*
@ -1437,7 +1443,6 @@ Array.prototype.min = function() {
return Math.min.apply(null, this);
};
/**
* Sums all the values in an array.
*
@ -1453,7 +1458,6 @@ Array.prototype.sum = function() {
}, 0);
};
/**
* Determine whether two arrays are equal or not.
*
@ -1477,7 +1481,6 @@ Array.prototype.equals = function(other) {
return true;
};
/**
* Counts the number of times a char appears in a string.
*
@ -1492,17 +1495,14 @@ String.prototype.count = function(chr) {
return this.split(chr).length - 1;
};
/**
* Wrapper for self.sendStatusMessage to handle different environments.
*
* @param {string} msg
*/
export function sendStatusMessage(msg) {
if (isWorkerEnvironment())
self.sendStatusMessage(msg);
else if (isWebEnvironment())
app.alert(msg, 10000);
if (isWorkerEnvironment()) self.sendStatusMessage(msg);
else if (isWebEnvironment()) app.alert(msg, 10000);
else if (isNodeEnvironment() && !global.TESTING)
// eslint-disable-next-line no-console
console.debug(msg);
@ -1532,7 +1532,6 @@ export function debounce(func, wait, id, scope, args) {
};
}
/*
* Polyfills
*/
@ -1542,7 +1541,7 @@ export function debounce(func, wait, id, scope, args) {
if (!String.prototype.padStart) {
String.prototype.padStart = function padStart(targetLength, padString) {
targetLength = targetLength >> 0; // floor if number or convert non-number to 0;
padString = String((typeof padString !== "undefined" ? padString : " "));
padString = String(typeof padString !== "undefined" ? padString : " ");
if (this.length > targetLength) {
return String(this);
} else {
@ -1555,13 +1554,12 @@ if (!String.prototype.padStart) {
};
}
// https://github.com/uxitten/polyfill/blob/master/string.polyfill.js
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padEnd
if (!String.prototype.padEnd) {
String.prototype.padEnd = function padEnd(targetLength, padString) {
targetLength = targetLength >> 0; // floor if number or convert non-number to 0;
padString = String((typeof padString !== "undefined" ? padString : " "));
padString = String(typeof padString !== "undefined" ? padString : " ");
if (this.length > targetLength) {
return String(this);
} else {

View file

@ -19,12 +19,15 @@ import * as Ops from "../../operations/index.mjs";
const dir = path.join(process.cwd() + "/src/core/config/");
if (!fs.existsSync(dir)) {
console.log("\nCWD: " + process.cwd());
console.log("Error: generateConfig.mjs should be run from the project root");
console.log("Example> node --experimental-modules src/core/config/scripts/generateConfig.mjs");
console.log(
"Error: generateConfig.mjs should be run from the project root",
);
console.log(
"Example> node --experimental-modules src/core/config/scripts/generateConfig.mjs",
);
process.exit(1);
}
const operationConfig = {},
modules = {};
@ -43,25 +46,22 @@ for (const opObj in Ops) {
flowControl: op.flowControl,
manualBake: op.manualBake,
args: op.args,
checks: op.checks
checks: op.checks,
};
if (!(op.module in modules))
modules[op.module] = {};
if (!(op.module in modules)) modules[op.module] = {};
modules[op.module][op.name] = opObj;
}
/**
* Write OperationConfig.
*/
fs.writeFileSync(
path.join(dir, "OperationConfig.json"),
JSON.stringify(operationConfig, null, 4)
JSON.stringify(operationConfig, null, 4),
);
console.log("Written OperationConfig.json");
/**
* Write modules.
*/
@ -98,14 +98,10 @@ OpModules.${module} = {
export default OpModules;
`;
fs.writeFileSync(
path.join(dir, `modules/${module}.mjs`),
code
);
fs.writeFileSync(path.join(dir, `modules/${module}.mjs`), code);
console.log(`Written ${module} module`);
}
/**
* Write OpModules wrapper.
*/
@ -140,8 +136,5 @@ opModulesCode += `);
export default OpModules;
`;
fs.writeFileSync(
path.join(dir, "modules/OpModules.mjs"),
opModulesCode
);
fs.writeFileSync(path.join(dir, "modules/OpModules.mjs"), opModulesCode);
console.log("Written OpModules.mjs");

View file

@ -16,14 +16,18 @@ import process from "process";
const dir = path.join(process.cwd() + "/src/core/config/");
if (!fs.existsSync(dir)) {
console.log("\nCWD: " + process.cwd());
console.log("Error: generateOpsIndex.mjs should be run from the project root");
console.log("Example> node --experimental-modules src/core/config/scripts/generateOpsIndex.mjs");
console.log(
"Error: generateOpsIndex.mjs should be run from the project root",
);
console.log(
"Example> node --experimental-modules src/core/config/scripts/generateOpsIndex.mjs",
);
process.exit(1);
}
// Find all operation files
const opObjs = [];
fs.readdirSync(path.join(dir, "../operations")).forEach(file => {
fs.readdirSync(path.join(dir, "../operations")).forEach((file) => {
if (!file.endsWith(".mjs") || file === "index.mjs") return;
opObjs.push(file.split(".mjs")[0]);
});
@ -38,7 +42,7 @@ let code = `/**
*/
`;
opObjs.forEach(obj => {
opObjs.forEach((obj) => {
code += `import ${obj} from "./${obj}.mjs";\n`;
});
@ -46,15 +50,12 @@ code += `
export {
`;
opObjs.forEach(obj => {
opObjs.forEach((obj) => {
code += ` ${obj},\n`;
});
code += "};\n";
// Write file
fs.writeFileSync(
path.join(dir, "../operations/index.mjs"),
code
);
fs.writeFileSync(path.join(dir, "../operations/index.mjs"), code);
console.log("Written operation index.");

View file

@ -17,45 +17,56 @@ import process from "process";
const dir = path.join(process.cwd() + "/src/core/config/");
if (!fs.existsSync(dir)) {
console.log("\nCWD: " + process.cwd());
console.log("Error: newMinorVersion.mjs should be run from the project root");
console.log("Example> node --experimental-modules src/core/config/scripts/newMinorVersion.mjs");
console.log(
"Error: newMinorVersion.mjs should be run from the project root",
);
console.log(
"Example> node --experimental-modules src/core/config/scripts/newMinorVersion.mjs",
);
process.exit(1);
}
let changelogData = fs.readFileSync(path.join(process.cwd(), "CHANGELOG.md"), "utf8");
const lastVersion = changelogData.match(/## Details\s+### \[(\d+)\.(\d+)\.(\d+)\]/);
let changelogData = fs.readFileSync(
path.join(process.cwd(), "CHANGELOG.md"),
"utf8",
);
const lastVersion = changelogData.match(
/## Details\s+### \[(\d+)\.(\d+)\.(\d+)\]/,
);
const newVersion = [
parseInt(lastVersion[1], 10),
parseInt(lastVersion[2], 10) + 1,
0
0,
];
let knownContributors = changelogData.match(/^\[@([^\]]+)\]/gm);
knownContributors = knownContributors.map(c => c.slice(2, -1));
knownContributors = knownContributors.map((c) => c.slice(2, -1));
const date = (new Date()).toISOString().split("T")[0];
const date = new Date().toISOString().split("T")[0];
const schema = {
properties: {
message: {
description: "A short but descriptive summary of a feature in this version",
description:
"A short but descriptive summary of a feature in this version",
example: "Added 'Op name' operation",
prompt: "Feature description",
type: "string",
required: true,
},
author: {
description: "The author of the feature (only one supported, edit manually to add more)",
description:
"The author of the feature (only one supported, edit manually to add more)",
example: "n1474335",
prompt: "Author",
type: "string",
default: "n1474335"
default: "n1474335",
},
id: {
description: "The PR number or full commit hash for this feature.",
example: "1200",
prompt: "Pull request or commit ID",
type: "string"
type: "string",
},
another: {
description: "y/n",
@ -63,14 +74,19 @@ const schema = {
prompt: "Add another feature?",
type: "string",
pattern: /^[yn]$/,
}
}
},
},
};
// Build schema
for (const prop in schema.properties) {
const p = schema.properties[prop];
p.description = "\n" + colors.white(p.description) + colors.cyan("\nExample: " + p.example) + "\n" + colors.green(p.prompt);
p.description =
"\n" +
colors.white(p.description) +
colors.cyan("\nExample: " + p.example) +
"\n" +
colors.green(p.prompt);
}
prompt.message = "";
@ -97,46 +113,75 @@ const getFeature = function() {
} else {
let message = `### [${newVersion[0]}.${newVersion[1]}.${newVersion[2]}] - ${date}\n`;
features.forEach(feature => {
const id = feature.id.length > 10 ? feature.id.slice(0, 7) : "#" + feature.id;
features.forEach((feature) => {
const id =
feature.id.length > 10
? feature.id.slice(0, 7)
: "#" + feature.id;
message += `- ${feature.message} [@${feature.author}] | [${id}]\n`;
if (!knownContributors.includes(feature.author)) {
authors.push(`[@${feature.author}]: https://github.com/${feature.author}`);
authors.push(
`[@${feature.author}]: https://github.com/${feature.author}`,
);
}
if (feature.id.length > 10) {
commitIDs.push(`[${id}]: https://github.com/gchq/CyberChef/commit/${feature.id}`);
commitIDs.push(
`[${id}]: https://github.com/gchq/CyberChef/commit/${feature.id}`,
);
} else {
prIDs.push(`[#${feature.id}]: https://github.com/gchq/CyberChef/pull/${feature.id}`);
prIDs.push(
`[#${feature.id}]: https://github.com/gchq/CyberChef/pull/${feature.id}`,
);
}
});
// Message
changelogData = changelogData.replace(/## Details\n\n/, "## Details\n\n" + message + "\n");
changelogData = changelogData.replace(
/## Details\n\n/,
"## Details\n\n" + message + "\n",
);
// Tag
const newTag = `[${newVersion[0]}.${newVersion[1]}.${newVersion[2]}]: https://github.com/gchq/CyberChef/releases/tag/v${newVersion[0]}.${newVersion[1]}.${newVersion[2]}\n`;
changelogData = changelogData.replace(/\n\n(\[\d+\.\d+\.\d+\]: https)/, "\n\n" + newTag + "$1");
changelogData = changelogData.replace(
/\n\n(\[\d+\.\d+\.\d+\]: https)/,
"\n\n" + newTag + "$1",
);
// Author
authors.forEach(author => {
changelogData = changelogData.replace(/(\n\[@[^\]]+\]: https:\/\/github\.com\/[^\n]+\n)\n/, "$1" + author + "\n\n");
authors.forEach((author) => {
changelogData = changelogData.replace(
/(\n\[@[^\]]+\]: https:\/\/github\.com\/[^\n]+\n)\n/,
"$1" + author + "\n\n",
);
});
// Commit IDs
commitIDs.forEach(commitID => {
changelogData = changelogData.replace(/(\n\[[^\].]+\]: https:\/\/github.com\/gchq\/CyberChef\/commit\/[^\n]+\n)\n/, "$1" + commitID + "\n\n");
commitIDs.forEach((commitID) => {
changelogData = changelogData.replace(
/(\n\[[^\].]+\]: https:\/\/github.com\/gchq\/CyberChef\/commit\/[^\n]+\n)\n/,
"$1" + commitID + "\n\n",
);
});
// PR IDs
prIDs.forEach(prID => {
changelogData = changelogData.replace(/(\n\[#[^\]]+\]: https:\/\/github.com\/gchq\/CyberChef\/pull\/[^\n]+\n)\n*$/, "$1" + prID + "\n\n");
prIDs.forEach((prID) => {
changelogData = changelogData.replace(
/(\n\[#[^\]]+\]: https:\/\/github.com\/gchq\/CyberChef\/pull\/[^\n]+\n)\n*$/,
"$1" + prID + "\n\n",
);
});
fs.writeFileSync(path.join(process.cwd(), "CHANGELOG.md"), changelogData);
fs.writeFileSync(
path.join(process.cwd(), "CHANGELOG.md"),
changelogData,
);
console.log("Written CHANGELOG.md\nCommit changes and then run `npm version minor`.");
console.log(
"Written CHANGELOG.md\nCommit changes and then run `npm version minor`.",
);
}
});
};

View file

@ -15,16 +15,27 @@ import fs from "fs";
import path from "path";
import EscapeString from "../../operations/EscapeString.mjs";
const dir = path.join(process.cwd() + "/src/core/operations/");
if (!fs.existsSync(dir)) {
console.log("\nCWD: " + process.cwd());
console.log("Error: newOperation.mjs should be run from the project root");
console.log("Example> node --experimental-modules src/core/config/scripts/newOperation.mjs");
console.log(
"Example> node --experimental-modules src/core/config/scripts/newOperation.mjs",
);
process.exit(1);
}
const ioTypes = ["string", "byteArray", "number", "html", "ArrayBuffer", "BigNumber", "JSON", "File", "List<File>"];
const ioTypes = [
"string",
"byteArray",
"number",
"html",
"ArrayBuffer",
"BigNumber",
"JSON",
"File",
"List<File>",
];
const schema = {
properties: {
@ -35,7 +46,8 @@ const schema = {
type: "string",
pattern: /^[\w\s-/().]+$/,
required: true,
message: "Operation names should consist of letters, numbers or the following symbols: _-/()."
message:
"Operation names should consist of letters, numbers or the following symbols: _-/().",
},
module: {
description: `Modules are used to group operations that rely on large libraries. Any operation that is not in the Default module will be loaded in dynamically when it is first called. All operations in the same module will also be loaded at this time. This system prevents the CyberChef web app from getting too bloated and taking a long time to load initially.
@ -44,69 +56,89 @@ If your operation does not rely on a library, just leave this blank and it will
prompt: "Module",
type: "string",
pattern: /^[A-Z][A-Za-z\d]+$/,
message: "Module names should start with a capital letter and not contain any spaces or symbols.",
default: "Default"
message:
"Module names should start with a capital letter and not contain any spaces or symbols.",
default: "Default",
},
description: {
description: "The description should explain what the operation is and how it works. It can describe how the arguments should be entered and give examples of expected input and output. HTML markup is supported. Use <code> tags for examples. The description is scanned during searches, so include terms that are likely to be searched for when someone is looking for your operation.",
example: "Converts URI/URL percent-encoded characters back to their raw values.<br><br>e.g. <code>%3d</code> becomes <code>=</code>",
description:
"The description should explain what the operation is and how it works. It can describe how the arguments should be entered and give examples of expected input and output. HTML markup is supported. Use <code> tags for examples. The description is scanned during searches, so include terms that are likely to be searched for when someone is looking for your operation.",
example:
"Converts URI/URL percent-encoded characters back to their raw values.<br><br>e.g. <code>%3d</code> becomes <code>=</code>",
prompt: "Description",
type: "string"
type: "string",
},
infoURL: {
description: "An optional URL for an external site can be added to give more information about the operation. Wikipedia links are often suitable. If linking to Wikipedia, use an international link (e.g. https://wikipedia.org/...) rather than a localised link (e.g. https://en.wikipedia.org/...).",
description:
"An optional URL for an external site can be added to give more information about the operation. Wikipedia links are often suitable. If linking to Wikipedia, use an international link (e.g. https://wikipedia.org/...) rather than a localised link (e.g. https://en.wikipedia.org/...).",
example: "https://wikipedia.org/wiki/Percent-encoding",
prompt: "Information URL",
type: "string",
},
inputType: {
description: `The input type defines how the input data will be presented to your operation. Check the project wiki for a full description of each type. The options are: ${ioTypes.join(", ")}.`,
description: `The input type defines how the input data will be presented to your operation. Check the project wiki for a full description of each type. The options are: ${ioTypes.join(
", ",
)}.`,
example: "string",
prompt: "Input type",
type: "string",
pattern: new RegExp(`^(${ioTypes.join("|")})$`),
required: true,
message: `The input type should be one of: ${ioTypes.join(", ")}.`
message: `The input type should be one of: ${ioTypes.join(", ")}.`,
},
outputType: {
description: `The output type tells CyberChef what sort of data you are returning from your operation. Check the project wiki for a full description of each type. The options are: ${ioTypes.join(", ")}.`,
description: `The output type tells CyberChef what sort of data you are returning from your operation. Check the project wiki for a full description of each type. The options are: ${ioTypes.join(
", ",
)}.`,
example: "string",
prompt: "Output type",
type: "string",
pattern: new RegExp(`^(${ioTypes.join("|")})$`),
required: true,
message: `The output type should be one of: ${ioTypes.join(", ")}.`
message: `The output type should be one of: ${ioTypes.join(", ")}.`,
},
highlight: {
description: "If your operation does not change the length of the input in any way, we can enable highlighting. If it does change the length in a predictable way, we may still be able to enable highlighting and calculate the correct offsets. If this is not possible, we will disable highlighting for this operation.",
description:
"If your operation does not change the length of the input in any way, we can enable highlighting. If it does change the length in a predictable way, we may still be able to enable highlighting and calculate the correct offsets. If this is not possible, we will disable highlighting for this operation.",
example: "true/false",
prompt: "Enable highlighting",
type: "boolean",
default: "false",
message: "Enter true or false to specify if highlighting should be enabled."
message:
"Enter true or false to specify if highlighting should be enabled.",
},
authorName: {
description: "Your name or username will be added to the @author tag for this operation.",
description:
"Your name or username will be added to the @author tag for this operation.",
example: "n1474335",
prompt: "Username",
type: "string"
type: "string",
},
authorEmail: {
description: "Your email address will also be added to the @author tag for this operation.",
description:
"Your email address will also be added to the @author tag for this operation.",
example: "n1474335@gmail.com",
prompt: "Email",
type: "string"
}
}
type: "string",
},
},
};
// Build schema
for (const prop in schema.properties) {
const p = schema.properties[prop];
p.description = "\n" + colors.white(p.description) + colors.cyan("\nExample: " + p.example) + "\n" + colors.green(p.prompt);
p.description =
"\n" +
colors.white(p.description) +
colors.cyan("\nExample: " + p.example) +
"\n" +
colors.green(p.prompt);
}
console.log("\n\nThis script will generate a new operation template based on the information you provide. These values can be changed manually later.".yellow);
console.log(
"\n\nThis script will generate a new operation template based on the information you provide. These values can be changed manually later."
.yellow,
);
prompt.message = "";
prompt.delimiter = ":".green;
@ -119,14 +151,15 @@ prompt.get(schema, (err, result) => {
process.exit(0);
}
const moduleName = result.opName.replace(/\w\S*/g, txt => {
const moduleName = result.opName
.replace(/\w\S*/g, (txt) => {
return txt.charAt(0).toUpperCase() + txt.substr(1);
}).replace(/[\s-()./]/g, "");
})
.replace(/[\s-()./]/g, "");
const template = `/**
* @author ${result.authorName} [${result.authorEmail}]
* @copyright Crown Copyright ${(new Date()).getFullYear()}
* @copyright Crown Copyright ${new Date().getFullYear()}
* @license Apache-2.0
*/
@ -146,7 +179,10 @@ class ${moduleName} extends Operation {
this.name = "${result.opName}";
this.module = "${result.module}";
this.description = "${(new EscapeString).run(result.description, ["Special chars", "Double"])}";
this.description = "${new EscapeString().run(result.description, [
"Special chars",
"Double",
])}";
this.infoURL = "${result.infoURL}";
this.inputType = "${result.inputType}";
this.outputType = "${result.outputType}";
@ -176,7 +212,9 @@ class ${moduleName} extends Operation {
throw new OperationError("Test");
}
${result.highlight ? `
${
result.highlight
? `
/**
* Highlight ${result.opName}
*
@ -202,7 +240,9 @@ ${result.highlight ? `
highlightReverse(pos, args) {
return pos;
}
` : ""}
`
: ""
}
}
export default ${moduleName};
@ -212,7 +252,9 @@ export default ${moduleName};
const filename = path.join(dir, `./${moduleName}.mjs`);
if (fs.existsSync(filename)) {
console.log(`${filename} already exists. It has NOT been overwritten.`.red);
console.log(
`${filename} already exists. It has NOT been overwritten.`.red,
);
console.log("Choose a different operation name to avoid conflicts.");
process.exit(0);
}
@ -225,6 +267,4 @@ export default ${moduleName};
3. Write tests in ${colors.green("tests/operations/tests/")}
4. Run ${colors.cyan("npm run lint")} and ${colors.cyan("npm run test")}
5. Submit a Pull Request to get your operation added to the official CyberChef repository.`);
});

View file

@ -12,14 +12,15 @@ import BigNumber from "bignumber.js";
* translation methods for BigNumber Dishes
*/
class DishBigNumber extends DishType {
/**
* convert the given value to a ArrayBuffer
* @param {BigNumber} value
*/
static toArrayBuffer() {
DishBigNumber.checkForValue(this.value);
this.value = BigNumber.isBigNumber(this.value) ? Utils.strToArrayBuffer(this.value.toFixed()) : new ArrayBuffer;
this.value = BigNumber.isBigNumber(this.value)
? Utils.strToArrayBuffer(this.value.toFixed())
: new ArrayBuffer();
}
/**

View file

@ -10,7 +10,6 @@ import DishType from "./DishType.mjs";
* Translation methods for ArrayBuffer Dishes
*/
class DishByteArray extends DishType {
/**
* convert the given value to a ArrayBuffer
*/

View file

@ -11,7 +11,6 @@ import Utils, { isNodeEnvironment } from "../Utils.mjs";
* Translation methods for file Dishes
*/
class DishFile extends DishType {
/**
* convert the given value to an ArrayBuffer
* @param {File} value
@ -23,7 +22,7 @@ class DishFile extends DishType {
} else {
return new Promise((resolve, reject) => {
Utils.readFile(this.value)
.then(v => this.value = v.buffer)
.then((v) => (this.value = v.buffer))
.then(resolve)
.catch(reject);
});

View file

@ -11,16 +11,18 @@ import Utils from "../Utils.mjs";
* Translation methods for HTML Dishes
*/
class DishHTML extends DishString {
/**
* convert the given value to a ArrayBuffer
* @param {String} value
*/
static toArrayBuffer() {
DishHTML.checkForValue(this.value);
this.value = this.value ? Utils.strToArrayBuffer(Utils.unescapeHtml(Utils.stripHtmlTags(this.value, true))) : new ArrayBuffer;
this.value = this.value
? Utils.strToArrayBuffer(
Utils.unescapeHtml(Utils.stripHtmlTags(this.value, true)),
)
: new ArrayBuffer();
}
}
export default DishHTML;

View file

@ -11,13 +11,15 @@ import Utils from "../Utils.mjs";
* Translation methods for JSON dishes
*/
class DishJSON extends DishType {
/**
* convert the given value to a ArrayBuffer
*/
static toArrayBuffer() {
DishJSON.checkForValue(this.value);
this.value = this.value !== undefined ? Utils.strToArrayBuffer(JSON.stringify(this.value, null, 4)) : new ArrayBuffer;
this.value =
this.value !== undefined
? Utils.strToArrayBuffer(JSON.stringify(this.value, null, 4))
: new ArrayBuffer();
}
/**

View file

@ -7,12 +7,10 @@
import DishType from "./DishType.mjs";
import Utils, { isNodeEnvironment } from "../Utils.mjs";
/**
* Translation methods for ListFile Dishes
*/
class DishListFile extends DishType {
/**
* convert the given value to a ArrayBuffer
*/
@ -20,9 +18,12 @@ class DishListFile extends DishType {
DishListFile.checkForValue(this.value);
if (isNodeEnvironment()) {
this.value = this.value.map(file => Uint8Array.from(file.data));
this.value = this.value.map((file) => Uint8Array.from(file.data));
} else {
this.value = await DishListFile.concatenateTypedArraysWithTypedElements(...this.value);
this.value =
await DishListFile.concatenateTypedArraysWithTypedElements(
...this.value,
);
}
}

View file

@ -4,7 +4,6 @@
* @license Apache-2.0
*/
import DishType from "./DishType.mjs";
import Utils from "../Utils.mjs";
@ -12,13 +11,15 @@ import Utils from "../Utils.mjs";
* Translation methods for number dishes
*/
class DishNumber extends DishType {
/**
* convert the given value to a ArrayBuffer
*/
static toArrayBuffer() {
DishNumber.checkForValue(this.value);
this.value = typeof this.value === "number" ? Utils.strToArrayBuffer(this.value.toString()) : new ArrayBuffer;
this.value =
typeof this.value === "number"
? Utils.strToArrayBuffer(this.value.toString())
: new ArrayBuffer();
}
/**
@ -26,7 +27,9 @@ class DishNumber extends DishType {
*/
static fromArrayBuffer() {
DishNumber.checkForValue(this.value);
this.value = this.value ? parseFloat(Utils.arrayBufferToStr(this.value)) : 0;
this.value = this.value
? parseFloat(Utils.arrayBufferToStr(this.value))
: 0;
}
}

View file

@ -4,7 +4,6 @@
* @license Apache-2.0
*/
import DishType from "./DishType.mjs";
import Utils from "../Utils.mjs";
@ -12,13 +11,14 @@ import Utils from "../Utils.mjs";
* Translation methods for string dishes
*/
class DishString extends DishType {
/**
* convert the given value to a ArrayBuffer
*/
static toArrayBuffer() {
DishString.checkForValue(this.value);
this.value = this.value ? Utils.strToArrayBuffer(this.value) : new ArrayBuffer;
this.value = this.value
? Utils.strToArrayBuffer(this.value)
: new ArrayBuffer();
}
/**

View file

@ -4,12 +4,10 @@
* @license Apache-2.0
*/
/**
* Abstract class for dish translation methods
*/
class DishType {
/**
* Warn translations dont work without value from bind
*/

View file

@ -4,7 +4,6 @@
* @license Apache-2.0
*/
import DishByteArray from "./DishByteArray.mjs";
import DishBigNumber from "./DishBigNumber.mjs";
import DishFile from "./DishFile.mjs";

View file

@ -2,8 +2,4 @@ import OperationError from "./OperationError.mjs";
import DishError from "./DishError.mjs";
import ExcludedOperationError from "./ExcludedOperationError.mjs";
export {
OperationError,
DishError,
ExcludedOperationError,
};
export { OperationError, DishError, ExcludedOperationError };

View file

@ -8,7 +8,6 @@
import Utils from "../Utils.mjs";
import BigNumber from "bignumber.js";
/**
* Converts a string array to a number array.
*
@ -35,7 +34,6 @@ export function createNumArray(input, delim) {
return numbers;
}
/**
* Adds an array of numbers and returns the value.
*
@ -48,7 +46,6 @@ export function sum(data) {
}
}
/**
* Subtracts an array of numbers and returns the value.
*
@ -61,7 +58,6 @@ export function sub(data) {
}
}
/**
* Multiplies an array of numbers and returns the value.
*
@ -74,7 +70,6 @@ export function multi(data) {
}
}
/**
* Divides an array of numbers and returns the value.
*
@ -87,7 +82,6 @@ export function div(data) {
}
}
/**
* Computes mean of a number array and returns the value.
*
@ -100,7 +94,6 @@ export function mean(data) {
}
}
/**
* Computes median of a number array and returns the value.
*
@ -108,7 +101,7 @@ export function mean(data) {
* @returns {BigNumber}
*/
export function median(data) {
if ((data.length % 2) === 0 && data.length > 0) {
if (data.length % 2 === 0 && data.length > 0) {
data.sort(function (a, b) {
return a.minus(b);
});
@ -120,7 +113,6 @@ export function median(data) {
}
}
/**
* Computes standard deviation of a number array and returns the value.
*

View file

@ -12,11 +12,14 @@
export const BACON_ALPHABETS = {
"Standard (I=J and U=V)": {
alphabet: "ABCDEFGHIKLMNOPQRSTUWXYZ",
codes: [0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 23]
codes: [
0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
19, 19, 20, 21, 22, 23,
],
},
Complete: {
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZ",
},
"Complete": {
alphabet: "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
}
};
export const BACON_TRANSLATION_01 = "0/1";
export const BACON_TRANSLATION_AB = "A/B";
@ -30,7 +33,7 @@ export const BACON_TRANSLATIONS = [
];
export const BACON_TRANSLATIONS_FOR_ENCODING = [
BACON_TRANSLATION_01,
BACON_TRANSLATION_AB
BACON_TRANSLATION_AB,
];
export const BACON_CLEARER_MAP = {
[BACON_TRANSLATION_01]: /[^01]/g,
@ -39,10 +42,10 @@ export const BACON_CLEARER_MAP = {
};
export const BACON_NORMALIZE_MAP = {
[BACON_TRANSLATION_AB]: {
"A": "0",
"B": "1",
"a": "0",
"b": "1"
A: "0",
B: "1",
a: "0",
b: "1",
},
};
@ -59,8 +62,8 @@ export const BACON_NORMALIZE_MAP = {
export function swapZeroAndOne(string) {
return string.replace(/[01]/g, function (c) {
return {
"0": "1",
"1": "0"
0: "1",
1: "0",
}[c];
});
}

View file

@ -33,13 +33,21 @@ export function toBase64(data, alphabet="A-Za-z0-9+/=") {
}
alphabet = Utils.expandAlphRange(alphabet).join("");
if (alphabet.length !== 64 && alphabet.length !== 65) { // Allow for padding
throw new OperationError(`Invalid Base64 alphabet length (${alphabet.length}): ${alphabet}`);
if (alphabet.length !== 64 && alphabet.length !== 65) {
// Allow for padding
throw new OperationError(
`Invalid Base64 alphabet length (${alphabet.length}): ${alphabet}`,
);
}
let output = "",
chr1, chr2, chr3,
enc1, enc2, enc3, enc4,
chr1,
chr2,
chr3,
enc1,
enc2,
enc3,
enc4,
i = 0;
while (i < data.length) {
@ -58,14 +66,16 @@ export function toBase64(data, alphabet="A-Za-z0-9+/=") {
enc4 = 64;
}
output += alphabet.charAt(enc1) + alphabet.charAt(enc2) +
alphabet.charAt(enc3) + alphabet.charAt(enc4);
output +=
alphabet.charAt(enc1) +
alphabet.charAt(enc2) +
alphabet.charAt(enc3) +
alphabet.charAt(enc4);
}
return output;
}
/**
* UnBase64's the input string using the given alphabet, returning a byte array.
*
@ -82,7 +92,13 @@ export function toBase64(data, alphabet="A-Za-z0-9+/=") {
* // returns [72, 101, 108, 108, 111]
* fromBase64("SGVsbG8=", null, "byteArray");
*/
export function fromBase64(data, alphabet="A-Za-z0-9+/=", returnType="string", removeNonAlphChars=true, strictMode=false) {
export function fromBase64(
data,
alphabet = "A-Za-z0-9+/=",
returnType = "string",
removeNonAlphChars = true,
strictMode = false,
) {
if (!data) {
return returnType === "string" ? "" : [];
}
@ -91,42 +107,63 @@ export function fromBase64(data, alphabet="A-Za-z0-9+/=", returnType="string", r
alphabet = Utils.expandAlphRange(alphabet).join("");
// Confirm alphabet is a valid length
if (alphabet.length !== 64 && alphabet.length !== 65) { // Allow for padding
throw new OperationError(`Error: Base64 alphabet should be 64 characters long, or 65 with a padding character. Found ${alphabet.length}: ${alphabet}`);
if (alphabet.length !== 64 && alphabet.length !== 65) {
// Allow for padding
throw new OperationError(
`Error: Base64 alphabet should be 64 characters long, or 65 with a padding character. Found ${alphabet.length}: ${alphabet}`,
);
}
// Remove non-alphabet characters
if (removeNonAlphChars) {
const re = new RegExp("[^" + alphabet.replace(/[[\]\\\-^$]/g, "\\$&") + "]", "g");
const re = new RegExp(
"[^" + alphabet.replace(/[[\]\\\-^$]/g, "\\$&") + "]",
"g",
);
data = data.replace(re, "");
}
if (strictMode) {
// Check for incorrect lengths (even without padding)
if (data.length % 4 === 1) {
throw new OperationError(`Error: Invalid Base64 input length (${data.length}). Cannot be 4n+1, even without padding chars.`);
throw new OperationError(
`Error: Invalid Base64 input length (${data.length}). Cannot be 4n+1, even without padding chars.`,
);
}
if (alphabet.length === 65) { // Padding character included
if (alphabet.length === 65) {
// Padding character included
const pad = alphabet.charAt(64);
const padPos = data.indexOf(pad);
if (padPos >= 0) {
// Check that the padding character is only used at the end and maximum of twice
if (padPos < data.length - 2 || data.charAt(data.length - 1) !== pad) {
throw new OperationError(`Error: Base64 padding character (${pad}) not used in the correct place.`);
if (
padPos < data.length - 2 ||
data.charAt(data.length - 1) !== pad
) {
throw new OperationError(
`Error: Base64 padding character (${pad}) not used in the correct place.`,
);
}
// Check that input is padded to the correct length
if (data.length % 4 !== 0) {
throw new OperationError("Error: Base64 not padded to a multiple of 4.");
throw new OperationError(
"Error: Base64 not padded to a multiple of 4.",
);
}
}
}
}
const output = [];
let chr1, chr2, chr3,
enc1, enc2, enc3, enc4,
let chr1,
chr2,
chr3,
enc1,
enc2,
enc3,
enc4,
i = 0;
while (i < data.length) {
@ -137,7 +174,9 @@ export function fromBase64(data, alphabet="A-Za-z0-9+/=", returnType="string", r
enc4 = alphabet.indexOf(data.charAt(i++) || null);
if (strictMode && (enc1 < 0 || enc2 < 0 || enc3 < 0 || enc4 < 0)) {
throw new OperationError("Error: Base64 input contains non-alphabet char(s)");
throw new OperationError(
"Error: Base64 input contains non-alphabet char(s)",
);
}
chr1 = (enc1 << 2) | (enc2 >> 4);
@ -158,7 +197,6 @@ export function fromBase64(data, alphabet="A-Za-z0-9+/=", returnType="string", r
return returnType === "string" ? Utils.byteArrayToUtf8(output) : output;
}
/**
* Base64 alphabets.
*/
@ -173,11 +211,26 @@ export const ALPHABET_OPTIONS = [
{ name: "Radix-64 (RFC 4880): 0-9A-Za-z+/=", value: "0-9A-Za-z+/=" },
{ name: "Uuencoding: [space]-_", value: " -_" },
{ name: "Xxencoding: +-0-9A-Za-z", value: "+\\-0-9A-Za-z" },
{name: "BinHex: !-,-0-689@A-NP-VX-Z[`a-fh-mp-r", value: "!-,-0-689@A-NP-VX-Z[`a-fh-mp-r"},
{
name: "BinHex: !-,-0-689@A-NP-VX-Z[`a-fh-mp-r",
value: "!-,-0-689@A-NP-VX-Z[`a-fh-mp-r",
},
{ name: "ROT13: N-ZA-Mn-za-m0-9+/=", value: "N-ZA-Mn-za-m0-9+/=" },
{ name: "UNIX crypt: ./0-9A-Za-z", value: "./0-9A-Za-z" },
{name: "Atom128: /128GhIoPQROSTeUbADfgHijKLM+n0pFWXY456xyzB7=39VaqrstJklmNuZvwcdEC", value: "/128GhIoPQROSTeUbADfgHijKLM+n0pFWXY456xyzB7=39VaqrstJklmNuZvwcdEC"},
{name: "Megan35: 3GHIJKLMNOPQRSTUb=cdefghijklmnopWXYZ/12+406789VaqrstuvwxyzABCDEF5", value: "3GHIJKLMNOPQRSTUb=cdefghijklmnopWXYZ/12+406789VaqrstuvwxyzABCDEF5"},
{name: "Zong22: ZKj9n+yf0wDVX1s/5YbdxSo=ILaUpPBCHg8uvNO4klm6iJGhQ7eFrWczAMEq3RTt2", value: "ZKj9n+yf0wDVX1s/5YbdxSo=ILaUpPBCHg8uvNO4klm6iJGhQ7eFrWczAMEq3RTt2"},
{name: "Hazz15: HNO4klm6ij9n+J2hyf0gzA8uvwDEq3X1Q7ZKeFrWcVTts/MRGYbdxSo=ILaUpPBC5", value: "HNO4klm6ij9n+J2hyf0gzA8uvwDEq3X1Q7ZKeFrWcVTts/MRGYbdxSo=ILaUpPBC5"}
{
name: "Atom128: /128GhIoPQROSTeUbADfgHijKLM+n0pFWXY456xyzB7=39VaqrstJklmNuZvwcdEC",
value: "/128GhIoPQROSTeUbADfgHijKLM+n0pFWXY456xyzB7=39VaqrstJklmNuZvwcdEC",
},
{
name: "Megan35: 3GHIJKLMNOPQRSTUb=cdefghijklmnopWXYZ/12+406789VaqrstuvwxyzABCDEF5",
value: "3GHIJKLMNOPQRSTUb=cdefghijklmnopWXYZ/12+406789VaqrstuvwxyzABCDEF5",
},
{
name: "Zong22: ZKj9n+yf0wDVX1s/5YbdxSo=ILaUpPBCHg8uvNO4klm6iJGhQ7eFrWczAMEq3RTt2",
value: "ZKj9n+yf0wDVX1s/5YbdxSo=ILaUpPBCHg8uvNO4klm6iJGhQ7eFrWczAMEq3RTt2",
},
{
name: "Hazz15: HNO4klm6ij9n+J2hyf0gzA8uvwDEq3X1Q7ZKeFrWcVTts/MRGYbdxSo=ILaUpPBC5",
value: "HNO4klm6ij9n+J2hyf0gzA8uvwDEq3X1Q7ZKeFrWcVTts/MRGYbdxSo=ILaUpPBC5",
},
];

View file

@ -23,10 +23,9 @@ export const ALPHABET_OPTIONS = [
{
name: "IPv6",
value: "0-9A-Za-z!#$%&()*+\\-;<=>?@^_`{|}~",
}
},
];
/**
* Returns the name of the alphabet, when given the alphabet.
*

View file

@ -18,12 +18,9 @@ export function base92Chr(val) {
if (val < 0 || val >= 91) {
throw new OperationError("Invalid value");
}
if (val === 0)
return "!".charCodeAt(0);
else if (val <= 61)
return "#".charCodeAt(0) + val - 1;
else
return "a".charCodeAt(0) + val - 62;
if (val === 0) return "!".charCodeAt(0);
else if (val <= 61) return "#".charCodeAt(0) + val - 1;
else return "a".charCodeAt(0) + val - 62;
}
/**
@ -33,12 +30,10 @@ export function base92Chr(val) {
* @returns {number}
*/
export function base92Ord(val) {
if (val === "!")
return 0;
if (val === "!") return 0;
else if ("#" <= val && val <= "_")
return val.charCodeAt(0) - "#".charCodeAt(0) + 1;
else if ("a" <= val && val <= "}")
return val.charCodeAt(0) - "a".charCodeAt(0) + 62;
throw new OperationError(`${val} is not a base92 character`);
}

View file

@ -9,7 +9,6 @@
import Utils from "../Utils.mjs";
import OperationError from "../errors/OperationError.mjs";
/**
* Convert a byte array into a binary string.
*
@ -30,17 +29,21 @@ import OperationError from "../errors/OperationError.mjs";
*/
export function toBinary(data, delim = "Space", padding = 8) {
if (data === undefined || data === null)
throw new OperationError("Unable to convert to binary: Empty input data enocuntered");
throw new OperationError(
"Unable to convert to binary: Empty input data enocuntered",
);
delim = Utils.charRep(delim);
let output = "";
if (data.length) { // array
if (data.length) {
// array
for (let i = 0; i < data.length; i++) {
output += data[i].toString(2).padStart(padding, "0");
if (i !== data.length - 1) output += delim;
}
} else if (typeof data === "number") { // Single value
} else if (typeof data === "number") {
// Single value
return data.toString(2).padStart(padding, "0");
} else {
return "";
@ -48,7 +51,6 @@ export function toBinary(data, delim="Space", padding=8) {
return output;
}
/**
* Convert a binary string into a byte array.
*
@ -77,4 +79,3 @@ export function fromBinary(data, delim="Space", byteLen=8) {
}
return output;
}

View file

@ -29,9 +29,11 @@ export function bitOp (input, key, func, nullPreserving, scheme) {
o = input[i];
x = nullPreserving && (o === 0 || o === k) ? o : func(o, k);
result.push(x);
if (scheme &&
if (
scheme &&
scheme !== "Standard" &&
!(nullPreserving && (o === 0 || o === k))) {
!(nullPreserving && (o === 0 || o === k))
) {
switch (scheme) {
case "Input differential":
key[i % key.length] = o;
@ -57,7 +59,6 @@ export function xor(operand, key) {
return operand ^ key;
}
/**
* NOT bitwise calculation.
*
@ -68,7 +69,6 @@ export function not(operand, _) {
return ~operand & 0xff;
}
/**
* AND bitwise calculation.
*
@ -80,7 +80,6 @@ export function and(operand, key) {
return operand & key;
}
/**
* OR bitwise calculation.
*
@ -92,7 +91,6 @@ export function or(operand, key) {
return operand | key;
}
/**
* ADD bitwise calculation.
*
@ -104,7 +102,6 @@ export function add(operand, key) {
return (operand + key) % 256;
}
/**
* SUB bitwise calculation.
*
@ -114,11 +111,17 @@ export function add(operand, key) {
*/
export function sub(operand, key) {
const result = operand - key;
return (result < 0) ? 256 + result : result;
return result < 0 ? 256 + result : result;
}
/**
* Delimiter options for bitwise operations
*/
export const BITWISE_OP_DELIMS = ["Hex", "Decimal", "Binary", "Base64", "UTF8", "Latin1"];
export const BITWISE_OP_DELIMS = [
"Hex",
"Decimal",
"Binary",
"Base64",
"UTF8",
"Latin1",
];

View file

@ -40,7 +40,6 @@ const crypto = {};
import forge from "node-forge";
/* dojo-release-1.8.1/dojo/_base/lang.js.uncompressed.js */
const lang = {};
@ -49,10 +48,9 @@ lang.isString = function(it) {
// Return true if it is a String
// it: anything
// Item to test.
return (typeof it == "string" || it instanceof String); // Boolean
return typeof it == "string" || it instanceof String; // Boolean
};
/* dojo-release-1.8.1/dojo/_base/array.js.uncompressed.js */
const arrayUtil = {};
@ -81,7 +79,8 @@ arrayUtil.map = function(arr, callback, thisObject, Ctr) {
// TODO: why do we have a non-standard signature here? do we need "Ctr"?
let i = 0;
const l = arr && arr.length || 0, out = new (Ctr || Array)(l);
const l = (arr && arr.length) || 0,
out = new (Ctr || Array)(l);
if (l && typeof arr == "string") arr = arr.split("");
if (thisObject) {
for (; i < l; ++i) {
@ -104,168 +103,228 @@ arrayUtil.map = function(arr, callback, thisObject, Ctr) {
*/
const boxes = {
p: [
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0, 0x082efa98, 0xec4e6c89,
0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c, 0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917,
0x9216d5d9, 0x8979fb1b
0x243f6a88, 0x85a308d3, 0x13198a2e, 0x03707344, 0xa4093822, 0x299f31d0,
0x082efa98, 0xec4e6c89, 0x452821e6, 0x38d01377, 0xbe5466cf, 0x34e90c6c,
0xc0ac29b7, 0xc97c50dd, 0x3f84d5b5, 0xb5470917, 0x9216d5d9, 0x8979fb1b,
],
s0: [
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96, 0xba7c9045, 0xf12c7f99,
0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16, 0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e,
0x0d95748f, 0x728eb658, 0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e, 0x6c9e0e8b, 0xb01e8a3e,
0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60, 0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440,
0x55ca396a, 0x2aab10b6, 0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c, 0x7a325381, 0x28958677,
0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193, 0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032,
0xef845d5d, 0xe98575b1, 0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a, 0x670c9c61, 0xabd388f0,
0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3, 0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98,
0xa1f1651d, 0x39af0176, 0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706, 0x1bfedf72, 0x429b023d,
0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b, 0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7,
0xe3fe501a, 0xb6794c3b, 0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c, 0xcc814544, 0xaf5ebd09,
0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3, 0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb,
0x5579c0bd, 0x1a60320a, 0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760, 0x53317b48, 0x3e00df82,
0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db, 0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573,
0x695b27b0, 0xbbca58c8, 0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33, 0x62fb1341, 0xcee4c6e8,
0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4, 0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0,
0xd08ed1d0, 0xafc725e0, 0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777, 0xea752dfe, 0x8b021fa1,
0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299, 0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9,
0x165fa266, 0x80957705, 0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e, 0x226800bb, 0x57b8e0af,
0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa, 0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5,
0x83260376, 0x6295cfa9, 0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f, 0xf296ec6b, 0x2a0dd915,
0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664, 0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a
0xd1310ba6, 0x98dfb5ac, 0x2ffd72db, 0xd01adfb7, 0xb8e1afed, 0x6a267e96,
0xba7c9045, 0xf12c7f99, 0x24a19947, 0xb3916cf7, 0x0801f2e2, 0x858efc16,
0x636920d8, 0x71574e69, 0xa458fea3, 0xf4933d7e, 0x0d95748f, 0x728eb658,
0x718bcd58, 0x82154aee, 0x7b54a41d, 0xc25a59b5, 0x9c30d539, 0x2af26013,
0xc5d1b023, 0x286085f0, 0xca417918, 0xb8db38ef, 0x8e79dcb0, 0x603a180e,
0x6c9e0e8b, 0xb01e8a3e, 0xd71577c1, 0xbd314b27, 0x78af2fda, 0x55605c60,
0xe65525f3, 0xaa55ab94, 0x57489862, 0x63e81440, 0x55ca396a, 0x2aab10b6,
0xb4cc5c34, 0x1141e8ce, 0xa15486af, 0x7c72e993, 0xb3ee1411, 0x636fbc2a,
0x2ba9c55d, 0x741831f6, 0xce5c3e16, 0x9b87931e, 0xafd6ba33, 0x6c24cf5c,
0x7a325381, 0x28958677, 0x3b8f4898, 0x6b4bb9af, 0xc4bfe81b, 0x66282193,
0x61d809cc, 0xfb21a991, 0x487cac60, 0x5dec8032, 0xef845d5d, 0xe98575b1,
0xdc262302, 0xeb651b88, 0x23893e81, 0xd396acc5, 0x0f6d6ff3, 0x83f44239,
0x2e0b4482, 0xa4842004, 0x69c8f04a, 0x9e1f9b5e, 0x21c66842, 0xf6e96c9a,
0x670c9c61, 0xabd388f0, 0x6a51a0d2, 0xd8542f68, 0x960fa728, 0xab5133a3,
0x6eef0b6c, 0x137a3be4, 0xba3bf050, 0x7efb2a98, 0xa1f1651d, 0x39af0176,
0x66ca593e, 0x82430e88, 0x8cee8619, 0x456f9fb4, 0x7d84a5c3, 0x3b8b5ebe,
0xe06f75d8, 0x85c12073, 0x401a449f, 0x56c16aa6, 0x4ed3aa62, 0x363f7706,
0x1bfedf72, 0x429b023d, 0x37d0d724, 0xd00a1248, 0xdb0fead3, 0x49f1c09b,
0x075372c9, 0x80991b7b, 0x25d479d8, 0xf6e8def7, 0xe3fe501a, 0xb6794c3b,
0x976ce0bd, 0x04c006ba, 0xc1a94fb6, 0x409f60c4, 0x5e5c9ec2, 0x196a2463,
0x68fb6faf, 0x3e6c53b5, 0x1339b2eb, 0x3b52ec6f, 0x6dfc511f, 0x9b30952c,
0xcc814544, 0xaf5ebd09, 0xbee3d004, 0xde334afd, 0x660f2807, 0x192e4bb3,
0xc0cba857, 0x45c8740f, 0xd20b5f39, 0xb9d3fbdb, 0x5579c0bd, 0x1a60320a,
0xd6a100c6, 0x402c7279, 0x679f25fe, 0xfb1fa3cc, 0x8ea5e9f8, 0xdb3222f8,
0x3c7516df, 0xfd616b15, 0x2f501ec8, 0xad0552ab, 0x323db5fa, 0xfd238760,
0x53317b48, 0x3e00df82, 0x9e5c57bb, 0xca6f8ca0, 0x1a87562e, 0xdf1769db,
0xd542a8f6, 0x287effc3, 0xac6732c6, 0x8c4f5573, 0x695b27b0, 0xbbca58c8,
0xe1ffa35d, 0xb8f011a0, 0x10fa3d98, 0xfd2183b8, 0x4afcb56c, 0x2dd1d35b,
0x9a53e479, 0xb6f84565, 0xd28e49bc, 0x4bfb9790, 0xe1ddf2da, 0xa4cb7e33,
0x62fb1341, 0xcee4c6e8, 0xef20cada, 0x36774c01, 0xd07e9efe, 0x2bf11fb4,
0x95dbda4d, 0xae909198, 0xeaad8e71, 0x6b93d5a0, 0xd08ed1d0, 0xafc725e0,
0x8e3c5b2f, 0x8e7594b7, 0x8ff6e2fb, 0xf2122b64, 0x8888b812, 0x900df01c,
0x4fad5ea0, 0x688fc31c, 0xd1cff191, 0xb3a8c1ad, 0x2f2f2218, 0xbe0e1777,
0xea752dfe, 0x8b021fa1, 0xe5a0cc0f, 0xb56f74e8, 0x18acf3d6, 0xce89e299,
0xb4a84fe0, 0xfd13e0b7, 0x7cc43b81, 0xd2ada8d9, 0x165fa266, 0x80957705,
0x93cc7314, 0x211a1477, 0xe6ad2065, 0x77b5fa86, 0xc75442f5, 0xfb9d35cf,
0xebcdaf0c, 0x7b3e89a0, 0xd6411bd3, 0xae1e7e49, 0x00250e2d, 0x2071b35e,
0x226800bb, 0x57b8e0af, 0x2464369b, 0xf009b91e, 0x5563911d, 0x59dfa6aa,
0x78c14389, 0xd95a537f, 0x207d5ba2, 0x02e5b9c5, 0x83260376, 0x6295cfa9,
0x11c81968, 0x4e734a41, 0xb3472dca, 0x7b14a94a, 0x1b510052, 0x9a532915,
0xd60f573f, 0xbc9bc6e4, 0x2b60a476, 0x81e67400, 0x08ba6fb5, 0x571be91f,
0xf296ec6b, 0x2a0dd915, 0xb6636521, 0xe7b9f9b6, 0xff34052e, 0xc5855664,
0x53b02d5d, 0xa99f8fa1, 0x08ba4799, 0x6e85076a,
],
s1: [
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d, 0x9cee60b8, 0x8fedb266,
0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1, 0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e,
0x3f54989a, 0x5b429d65, 0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9, 0x3c971814, 0x6b6a70a1,
0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737, 0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8,
0xb03ada37, 0xf0500c0d, 0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc, 0xc8b57634, 0x9af3dda7,
0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41, 0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331,
0x4e548b38, 0x4f6db908, 0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124, 0x501adde6, 0x9f84cd87,
0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c, 0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2,
0xef1c1847, 0x3215d908, 0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b, 0x3c11183b, 0x5924a509,
0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e, 0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3,
0x771fe71c, 0x4e3d06fa, 0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d, 0x1939260f, 0x19c27960,
0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66, 0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28,
0xc332ddef, 0xbe6c5aa5, 0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96, 0x0334fe1e, 0xaa0363cf,
0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14, 0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e,
0x648b1eaf, 0x19bdf0ca, 0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77, 0x11ed935f, 0x16681281,
0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99, 0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696,
0xcdb30aeb, 0x532e3054, 0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea, 0xdb6c4f15, 0xfacb4fd0,
0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105, 0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250,
0xcf62a1f2, 0x5b8d2646, 0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea, 0x1dadf43e, 0x233f7061,
0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb, 0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e,
0xa6078084, 0x19f8509e, 0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd, 0x675fda79, 0xe3674340,
0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20, 0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7
0x4b7a70e9, 0xb5b32944, 0xdb75092e, 0xc4192623, 0xad6ea6b0, 0x49a7df7d,
0x9cee60b8, 0x8fedb266, 0xecaa8c71, 0x699a17ff, 0x5664526c, 0xc2b19ee1,
0x193602a5, 0x75094c29, 0xa0591340, 0xe4183a3e, 0x3f54989a, 0x5b429d65,
0x6b8fe4d6, 0x99f73fd6, 0xa1d29c07, 0xefe830f5, 0x4d2d38e6, 0xf0255dc1,
0x4cdd2086, 0x8470eb26, 0x6382e9c6, 0x021ecc5e, 0x09686b3f, 0x3ebaefc9,
0x3c971814, 0x6b6a70a1, 0x687f3584, 0x52a0e286, 0xb79c5305, 0xaa500737,
0x3e07841c, 0x7fdeae5c, 0x8e7d44ec, 0x5716f2b8, 0xb03ada37, 0xf0500c0d,
0xf01c1f04, 0x0200b3ff, 0xae0cf51a, 0x3cb574b2, 0x25837a58, 0xdc0921bd,
0xd19113f9, 0x7ca92ff6, 0x94324773, 0x22f54701, 0x3ae5e581, 0x37c2dadc,
0xc8b57634, 0x9af3dda7, 0xa9446146, 0x0fd0030e, 0xecc8c73e, 0xa4751e41,
0xe238cd99, 0x3bea0e2f, 0x3280bba1, 0x183eb331, 0x4e548b38, 0x4f6db908,
0x6f420d03, 0xf60a04bf, 0x2cb81290, 0x24977c79, 0x5679b072, 0xbcaf89af,
0xde9a771f, 0xd9930810, 0xb38bae12, 0xdccf3f2e, 0x5512721f, 0x2e6b7124,
0x501adde6, 0x9f84cd87, 0x7a584718, 0x7408da17, 0xbc9f9abc, 0xe94b7d8c,
0xec7aec3a, 0xdb851dfa, 0x63094366, 0xc464c3d2, 0xef1c1847, 0x3215d908,
0xdd433b37, 0x24c2ba16, 0x12a14d43, 0x2a65c451, 0x50940002, 0x133ae4dd,
0x71dff89e, 0x10314e55, 0x81ac77d6, 0x5f11199b, 0x043556f1, 0xd7a3c76b,
0x3c11183b, 0x5924a509, 0xf28fe6ed, 0x97f1fbfa, 0x9ebabf2c, 0x1e153c6e,
0x86e34570, 0xeae96fb1, 0x860e5e0a, 0x5a3e2ab3, 0x771fe71c, 0x4e3d06fa,
0x2965dcb9, 0x99e71d0f, 0x803e89d6, 0x5266c825, 0x2e4cc978, 0x9c10b36a,
0xc6150eba, 0x94e2ea78, 0xa5fc3c53, 0x1e0a2df4, 0xf2f74ea7, 0x361d2b3d,
0x1939260f, 0x19c27960, 0x5223a708, 0xf71312b6, 0xebadfe6e, 0xeac31f66,
0xe3bc4595, 0xa67bc883, 0xb17f37d1, 0x018cff28, 0xc332ddef, 0xbe6c5aa5,
0x65582185, 0x68ab9802, 0xeecea50f, 0xdb2f953b, 0x2aef7dad, 0x5b6e2f84,
0x1521b628, 0x29076170, 0xecdd4775, 0x619f1510, 0x13cca830, 0xeb61bd96,
0x0334fe1e, 0xaa0363cf, 0xb5735c90, 0x4c70a239, 0xd59e9e0b, 0xcbaade14,
0xeecc86bc, 0x60622ca7, 0x9cab5cab, 0xb2f3846e, 0x648b1eaf, 0x19bdf0ca,
0xa02369b9, 0x655abb50, 0x40685a32, 0x3c2ab4b3, 0x319ee9d5, 0xc021b8f7,
0x9b540b19, 0x875fa099, 0x95f7997e, 0x623d7da8, 0xf837889a, 0x97e32d77,
0x11ed935f, 0x16681281, 0x0e358829, 0xc7e61fd6, 0x96dedfa1, 0x7858ba99,
0x57f584a5, 0x1b227263, 0x9b83c3ff, 0x1ac24696, 0xcdb30aeb, 0x532e3054,
0x8fd948e4, 0x6dbc3128, 0x58ebf2ef, 0x34c6ffea, 0xfe28ed61, 0xee7c3c73,
0x5d4a14d9, 0xe864b7e3, 0x42105d14, 0x203e13e0, 0x45eee2b6, 0xa3aaabea,
0xdb6c4f15, 0xfacb4fd0, 0xc742f442, 0xef6abbb5, 0x654f3b1d, 0x41cd2105,
0xd81e799e, 0x86854dc7, 0xe44b476a, 0x3d816250, 0xcf62a1f2, 0x5b8d2646,
0xfc8883a0, 0xc1c7b6a3, 0x7f1524c3, 0x69cb7492, 0x47848a0b, 0x5692b285,
0x095bbf00, 0xad19489d, 0x1462b174, 0x23820e00, 0x58428d2a, 0x0c55f5ea,
0x1dadf43e, 0x233f7061, 0x3372f092, 0x8d937e41, 0xd65fecf1, 0x6c223bdb,
0x7cde3759, 0xcbee7460, 0x4085f2a7, 0xce77326e, 0xa6078084, 0x19f8509e,
0xe8efd855, 0x61d99735, 0xa969a7aa, 0xc50c06c2, 0x5a04abfc, 0x800bcadc,
0x9e447a2e, 0xc3453484, 0xfdd56705, 0x0e1e9ec9, 0xdb73dbd3, 0x105588cd,
0x675fda79, 0xe3674340, 0xc5c43465, 0x713e38d8, 0x3d28f89e, 0xf16dff20,
0x153e21e7, 0x8fb03d4a, 0xe6e39f2b, 0xdb83adf7,
],
s2: [
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7, 0xbcf46b2e, 0xd4a20068,
0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af, 0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840,
0x4d95fc1d, 0x96b591af, 0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4, 0x0a2c86da, 0xe9b66dfb,
0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee, 0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6,
0xaace1e7c, 0xd3375fec, 0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332, 0x6841e7f7, 0xca7820fb,
0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527, 0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b,
0x55a867bc, 0xa1159a58, 0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22, 0x48c1133f, 0xc70f86dc,
0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17, 0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564,
0x257b7834, 0x602a9c60, 0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99, 0xde720c8c, 0x2da2f728,
0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0, 0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e,
0x0a476341, 0x992eff74, 0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3, 0xb5390f92, 0x690fed0b,
0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3, 0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb,
0x37392eb3, 0xcc115979, 0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa, 0x3d25bdd8, 0xe2e1c3c9,
0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a, 0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe,
0x9dbc8057, 0xf0f7c086, 0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24, 0x55464299, 0xbf582e61,
0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2, 0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9,
0x7aeb2661, 0x8b1ddf84, 0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09, 0x662d09a1, 0xc4324633,
0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10, 0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169,
0xdcb7da83, 0x573906fe, 0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0, 0x006058aa, 0x30dc7d62,
0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634, 0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76,
0x6f05e409, 0x4b7c0188, 0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8, 0xa28514d9, 0x6c51133c,
0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837, 0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0
0xe93d5a68, 0x948140f7, 0xf64c261c, 0x94692934, 0x411520f7, 0x7602d4f7,
0xbcf46b2e, 0xd4a20068, 0xd4082471, 0x3320f46a, 0x43b7d4b7, 0x500061af,
0x1e39f62e, 0x97244546, 0x14214f74, 0xbf8b8840, 0x4d95fc1d, 0x96b591af,
0x70f4ddd3, 0x66a02f45, 0xbfbc09ec, 0x03bd9785, 0x7fac6dd0, 0x31cb8504,
0x96eb27b3, 0x55fd3941, 0xda2547e6, 0xabca0a9a, 0x28507825, 0x530429f4,
0x0a2c86da, 0xe9b66dfb, 0x68dc1462, 0xd7486900, 0x680ec0a4, 0x27a18dee,
0x4f3ffea2, 0xe887ad8c, 0xb58ce006, 0x7af4d6b6, 0xaace1e7c, 0xd3375fec,
0xce78a399, 0x406b2a42, 0x20fe9e35, 0xd9f385b9, 0xee39d7ab, 0x3b124e8b,
0x1dc9faf7, 0x4b6d1856, 0x26a36631, 0xeae397b2, 0x3a6efa74, 0xdd5b4332,
0x6841e7f7, 0xca7820fb, 0xfb0af54e, 0xd8feb397, 0x454056ac, 0xba489527,
0x55533a3a, 0x20838d87, 0xfe6ba9b7, 0xd096954b, 0x55a867bc, 0xa1159a58,
0xcca92963, 0x99e1db33, 0xa62a4a56, 0x3f3125f9, 0x5ef47e1c, 0x9029317c,
0xfdf8e802, 0x04272f70, 0x80bb155c, 0x05282ce3, 0x95c11548, 0xe4c66d22,
0x48c1133f, 0xc70f86dc, 0x07f9c9ee, 0x41041f0f, 0x404779a4, 0x5d886e17,
0x325f51eb, 0xd59bc0d1, 0xf2bcc18f, 0x41113564, 0x257b7834, 0x602a9c60,
0xdff8e8a3, 0x1f636c1b, 0x0e12b4c2, 0x02e1329e, 0xaf664fd1, 0xcad18115,
0x6b2395e0, 0x333e92e1, 0x3b240b62, 0xeebeb922, 0x85b2a20e, 0xe6ba0d99,
0xde720c8c, 0x2da2f728, 0xd0127845, 0x95b794fd, 0x647d0862, 0xe7ccf5f0,
0x5449a36f, 0x877d48fa, 0xc39dfd27, 0xf33e8d1e, 0x0a476341, 0x992eff74,
0x3a6f6eab, 0xf4f8fd37, 0xa812dc60, 0xa1ebddf8, 0x991be14c, 0xdb6e6b0d,
0xc67b5510, 0x6d672c37, 0x2765d43b, 0xdcd0e804, 0xf1290dc7, 0xcc00ffa3,
0xb5390f92, 0x690fed0b, 0x667b9ffb, 0xcedb7d9c, 0xa091cf0b, 0xd9155ea3,
0xbb132f88, 0x515bad24, 0x7b9479bf, 0x763bd6eb, 0x37392eb3, 0xcc115979,
0x8026e297, 0xf42e312d, 0x6842ada7, 0xc66a2b3b, 0x12754ccc, 0x782ef11c,
0x6a124237, 0xb79251e7, 0x06a1bbe6, 0x4bfb6350, 0x1a6b1018, 0x11caedfa,
0x3d25bdd8, 0xe2e1c3c9, 0x44421659, 0x0a121386, 0xd90cec6e, 0xd5abea2a,
0x64af674e, 0xda86a85f, 0xbebfe988, 0x64e4c3fe, 0x9dbc8057, 0xf0f7c086,
0x60787bf8, 0x6003604d, 0xd1fd8346, 0xf6381fb0, 0x7745ae04, 0xd736fccc,
0x83426b33, 0xf01eab71, 0xb0804187, 0x3c005e5f, 0x77a057be, 0xbde8ae24,
0x55464299, 0xbf582e61, 0x4e58f48f, 0xf2ddfda2, 0xf474ef38, 0x8789bdc2,
0x5366f9c3, 0xc8b38e74, 0xb475f255, 0x46fcd9b9, 0x7aeb2661, 0x8b1ddf84,
0x846a0e79, 0x915f95e2, 0x466e598e, 0x20b45770, 0x8cd55591, 0xc902de4c,
0xb90bace1, 0xbb8205d0, 0x11a86248, 0x7574a99e, 0xb77f19b6, 0xe0a9dc09,
0x662d09a1, 0xc4324633, 0xe85a1f02, 0x09f0be8c, 0x4a99a025, 0x1d6efe10,
0x1ab93d1d, 0x0ba5a4df, 0xa186f20f, 0x2868f169, 0xdcb7da83, 0x573906fe,
0xa1e2ce9b, 0x4fcd7f52, 0x50115e01, 0xa70683fa, 0xa002b5c4, 0x0de6d027,
0x9af88c27, 0x773f8641, 0xc3604c06, 0x61a806b5, 0xf0177a28, 0xc0f586e0,
0x006058aa, 0x30dc7d62, 0x11e69ed7, 0x2338ea63, 0x53c2dd94, 0xc2c21634,
0xbbcbee56, 0x90bcb6de, 0xebfc7da1, 0xce591d76, 0x6f05e409, 0x4b7c0188,
0x39720a3d, 0x7c927c24, 0x86e3725f, 0x724d9db9, 0x1ac15bb4, 0xd39eb8fc,
0xed545578, 0x08fca5b5, 0xd83d7cd3, 0x4dad0fc4, 0x1e50ef5e, 0xb161e6f8,
0xa28514d9, 0x6c51133c, 0x6fd5c7e7, 0x56e14ec4, 0x362abfce, 0xddc6c837,
0xd79a3234, 0x92638212, 0x670efa8e, 0x406000e0,
],
s3: [
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742, 0xd3822740, 0x99bc9bbe,
0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b, 0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4,
0x5748ab2f, 0xbc946e79, 0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a, 0x63ef8ce2, 0x9a86ee22,
0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4, 0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6,
0x2826a2f9, 0xa73a3ae1, 0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797, 0x2cf0b7d9, 0x022b8b51,
0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28, 0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c,
0xe029ac71, 0xe019a5e6, 0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba, 0x03a16125, 0x0564f0bd,
0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a, 0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319,
0x7533d928, 0xb155fdf5, 0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce, 0x5121ce64, 0x774fbe32,
0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680, 0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166,
0xb39a460a, 0x6445c0dd, 0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb, 0x8d6612ae, 0xbf3c6f47,
0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370, 0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d,
0x4040cb08, 0x4eb4e2cc, 0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc, 0xbb3a792b, 0x344525bd,
0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9, 0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7,
0x1a908749, 0xd44fbd9a, 0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a, 0x0f91fc71, 0x9b941525,
0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1, 0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442,
0xe0ec6e0e, 0x1698db3b, 0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e, 0xe60b6f47, 0x0fe3f11d,
0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f, 0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299,
0xf523f357, 0xa6327623, 0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a, 0x45e1d006, 0xc3f27b9a,
0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6, 0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b,
0x53113ec0, 0x1640e3d3, 0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c, 0x01c36ae4, 0xd6ebe1f9,
0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f, 0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6
]
0x3a39ce37, 0xd3faf5cf, 0xabc27737, 0x5ac52d1b, 0x5cb0679e, 0x4fa33742,
0xd3822740, 0x99bc9bbe, 0xd5118e9d, 0xbf0f7315, 0xd62d1c7e, 0xc700c47b,
0xb78c1b6b, 0x21a19045, 0xb26eb1be, 0x6a366eb4, 0x5748ab2f, 0xbc946e79,
0xc6a376d2, 0x6549c2c8, 0x530ff8ee, 0x468dde7d, 0xd5730a1d, 0x4cd04dc6,
0x2939bbdb, 0xa9ba4650, 0xac9526e8, 0xbe5ee304, 0xa1fad5f0, 0x6a2d519a,
0x63ef8ce2, 0x9a86ee22, 0xc089c2b8, 0x43242ef6, 0xa51e03aa, 0x9cf2d0a4,
0x83c061ba, 0x9be96a4d, 0x8fe51550, 0xba645bd6, 0x2826a2f9, 0xa73a3ae1,
0x4ba99586, 0xef5562e9, 0xc72fefd3, 0xf752f7da, 0x3f046f69, 0x77fa0a59,
0x80e4a915, 0x87b08601, 0x9b09e6ad, 0x3b3ee593, 0xe990fd5a, 0x9e34d797,
0x2cf0b7d9, 0x022b8b51, 0x96d5ac3a, 0x017da67d, 0xd1cf3ed6, 0x7c7d2d28,
0x1f9f25cf, 0xadf2b89b, 0x5ad6b472, 0x5a88f54c, 0xe029ac71, 0xe019a5e6,
0x47b0acfd, 0xed93fa9b, 0xe8d3c48d, 0x283b57cc, 0xf8d56629, 0x79132e28,
0x785f0191, 0xed756055, 0xf7960e44, 0xe3d35e8c, 0x15056dd4, 0x88f46dba,
0x03a16125, 0x0564f0bd, 0xc3eb9e15, 0x3c9057a2, 0x97271aec, 0xa93a072a,
0x1b3f6d9b, 0x1e6321f5, 0xf59c66fb, 0x26dcf319, 0x7533d928, 0xb155fdf5,
0x03563482, 0x8aba3cbb, 0x28517711, 0xc20ad9f8, 0xabcc5167, 0xccad925f,
0x4de81751, 0x3830dc8e, 0x379d5862, 0x9320f991, 0xea7a90c2, 0xfb3e7bce,
0x5121ce64, 0x774fbe32, 0xa8b6e37e, 0xc3293d46, 0x48de5369, 0x6413e680,
0xa2ae0810, 0xdd6db224, 0x69852dfd, 0x09072166, 0xb39a460a, 0x6445c0dd,
0x586cdecf, 0x1c20c8ae, 0x5bbef7dd, 0x1b588d40, 0xccd2017f, 0x6bb4e3bb,
0xdda26a7e, 0x3a59ff45, 0x3e350a44, 0xbcb4cdd5, 0x72eacea8, 0xfa6484bb,
0x8d6612ae, 0xbf3c6f47, 0xd29be463, 0x542f5d9e, 0xaec2771b, 0xf64e6370,
0x740e0d8d, 0xe75b1357, 0xf8721671, 0xaf537d5d, 0x4040cb08, 0x4eb4e2cc,
0x34d2466a, 0x0115af84, 0xe1b00428, 0x95983a1d, 0x06b89fb4, 0xce6ea048,
0x6f3f3b82, 0x3520ab82, 0x011a1d4b, 0x277227f8, 0x611560b1, 0xe7933fdc,
0xbb3a792b, 0x344525bd, 0xa08839e1, 0x51ce794b, 0x2f32c9b7, 0xa01fbac9,
0xe01cc87e, 0xbcc7d1f6, 0xcf0111c3, 0xa1e8aac7, 0x1a908749, 0xd44fbd9a,
0xd0dadecb, 0xd50ada38, 0x0339c32a, 0xc6913667, 0x8df9317c, 0xe0b12b4f,
0xf79e59b7, 0x43f5bb3a, 0xf2d519ff, 0x27d9459c, 0xbf97222c, 0x15e6fc2a,
0x0f91fc71, 0x9b941525, 0xfae59361, 0xceb69ceb, 0xc2a86459, 0x12baa8d1,
0xb6c1075e, 0xe3056a0c, 0x10d25065, 0xcb03a442, 0xe0ec6e0e, 0x1698db3b,
0x4c98a0be, 0x3278e964, 0x9f1f9532, 0xe0d392df, 0xd3a0342b, 0x8971f21e,
0x1b0a7441, 0x4ba3348c, 0xc5be7120, 0xc37632d8, 0xdf359f8d, 0x9b992f2e,
0xe60b6f47, 0x0fe3f11d, 0xe54cda54, 0x1edad891, 0xce6279cf, 0xcd3e7e6f,
0x1618b166, 0xfd2c1d05, 0x848fd2c5, 0xf6fb2299, 0xf523f357, 0xa6327623,
0x93a83531, 0x56cccd02, 0xacf08162, 0x5a75ebb5, 0x6e163697, 0x88d273cc,
0xde966292, 0x81b949d0, 0x4c50901b, 0x71c65614, 0xe6c6c7bd, 0x327a140a,
0x45e1d006, 0xc3f27b9a, 0xc9aa53fd, 0x62a80f00, 0xbb25bfe2, 0x35bdd2f6,
0x71126905, 0xb2040222, 0xb6cbcf7c, 0xcd769c2b, 0x53113ec0, 0x1640e3d3,
0x38abbd60, 0x2547adf0, 0xba38209c, 0xf746ce76, 0x77afa1c5, 0x20756060,
0x85cbfe4e, 0x8ae88dd8, 0x7aaaf9b0, 0x4cf9aa7e, 0x1948c25c, 0x02fb8a8c,
0x01c36ae4, 0xd6ebe1f9, 0x90d4f869, 0xa65cdea0, 0x3f09252d, 0xc208e69f,
0xb74e6132, 0xce77e25b, 0x578fdfe3, 0x3ac372e6,
],
};
////////////////////////////////////////////////////////////////////////////
// fixes based on patch submitted by Peter Wood (#5791)
const xor = function (x, y) {
return (((x>>0x10)^(y>>0x10))<<0x10)|(((x&0xffff)^(y&0xffff))&0xffff);
return (
(((x >> 0x10) ^ (y >> 0x10)) << 0x10) |
(((x & 0xffff) ^ (y & 0xffff)) & 0xffff)
);
};
const f = function (v, box) {
const d=box.s3[v&0xff]; v>>=8;
const c=box.s2[v&0xff]; v>>=8;
const b=box.s1[v&0xff]; v>>=8;
const d = box.s3[v & 0xff];
v >>= 8;
const c = box.s2[v & 0xff];
v >>= 8;
const b = box.s1[v & 0xff];
v >>= 8;
const a = box.s0[v & 0xff];
let r = (((a>>0x10)+(b>>0x10)+(((a&0xffff)+(b&0xffff))>>0x10))<<0x10)|(((a&0xffff)+(b&0xffff))&0xffff);
r = (((r>>0x10)^(c>>0x10))<<0x10)|(((r&0xffff)^(c&0xffff))&0xffff);
return (((r>>0x10)+(d>>0x10)+(((r&0xffff)+(d&0xffff))>>0x10))<<0x10)|(((r&0xffff)+(d&0xffff))&0xffff);
let r =
(((a >> 0x10) +
(b >> 0x10) +
(((a & 0xffff) + (b & 0xffff)) >> 0x10)) <<
0x10) |
(((a & 0xffff) + (b & 0xffff)) & 0xffff);
r =
(((r >> 0x10) ^ (c >> 0x10)) << 0x10) |
(((r & 0xffff) ^ (c & 0xffff)) & 0xffff);
return (
(((r >> 0x10) +
(d >> 0x10) +
(((r & 0xffff) + (d & 0xffff)) >> 0x10)) <<
0x10) |
(((r & 0xffff) + (d & 0xffff)) & 0xffff)
);
};
const eb = function (o, box) {
// TODO: see if this can't be made more efficient
let l = o.left;
@ -333,12 +392,12 @@ const decryptBlock=function(inblock, outblock, box) {
outblock[1] = o.right;
};
crypto.Blowfish = new function() {
crypto.Blowfish = new (function () {
this.createCipher = function (key, modeName) {
return new forge.cipher.BlockCipher({
algorithm: new Blowfish.Algorithm(key, modeName),
key: key,
decrypt: false
decrypt: false,
});
};
@ -346,11 +405,10 @@ crypto.Blowfish = new function() {
return new forge.cipher.BlockCipher({
algorithm: new Blowfish.Algorithm(key, modeName),
key: key,
decrypt: true
decrypt: true,
});
};
}();
})();
crypto.Blowfish.Algorithm = function (key, modeName) {
this.initialize({ key: key });
@ -364,7 +422,7 @@ crypto.Blowfish.Algorithm=function(key, modeName) {
decrypt: function (inblock, outblock) {
decryptBlock(inblock, outblock, _box);
},
}
},
};
switch (modeName.toLowerCase()) {
@ -387,7 +445,6 @@ crypto.Blowfish.Algorithm=function(key, modeName) {
this.mode = new forge.cipher.modes.ecb(modeOption);
break;
}
};
crypto.Blowfish.Algorithm.prototype.initialize = function (options) {
@ -401,7 +458,8 @@ crypto.Blowfish.Algorithm.prototype.initialize=function(options) {
}
// init the boxes
let pos=0, data=0;
let pos = 0,
data = 0;
const res = { left: 0, right: 0 };
const box = {
p: arrayUtil.map(boxes.p.slice(0), function (item) {
@ -409,12 +467,15 @@ crypto.Blowfish.Algorithm.prototype.initialize=function(options) {
for (let j = 0; j < 4; j++) {
data = (data * POW8) | k[pos++ % l];
}
return (((item>>0x10)^(data>>0x10))<<0x10)|(((item&0xffff)^(data&0xffff))&0xffff);
return (
(((item >> 0x10) ^ (data >> 0x10)) << 0x10) |
(((item & 0xffff) ^ (data & 0xffff)) & 0xffff)
);
}),
s0: boxes.s0.slice(0),
s1: boxes.s1.slice(0),
s2: boxes.s2.slice(0),
s3: boxes.s3.slice(0)
s3: boxes.s3.slice(0),
};
// encrypt p and the s boxes

View file

@ -219,7 +219,6 @@ class Scrambler {
this.cache = this.baseScrambler.higherCache[this.rotor.pos];
}
/**
* Run a letter through the scrambler.
* @param {number} i - The letter to transform (as a number)
@ -296,7 +295,14 @@ export class BombeMachine {
* @param {boolean} check - Whether to use the checking machine
* @param {function} update - Function to call to send status updates (optional)
*/
constructor(rotors, reflector, ciphertext, crib, check, update=undefined) {
constructor(
rotors,
reflector,
ciphertext,
crib,
check,
update = undefined,
) {
if (ciphertext.length < crib.length) {
throw new OperationError("Crib overruns supplied ciphertext");
}
@ -312,7 +318,9 @@ export class BombeMachine {
}
for (let i = 0; i < crib.length; i++) {
if (ciphertext[i] === crib[i]) {
throw new OperationError(`Invalid crib: character ${ciphertext[i]} at pos ${i} in both ciphertext and crib`);
throw new OperationError(
`Invalid crib: character ${ciphertext[i]} at pos ${i} in both ciphertext and crib`,
);
}
}
this.ciphertext = ciphertext;
@ -333,14 +341,23 @@ export class BombeMachine {
for (let i = 0; i < 26; i++) {
this.scramblers.push(new Array());
}
this.sharedScrambler = new SharedScrambler(this.baseRotors.slice(1), reflector);
this.sharedScrambler = new SharedScrambler(
this.baseRotors.slice(1),
reflector,
);
this.allScramblers = new Array();
this.indicator = undefined;
for (const edge of edges) {
const cRotor = this.baseRotors[0].copy();
const end1 = a2i(edge.node1.letter);
const end2 = a2i(edge.node2.letter);
const scrambler = new Scrambler(this.sharedScrambler, cRotor, edge.pos, end1, end2);
const scrambler = new Scrambler(
this.sharedScrambler,
cRotor,
edge.pos,
end1,
end2,
);
if (edge.pos === 0) {
this.indicator = scrambler;
}
@ -352,14 +369,23 @@ export class BombeMachine {
// use one of the actual scramblers if there's one in the right position, but if not we'll
// just create one.
if (this.indicator === undefined) {
this.indicator = new Scrambler(this.sharedScrambler, this.baseRotors[0].copy(), 0, undefined, undefined);
this.indicator = new Scrambler(
this.sharedScrambler,
this.baseRotors[0].copy(),
0,
undefined,
undefined,
);
this.allScramblers.push(this.indicator);
}
this.testRegister = a2i(mostConnected.letter);
// This is an arbitrary letter other than the most connected letter
for (const edge of mostConnected.edges) {
this.testInput = [this.testRegister, a2i(edge.getOther(mostConnected).letter)];
this.testInput = [
this.testRegister,
a2i(edge.getOther(mostConnected).letter),
];
break;
}
}
@ -430,7 +456,8 @@ export class BombeMachine {
continue;
}
// This is a newly visited node
const [oLoops, oNNodes, oMostConnected, oNConnections, oEdges] = this.dfs(other);
const [oLoops, oNNodes, oMostConnected, oNConnections, oEdges] =
this.dfs(other);
loops += oLoops;
nNodes += oNNodes;
edges = new Set([...edges, ...oEdges]);
@ -562,7 +589,9 @@ export class BombeMachine {
const plugboard = new Plugboard(stecker);
// The indicator scrambler starts in the right place for the beginning of the ciphertext.
for (let i = 0; i < Math.min(26, this.ciphertext.length); i++) {
const t = this.indicator.transform(plugboard.transform(a2i(this.ciphertext[i])));
const t = this.indicator.transform(
plugboard.transform(a2i(this.ciphertext[i])),
);
res.push(i2a(plugboard.transform(t)));
this.indicator.step(1);
}
@ -676,7 +705,11 @@ export class BombeMachine {
if (newStecker !== "") {
if (stecker !== undefined) {
// Multiple hypotheses can't be ruled out.
return [this.indicator.getPos(), "??", this.tryDecrypt("")];
return [
this.indicator.getPos(),
"??",
this.tryDecrypt(""),
];
}
stecker = newStecker;
}
@ -733,7 +766,7 @@ export class BombeMachine {
// next one needs to step as well)
let n = 1;
for (let j = 1; j < this.baseRotors.length; j++) {
if ((i % Math.pow(26, j)) === 0) {
if (i % Math.pow(26, j) === 0) {
n++;
} else {
break;

View file

@ -11,5 +11,5 @@
*/
export const BRAILLE_LOOKUP = {
ascii: " A1B'K2L@CIF/MSP\"E3H9O6R^DJG>NTQ,*5<-U8V.%[$+X!&;:4\\0Z7(_?W]#Y)=",
dot6: "⠀⠁⠂⠃⠄⠅⠆⠇⠈⠉⠊⠋⠌⠍⠎⠏⠐⠑⠒⠓⠔⠕⠖⠗⠘⠙⠚⠛⠜⠝⠞⠟⠠⠡⠢⠣⠤⠥⠦⠧⠨⠩⠪⠫⠬⠭⠮⠯⠰⠱⠲⠳⠴⠵⠶⠷⠸⠹⠺⠻⠼⠽⠾⠿"
dot6: "⠀⠁⠂⠃⠄⠅⠆⠇⠈⠉⠊⠋⠌⠍⠎⠏⠐⠑⠒⠓⠔⠕⠖⠗⠘⠙⠚⠛⠜⠝⠞⠟⠠⠡⠢⠣⠤⠥⠦⠧⠨⠩⠪⠫⠬⠭⠮⠯⠰⠱⠲⠳⠴⠵⠶⠷⠸⠹⠺⠻⠼⠽⠾⠿",
};

View file

@ -34,7 +34,15 @@ export function drawLine(ctx, startX, startY, endX, endY) {
* @param numYLabels
* @param fontSize
*/
export function drawBarChart(canvas, scores, xAxisLabel, yAxisLabel, numXLabels, numYLabels, 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);
@ -64,14 +72,14 @@ export function drawBarChart(canvas, scores, xAxisLabel, yAxisLabel, numXLabels,
// Bar properties
const barPadding = graphWidth * 0.003,
barWidth = (graphWidth - (barPadding * scores.length)) / scores.length,
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;
const h = (scores[i] / max) * graphHeight;
ctx.fillRect(currX, base - h, barWidth, h);
currX += barWidth + barPadding;
}
@ -83,7 +91,7 @@ export function drawBarChart(canvas, scores, xAxisLabel, yAxisLabel, numXLabels,
if (numXLabels >= scores.length) {
// Mark every score
for (let i = 0; i <= scores.length; i++) {
ctx.fillText(i, currX, base + (bottomPadding * 0.3));
ctx.fillText(i, currX, base + bottomPadding * 0.3);
currX += barWidth + barPadding;
}
} else {
@ -91,7 +99,7 @@ export function drawBarChart(canvas, scores, xAxisLabel, yAxisLabel, numXLabels,
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));
ctx.fillText(val, currX, base + bottomPadding * 0.3);
}
}
@ -101,14 +109,14 @@ export function drawBarChart(canvas, scores, xAxisLabel, yAxisLabel, numXLabels,
if (numYLabels >= max) {
// Mark every increment
for (let i = 0; i <= max; i++) {
currY = base - (i / max * graphHeight) + fontSize / 3;
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;
currY = base - (val / max) * graphHeight + fontSize / 3;
ctx.fillText(val, leftPadding * 0.8, currY);
}
}
@ -116,7 +124,11 @@ export function drawBarChart(canvas, scores, xAxisLabel, yAxisLabel, numXLabels,
// Label x axis
if (xAxisLabel) {
ctx.textAlign = "center";
ctx.fillText(xAxisLabel, graphWidth / 2 + leftPadding, base + bottomPadding * 0.8);
ctx.fillText(
xAxisLabel,
graphWidth / 2 + leftPadding,
base + bottomPadding * 0.8,
);
}
// Label y axis
@ -157,7 +169,12 @@ export function drawScaleBar(canvas, score, max, markings) {
ctx.strokeRect(leftPadding, topPadding, barWidth, barHeight);
// Shade in up to proportion
const grad = ctx.createLinearGradient(leftPadding, 0, barWidth + leftPadding, 0);
const grad = ctx.createLinearGradient(
leftPadding,
0,
barWidth + leftPadding,
0,
);
grad.addColorStop(0, "green");
grad.addColorStop(0.5, "gold");
grad.addColorStop(1, "red");
@ -171,21 +188,21 @@ export function drawScaleBar(canvas, score, max, markings) {
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);
x0 = (barWidth / max) * markings[i].min + leftPadding;
y0 = topPadding + barHeight + bottomPadding * 0.1;
x1 = x0;
y1 = topPadding + barHeight + (bottomPadding * 0.3);
y1 = topPadding + barHeight + bottomPadding * 0.3;
drawLine(ctx, x0, y0, x1, y1);
// Draw max line down
x0 = barWidth / max * markings[i].max + leftPadding;
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;
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);
@ -198,7 +215,7 @@ export function drawScaleBar(canvas, score, max, markings) {
} else {
x0 = x0 + (x1 - x0) / 2;
}
y0 = topPadding + barHeight + (bottomPadding * 0.8);
y0 = topPadding + barHeight + bottomPadding * 0.8;
ctx.fillText(markings[i].label, x0, y0);
}
}

View file

@ -14,13 +14,17 @@ import Utils from "../Utils.mjs";
*/
export const RECORD_DELIMITER_OPTIONS = ["Line feed", "CRLF"];
/**
* @constant
* @default
*/
export const FIELD_DELIMITER_OPTIONS = ["Space", "Comma", "Semi-colon", "Colon", "Tab"];
export const FIELD_DELIMITER_OPTIONS = [
"Space",
"Comma",
"Semi-colon",
"Colon",
"Tab",
];
/**
* Default from colour
@ -30,10 +34,9 @@ export const FIELD_DELIMITER_OPTIONS = ["Space", "Comma", "Semi-colon", "Colon",
*/
export const COLOURS = {
min: "white",
max: "black"
max: "black",
};
/**
* Gets values from input for a plot.
*
@ -44,15 +47,20 @@ export const COLOURS = {
* @param {number} length
* @returns {Object[]}
*/
export function getValues(input, recordDelimiter, fieldDelimiter, columnHeadingsAreIncluded, length) {
export function getValues(
input,
recordDelimiter,
fieldDelimiter,
columnHeadingsAreIncluded,
length,
) {
let headings;
const values = [];
input
.split(recordDelimiter)
.forEach((row, rowIndex) => {
input.split(recordDelimiter).forEach((row, rowIndex) => {
const split = row.split(fieldDelimiter);
if (split.length !== length) throw new OperationError(`Each row must have length ${length}.`);
if (split.length !== length)
throw new OperationError(`Each row must have length ${length}.`);
if (columnHeadingsAreIncluded && rowIndex === 0) {
headings = split;
@ -63,7 +71,6 @@ export function getValues(input, recordDelimiter, fieldDelimiter, columnHeadings
return { headings, values };
}
/**
* Gets values from input for a scatter plot.
*
@ -73,25 +80,32 @@ export function getValues(input, recordDelimiter, fieldDelimiter, columnHeadings
* @param {boolean} columnHeadingsAreIncluded - whether we should skip the first record
* @returns {Object[]}
*/
export function getScatterValues(input, recordDelimiter, fieldDelimiter, columnHeadingsAreIncluded) {
export function getScatterValues(
input,
recordDelimiter,
fieldDelimiter,
columnHeadingsAreIncluded,
) {
let { headings, values } = getValues(
input,
recordDelimiter,
fieldDelimiter,
columnHeadingsAreIncluded,
2
2,
);
if (headings) {
headings = { x: headings[0], y: headings[1] };
}
values = values.map(row => {
values = values.map((row) => {
const x = parseFloat(row[0]),
y = parseFloat(row[1]);
if (Number.isNaN(x)) throw new OperationError("Values must be numbers in base 10.");
if (Number.isNaN(y)) throw new OperationError("Values must be numbers in base 10.");
if (Number.isNaN(x))
throw new OperationError("Values must be numbers in base 10.");
if (Number.isNaN(y))
throw new OperationError("Values must be numbers in base 10.");
return [x, y];
});
@ -99,7 +113,6 @@ export function getScatterValues(input, recordDelimiter, fieldDelimiter, columnH
return { headings, values };
}
/**
* Gets values from input for a scatter plot with colour from the third column.
*
@ -109,25 +122,33 @@ export function getScatterValues(input, recordDelimiter, fieldDelimiter, columnH
* @param {boolean} columnHeadingsAreIncluded - whether we should skip the first record
* @returns {Object[]}
*/
export function getScatterValuesWithColour(input, recordDelimiter, fieldDelimiter, columnHeadingsAreIncluded) {
export function getScatterValuesWithColour(
input,
recordDelimiter,
fieldDelimiter,
columnHeadingsAreIncluded,
) {
let { headings, values } = getValues(
input,
recordDelimiter, fieldDelimiter,
recordDelimiter,
fieldDelimiter,
columnHeadingsAreIncluded,
3
3,
);
if (headings) {
headings = { x: headings[0], y: headings[1] };
}
values = values.map(row => {
values = values.map((row) => {
const x = parseFloat(row[0]),
y = parseFloat(row[1]),
colour = row[2];
if (Number.isNaN(x)) throw new OperationError("Values must be numbers in base 10.");
if (Number.isNaN(y)) throw new OperationError("Values must be numbers in base 10.");
if (Number.isNaN(x))
throw new OperationError("Values must be numbers in base 10.");
if (Number.isNaN(y))
throw new OperationError("Values must be numbers in base 10.");
return [x, y, Utils.escapeHtml(colour)];
});
@ -144,23 +165,30 @@ export function getScatterValuesWithColour(input, recordDelimiter, fieldDelimite
* @param {boolean} columnHeadingsAreIncluded - whether we should skip the first record
* @returns {Object[]}
*/
export function getSeriesValues(input, recordDelimiter, fieldDelimiter, columnHeadingsAreIncluded) {
export function getSeriesValues(
input,
recordDelimiter,
fieldDelimiter,
columnHeadingsAreIncluded,
) {
const { values } = getValues(
input,
recordDelimiter, fieldDelimiter,
recordDelimiter,
fieldDelimiter,
false,
3
3,
);
let xValues = new Set();
const series = {};
values.forEach(row => {
values.forEach((row) => {
const serie = row[0],
xVal = row[1],
val = parseFloat(row[2]);
if (Number.isNaN(val)) throw new OperationError("Values must be numbers in base 10.");
if (Number.isNaN(val))
throw new OperationError("Values must be numbers in base 10.");
xValues.add(xVal);
if (typeof series[serie] === "undefined") series[serie] = {};

View file

@ -166,7 +166,6 @@ export const CHR_ENC_CODE_PAGES = {
"Simplified Chinese GB18030 (54936)": 54936,
};
export const CHR_ENC_SIMPLE_LOOKUP = {};
export const CHR_ENC_SIMPLE_REVERSE_LOOKUP = {};
@ -177,7 +176,6 @@ for (const name in CHR_ENC_CODE_PAGES) {
CHR_ENC_SIMPLE_REVERSE_LOOKUP[CHR_ENC_CODE_PAGES[name]] = simpleName;
}
/**
* Returns the width of the character set for the given codepage.
* For example, UTF-8 is a Single Byte Character Set, whereas
@ -194,7 +192,12 @@ export function chrEncWidth(page) {
const pageStr = page.toString();
// Confirm this page is legitimate
if (!Object.prototype.hasOwnProperty.call(CHR_ENC_SIMPLE_REVERSE_LOOKUP, pageStr))
if (
!Object.prototype.hasOwnProperty.call(
CHR_ENC_SIMPLE_REVERSE_LOOKUP,
pageStr,
)
)
return 0;
// Statically defined code pages
@ -202,10 +205,8 @@ export function chrEncWidth(page) {
return cptable[pageStr].dec.length > 256 ? 2 : 1;
// Cached code pages
if (cptable.utils.cache.sbcs.includes(pageStr))
return 1;
if (cptable.utils.cache.dbcs.includes(pageStr))
return 2;
if (cptable.utils.cache.sbcs.includes(pageStr)) return 1;
if (cptable.utils.cache.dbcs.includes(pageStr)) return 2;
// Dynamically generated code pages
if (Object.prototype.hasOwnProperty.call(cptable.utils.magic, pageStr)) {

View file

@ -6,12 +6,12 @@
export function encode(tempIVP, key, rounds, input) {
const ivp = new Uint8Array(key.concat(tempIVP));
const state = new Array(256).fill(0);
let j = 0, i = 0;
let j = 0,
i = 0;
const result = [];
// Mixing states based off of IV.
for (let i = 0; i < 256; i++)
state[i] = i;
for (let i = 0; i < 256; i++) state[i] = i;
const ivpLength = ivp.length;
for (let r = 0; r < rounds; r++) {
for (let k = 0; k < 256; k++) {
@ -24,7 +24,7 @@ export function encode(tempIVP, key, rounds, input) {
// XOR cipher with key.
for (let x = 0; x < input.length; x++) {
i = (++i) % 256;
i = ++i % 256;
j = (j + state[i]) % 256;
[state[i], state[j]] = [state[j], state[i]];
const n = (state[i] + state[j]) % 256;

View file

@ -33,10 +33,13 @@ export function affineEncode(input, args) {
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];
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();
output +=
alphabet[
(a * alphabet.indexOf(input[i].toLowerCase()) + b) % 26
].toUpperCase();
} else {
// Non-alphabetic characters
output += input[i];
@ -72,11 +75,11 @@ export function genPolybiusSquare (keyword) {
* @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,
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,
};

View file

@ -14,7 +14,7 @@
* @returns {string}
*/
export function replaceVariableNames(input, replacer) {
const tokenRegex = /\\"|"(?:\\"|[^"])*"|(\b[a-z0-9\-_]+\b)/ig;
const tokenRegex = /\\"|"(?:\\"|[^"])*"|(\b[a-z0-9\-_]+\b)/gi;
return input.replace(tokenRegex, (...args) => {
const match = args[0],

View file

@ -21,7 +21,16 @@ export class ColossusComputer {
* @param {Object} control - control switches which specify stepping modes
* @param {Object} starts - rotor start positions
*/
constructor(ciphertext, pattern, qbusin, qbusswitches, control, starts, settotal, limit) {
constructor(
ciphertext,
pattern,
qbusin,
qbusswitches,
control,
starts,
settotal,
limit,
) {
this.ITAlookup = ITA2_TABLE;
this.ReverseITAlookup = {};
for (const letter in this.ITAlookup) {
@ -39,7 +48,6 @@ export class ColossusComputer {
this.settotal = settotal;
this.limitations = limit;
this.allCounters = [0, 0, 0, 0, 0];
this.Zbits = [0, 0, 0, 0, 0]; // Z input is the cipher tape
@ -69,11 +77,24 @@ export class ColossusComputer {
*/
run() {
const result = {
printout: ""
printout: "",
};
// loop until our start positions are back to the beginning
this.rotorPtrs = {X1: this.starts.X1, X2: this.starts.X2, X3: this.starts.X3, X4: this.starts.X4, X5: this.starts.X5, M61: this.starts.M61, M37: this.starts.M37, S1: this.starts.S1, S2: this.starts.S2, S3: this.starts.S3, S4: this.starts.S4, S5: this.starts.S5};
this.rotorPtrs = {
X1: this.starts.X1,
X2: this.starts.X2,
X3: this.starts.X3,
X4: this.starts.X4,
X5: this.starts.X5,
M61: this.starts.M61,
M37: this.starts.M37,
S1: this.starts.S1,
S2: this.starts.S2,
S3: this.starts.S3,
S4: this.starts.S4,
S5: this.starts.S5,
};
// this.rotorPtrs = this.starts;
let runcount = 1;
@ -94,12 +115,15 @@ export class ColossusComputer {
// Only print result if larger than set total
let fastRef = "00";
let slowRef = "00";
if (fast !== "") fastRef = this.rotorPtrs[fast].toString().padStart(2, "0");
if (slow !== "") slowRef = this.rotorPtrs[slow].toString().padStart(2, "0");
if (fast !== "")
fastRef = this.rotorPtrs[fast].toString().padStart(2, "0");
if (slow !== "")
slowRef = this.rotorPtrs[slow].toString().padStart(2, "0");
let printline = "";
for (let c = 0; c < 5; c++) {
if (this.allCounters[c] > this.settotal) {
printline += String.fromCharCode(c+97) + this.allCounters[c]+" ";
printline +=
String.fromCharCode(c + 97) + this.allCounters[c] + " ";
}
}
if (printline !== "") {
@ -111,17 +135,21 @@ export class ColossusComputer {
// Step fast rotor if required
if (fast !== "") {
this.rotorPtrs[fast]++;
if (this.rotorPtrs[fast] > ROTOR_SIZES[fast]) this.rotorPtrs[fast] = 1;
if (this.rotorPtrs[fast] > ROTOR_SIZES[fast])
this.rotorPtrs[fast] = 1;
}
// Step slow rotor if fast rotor has returned to initial start position
if (slow !== "" && this.rotorPtrs[fast] === this.starts[fast]) {
this.rotorPtrs[slow]++;
if (this.rotorPtrs[slow] > ROTOR_SIZES[slow]) this.rotorPtrs[slow] = 1;
if (this.rotorPtrs[slow] > ROTOR_SIZES[slow])
this.rotorPtrs[slow] = 1;
}
runcount++;
} while (JSON.stringify(this.rotorPtrs) !== JSON.stringify(this.starts));
} while (
JSON.stringify(this.rotorPtrs) !== JSON.stringify(this.starts)
);
result.counters = this.allCounters;
result.runcount = runcount;
@ -135,9 +163,21 @@ export class ColossusComputer {
runTape() {
let charZin = "";
this.Xptr = [this.rotorPtrs.X1, this.rotorPtrs.X2, this.rotorPtrs.X3, this.rotorPtrs.X4, this.rotorPtrs.X5];
this.Xptr = [
this.rotorPtrs.X1,
this.rotorPtrs.X2,
this.rotorPtrs.X3,
this.rotorPtrs.X4,
this.rotorPtrs.X5,
];
this.Mptr = [this.rotorPtrs.M37, this.rotorPtrs.M61];
this.Sptr = [this.rotorPtrs.S1, this.rotorPtrs.S2, this.rotorPtrs.S3, this.rotorPtrs.S4, this.rotorPtrs.S5];
this.Sptr = [
this.rotorPtrs.S1,
this.rotorPtrs.S2,
this.rotorPtrs.S3,
this.rotorPtrs.S4,
this.rotorPtrs.S5,
];
// Run full loop of all character on the input tape (Z)
for (let i = 0; i < this.ciphertext.length; i++) {
@ -164,7 +204,6 @@ export class ColossusComputer {
// Step rotors
this.stepThyratrons();
}
}
@ -315,7 +354,11 @@ export class ColossusComputer {
const Qswitch = this.readBusSwitches(row.Qswitches);
// Match switches to bit pattern
for (let s = 0; s < 5; s++) {
if (Qswitch[s] >= 0 && Qswitch[s] !== parseInt(this.Qbits[s], 10)) result = false;
if (
Qswitch[s] >= 0 &&
Qswitch[s] !== parseInt(this.Qbits[s], 10)
)
result = false;
}
// Check for NOT switch
if (row.Negate) result = !result;
@ -331,7 +374,8 @@ export class ColossusComputer {
// Negate the whole column, this allows A OR B by doing NOT(NOT A AND NOT B)
for (let c = 0; c < 5; c++) {
if (this.qbusswitches.condNegateAll && cnt[c] !== -1) cnt[c] = !cnt[c];
if (this.qbusswitches.condNegateAll && cnt[c] !== -1)
cnt[c] = !cnt[c];
}
return cnt;
@ -354,7 +398,7 @@ export class ColossusComputer {
addition = addition ^ this.Qbits[s];
}
}
const equals = (row.Equals===""?-1:(row.Equals==="."?0:1));
const equals = row.Equals === "" ? -1 : row.Equals === "." ? 0 : 1;
if (addition === equals) {
// AND with conditional rows to get final result
if (cnt[0] === -1) cnt[0] = true;
@ -366,12 +410,17 @@ export class ColossusComputer {
// Final check, check for addition section negate
// then, if any column set, from top to bottom of rack, add to counter.
for (let c = 0; c < 5; c++) {
if (this.qbusswitches.addNegateAll && cnt[c] !== -1) cnt[c] = !cnt[c];
if (this.qbusswitches.addNegateAll && cnt[c] !== -1)
cnt[c] = !cnt[c];
if (this.qbusswitches.totalMotor === "" || (this.qbusswitches.totalMotor === "x" && this.totalmotor === 0) || (this.qbusswitches.totalMotor === "." && this.totalmotor === 1)) {
if (
this.qbusswitches.totalMotor === "" ||
(this.qbusswitches.totalMotor === "x" &&
this.totalmotor === 0) ||
(this.qbusswitches.totalMotor === "." && this.totalmotor === 1)
) {
if (cnt[c] === true) this.allCounters[c]++;
}
}
}
@ -386,7 +435,7 @@ export class ColossusComputer {
2: INIT_PATTERNS[pattern].X[2].slice().reverse(),
3: INIT_PATTERNS[pattern].X[3].slice().reverse(),
4: INIT_PATTERNS[pattern].X[4].slice().reverse(),
5: INIT_PATTERNS[pattern].X[5].slice().reverse()
5: INIT_PATTERNS[pattern].X[5].slice().reverse(),
},
M: {
1: INIT_PATTERNS[pattern].M[1].slice().reverse(),
@ -397,8 +446,8 @@ export class ColossusComputer {
2: INIT_PATTERNS[pattern].S[2].slice().reverse(),
3: INIT_PATTERNS[pattern].S[3].slice().reverse(),
4: INIT_PATTERNS[pattern].S[4].slice().reverse(),
5: INIT_PATTERNS[pattern].S[5].slice().reverse()
}
5: INIT_PATTERNS[pattern].S[5].slice().reverse(),
},
};
}
@ -413,5 +462,4 @@ export class ColossusComputer {
}
return output;
}
}

View file

@ -33,7 +33,7 @@ export const FORMATS = [
"Geohash",
"Military Grid Reference System",
"Ordnance Survey National Grid",
"Universal Transverse Mercator"
"Universal Transverse Mercator",
];
/**
@ -58,7 +58,15 @@ const NO_CHANGE = [
* @param {number} precision - Precision of the result
* @returns {string} A formatted string of the converted co-ordinates
*/
export function convertCoordinates (input, inFormat, inDelim, outFormat, outDelim, includeDir, precision) {
export function convertCoordinates(
input,
inFormat,
inDelim,
outFormat,
outDelim,
includeDir,
precision,
) {
let isPair = false,
split,
latlon,
@ -83,7 +91,9 @@ export function convertCoordinates (input, inFormat, inDelim, outFormat, outDeli
// Try to detect a delimiter in the input.
inDelim = findDelim(input);
if (inDelim === null) {
throw new OperationError("Unable to detect the input delimiter automatically.");
throw new OperationError(
"Unable to detect the input delimiter automatically.",
);
}
} else if (!inDelim.includes("Direction")) {
// Convert the delimiter argument value to the actual character
@ -94,7 +104,9 @@ export function convertCoordinates (input, inFormat, inDelim, outFormat, outDeli
// Try to detect the format of the input data
inFormat = findFormat(input, inDelim);
if (inFormat === null) {
throw new OperationError("Unable to detect the input format automatically.");
throw new OperationError(
"Unable to detect the input format automatically.",
);
}
}
@ -154,11 +166,23 @@ export function convertCoordinates (input, inFormat, inDelim, outFormat, outDeli
splitLong = splitInput(split[1]);
if (splitLat.length >= 3 && splitLong.length >= 3) {
lat = convDMSToDD(splitLat[0], splitLat[1], splitLat[2], 10);
lon = convDMSToDD(splitLong[0], splitLong[1], splitLong[2], 10);
lat = convDMSToDD(
splitLat[0],
splitLat[1],
splitLat[2],
10,
);
lon = convDMSToDD(
splitLong[0],
splitLong[1],
splitLong[2],
10,
);
latlon = new LatLonEllipsoidal(lat.degrees, lon.degrees);
} else {
throw new OperationError("Invalid co-ordinate format for Degrees Minutes Seconds");
throw new OperationError(
"Invalid co-ordinate format for Degrees Minutes Seconds",
);
}
} else {
// Not a pair, so only try to convert one set of co-ordinates
@ -167,7 +191,9 @@ export function convertCoordinates (input, inFormat, inDelim, outFormat, outDeli
lat = convDMSToDD(splitLat[0], splitLat[1], splitLat[2]);
latlon = new LatLonEllipsoidal(lat.degrees, lat.degrees);
} else {
throw new OperationError("Invalid co-ordinate format for Degrees Minutes Seconds");
throw new OperationError(
"Invalid co-ordinate format for Degrees Minutes Seconds",
);
}
}
break;
@ -176,7 +202,9 @@ export function convertCoordinates (input, inFormat, inDelim, outFormat, outDeli
splitLat = splitInput(split[0]);
splitLong = splitInput(split[1]);
if (splitLat.length !== 2 || splitLong.length !== 2) {
throw new OperationError("Invalid co-ordinate format for Degrees Decimal Minutes.");
throw new OperationError(
"Invalid co-ordinate format for Degrees Decimal Minutes.",
);
}
// Convert to decimal degrees, and then convert to a geodesy object
lat = convDDMToDD(splitLat[0], splitLat[1], 10);
@ -186,7 +214,9 @@ export function convertCoordinates (input, inFormat, inDelim, outFormat, outDeli
// Not a pair, so only try to convert one set of co-ordinates
splitLat = splitInput(input);
if (splitLat.length !== 2) {
throw new OperationError("Invalid co-ordinate format for Degrees Decimal Minutes.");
throw new OperationError(
"Invalid co-ordinate format for Degrees Decimal Minutes.",
);
}
lat = convDDMToDD(splitLat[0], splitLat[1], 10);
latlon = new LatLonEllipsoidal(lat.degrees, lat.degrees);
@ -197,14 +227,18 @@ export function convertCoordinates (input, inFormat, inDelim, outFormat, outDeli
splitLat = splitInput(split[0]);
splitLong = splitInput(split[1]);
if (splitLat.length !== 1 || splitLong.length !== 1) {
throw new OperationError("Invalid co-ordinate format for Decimal Degrees.");
throw new OperationError(
"Invalid co-ordinate format for Decimal Degrees.",
);
}
latlon = new LatLonEllipsoidal(splitLat[0], splitLong[0]);
} else {
// Not a pair, so only try to convert one set of co-ordinates
splitLat = splitInput(split[0]);
if (splitLat.length !== 1) {
throw new OperationError("Invalid co-ordinate format for Decimal Degrees.");
throw new OperationError(
"Invalid co-ordinate format for Decimal Degrees.",
);
}
latlon = new LatLonEllipsoidal(splitLat[0], splitLat[0]);
}
@ -221,11 +255,11 @@ export function convertCoordinates (input, inFormat, inDelim, outFormat, outDeli
const dirs = input.toUpperCase().match(/[NESW]/g);
if (dirs && dirs.length >= 1) {
// Make positive lat/lon values with S/W directions into negative values
if (dirs[0] === "S" || dirs[0] === "W" && latlon.lat > 0) {
if (dirs[0] === "S" || (dirs[0] === "W" && latlon.lat > 0)) {
latlon.lat = -latlon.lat;
}
if (dirs.length >= 2) {
if (dirs[1] === "S" || dirs[1] === "W" && latlon.lon > 0) {
if (dirs[1] === "S" || (dirs[1] === "W" && latlon.lon > 0)) {
latlon.lon = -latlon.lon;
}
}
@ -275,7 +309,9 @@ export function convertCoordinates (input, inFormat, inDelim, outFormat, outDeli
case "Ordnance Survey National Grid":
osng = OsGridRef.latLonToOsGrid(latlon);
if (osng.toString() === "") {
throw new OperationError("Could not convert co-ordinates to OS National Grid. Are the co-ordinates in range?");
throw new OperationError(
"Could not convert co-ordinates to OS National Grid. Are the co-ordinates in range?",
);
}
// OSNG wants a precision that's an even number between 2 and 10
if (precision % 2 !== 0) {
@ -343,7 +379,7 @@ export function convertCoordinates (input, inFormat, inDelim, outFormat, outDeli
function splitInput(input) {
const split = [];
input.split(/\s+/).forEach(item => {
input.split(/\s+/).forEach((item) => {
// Remove any character that isn't a digit, decimal point or negative sign
item = item.replace(/[^0-9.-]/g, "");
if (item.length > 0) {
@ -365,15 +401,15 @@ function splitInput (input) {
*/
function convDMSToDD(degrees, minutes, seconds, precision) {
const absDegrees = Math.abs(degrees);
let conv = absDegrees + (minutes / 60) + (seconds / 3600);
let conv = absDegrees + minutes / 60 + seconds / 3600;
let outString = round(conv, precision) + "°";
if (isNegativeZero(degrees) || degrees < 0) {
conv = -conv;
outString = "-" + outString;
}
return {
"degrees": conv,
"string": outString
degrees: conv,
string: outString,
};
}
@ -394,8 +430,8 @@ function convDDMToDD (degrees, minutes, precision) {
outString = "-" + outString;
}
return {
"degrees": conv,
"string": outString
degrees: conv,
string: outString,
};
}
@ -409,8 +445,8 @@ function convDDMToDD (degrees, minutes, precision) {
*/
function convDDToDD(degrees, precision) {
return {
"degrees": degrees,
"string": round(degrees, precision) + "°"
degrees: degrees,
string: round(degrees, precision) + "°",
};
}
@ -425,17 +461,20 @@ function convDDToDMS (decDegrees, precision) {
const absDegrees = Math.abs(decDegrees);
let degrees = Math.floor(absDegrees);
const minutes = Math.floor(60 * (absDegrees - degrees)),
seconds = round(3600 * (absDegrees - degrees) - 60 * minutes, precision);
let outString = degrees + "° " + minutes + "' " + seconds + "\"";
seconds = round(
3600 * (absDegrees - degrees) - 60 * minutes,
precision,
);
let outString = degrees + "° " + minutes + "' " + seconds + '"';
if (isNegativeZero(decDegrees) || decDegrees < 0) {
degrees = -degrees;
outString = "-" + outString;
}
return {
"degrees": degrees,
"minutes": minutes,
"seconds": seconds,
"string": outString
degrees: degrees,
minutes: minutes,
seconds: seconds,
string: outString,
};
}
@ -458,9 +497,9 @@ function convDDToDDM (decDegrees, precision) {
}
return {
"degrees": degrees,
"minutes": decMinutes,
"string": outString,
degrees: degrees,
minutes: decMinutes,
string: outString,
};
}
@ -534,7 +573,9 @@ export function findDirs(input, delim) {
*/
export function findFormat(input, delim) {
let testData;
const mgrsPattern = new RegExp(/^[0-9]{2}\s?[C-HJ-NP-X]{1}\s?[A-HJ-NP-Z][A-HJ-NP-V]\s?[0-9\s]+/),
const mgrsPattern = new RegExp(
/^[0-9]{2}\s?[C-HJ-NP-X]{1}\s?[A-HJ-NP-Z][A-HJ-NP-V]\s?[0-9\s]+/,
),
osngPattern = new RegExp(/^[A-HJ-Z]{2}\s+[0-9\s]+$/),
geohashPattern = new RegExp(/^[0123456789BCDEFGHJKMNPQRSTUVWXYZ]+$/),
utmPattern = new RegExp(/^[0-9]{2}\s?[C-HJ-NP-X]\s[0-9.]+\s?[0-9.]+$/),
@ -636,12 +677,12 @@ export function findDelim (input) {
*/
export function realDelim(delim) {
return {
"Auto": "Auto",
"Space": " ",
Auto: "Auto",
Space: " ",
"\\n": "\n",
"Comma": ",",
Comma: ",",
"Semi-colon": ";",
"Colon": ":"
Colon: ":",
}[delim];
}
@ -652,7 +693,7 @@ export function realDelim (delim) {
* @returns {boolean}
*/
function isNegativeZero(zero) {
return zero === 0 && (1/zero < 0);
return zero === 0 && 1 / zero < 0;
}
/**

View file

@ -6,4 +6,5 @@
* @license Apache-2.0
*/
export const cryptNotice = "WARNING: Cryptographic operations in CyberChef should not be relied upon to provide security in any situation. No guarantee is offered for their correctness. We advise you not to use keys generated from CyberChef in operational contexts.";
export const cryptNotice =
"WARNING: Cryptographic operations in CyberChef should not be relied upon to provide security in any situation. No guarantee is offered for their correctness. We advise you not to use keys generated from CyberChef in operational contexts.";

View file

@ -9,7 +9,12 @@
/**
* DateTime units.
*/
export const UNITS = ["Seconds (s)", "Milliseconds (ms)", "Microseconds (μs)", "Nanoseconds (ns)"];
export const UNITS = [
"Seconds (s)",
"Milliseconds (ms)",
"Microseconds (μs)",
"Nanoseconds (ns)",
];
/**
* DateTime formats.
@ -17,31 +22,31 @@ export const UNITS = ["Seconds (s)", "Milliseconds (ms)", "Microseconds (μs)",
export const DATETIME_FORMATS = [
{
name: "Standard date and time",
value: "DD/MM/YYYY HH:mm:ss"
value: "DD/MM/YYYY HH:mm:ss",
},
{
name: "American-style date and time",
value: "MM/DD/YYYY HH:mm:ss"
value: "MM/DD/YYYY HH:mm:ss",
},
{
name: "International date and time",
value: "YYYY-MM-DD HH:mm:ss"
value: "YYYY-MM-DD HH:mm:ss",
},
{
name: "Verbose date and time",
value: "dddd Do MMMM YYYY HH:mm:ss Z z"
value: "dddd Do MMMM YYYY HH:mm:ss Z z",
},
{
name: "UNIX timestamp (seconds)",
value: "X"
value: "X",
},
{
name: "UNIX timestamp offset (milliseconds)",
value: "x"
value: "x",
},
{
name: "Automatic",
value: ""
value: "",
},
];
@ -310,4 +315,3 @@ export const FORMAT_EXAMPLES = `Format string tokens:
</tr>
</tbody>
</table>`;

View file

@ -8,7 +8,6 @@
import Utils from "../Utils.mjs";
/**
* Convert a string of decimal values into a byte array.
*

View file

@ -9,32 +9,79 @@
/**
* Generic sequence delimiters.
*/
export const DELIM_OPTIONS = ["Space", "Comma", "Semi-colon", "Colon", "Line feed", "CRLF"];
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"];
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"];
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"];
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)"];
export const INPUT_DELIM_OPTIONS = [
"Line feed",
"CRLF",
"Space",
"Comma",
"Semi-colon",
"Colon",
"Nothing (separate chars)",
];
/**
* Arithmetic sequence delimiters
*/
export const ARITHMETIC_DELIM_OPTIONS = ["Line feed", "Space", "Comma", "Semi-colon", "Colon", "CRLF"];
export const ARITHMETIC_DELIM_OPTIONS = [
"Line feed",
"Space",
"Comma",
"Semi-colon",
"Colon",
"CRLF",
];
/**
* Hash delimiters
@ -44,7 +91,13 @@ export const HASH_DELIM_OPTIONS = ["Line feed", "CRLF", "Space", "Comma"];
/**
* IP delimiters
*/
export const IP_DELIM_OPTIONS = ["Line feed", "CRLF", "Space", "Comma", "Semi-colon"];
export const IP_DELIM_OPTIONS = [
"Line feed",
"CRLF",
"Space",
"Comma",
"Semi-colon",
];
/**
* Split delimiters.
@ -56,7 +109,7 @@ export const SPLIT_DELIM_OPTIONS = [
{ name: "CRLF", value: "\\r\\n" },
{ name: "Semi-colon", value: ";" },
{ name: "Colon", value: ":" },
{name: "Nothing (separate chars)", value: ""}
{ name: "Nothing (separate chars)", value: "" },
];
/**
@ -69,7 +122,7 @@ export const JOIN_DELIM_OPTIONS = [
{ name: "Comma", value: "," },
{ name: "Semi-colon", value: ";" },
{ name: "Colon", value: ":" },
{name: "Nothing (join chars)", value: ""}
{ name: "Nothing (join chars)", value: "" },
];
/**
@ -79,5 +132,5 @@ export const RGBA_DELIM_OPTIONS = [
{ name: "Comma", value: "," },
{ name: "Space", value: " " },
{ name: "CRLF", value: "\\r\\n" },
{name: "Line Feed", value: "\n"}
{ name: "Line Feed", value: "\n" },
];

View file

@ -91,16 +91,24 @@ export class Rotor {
*/
constructor(wiring, steps, ringSetting, initialPosition) {
if (!/^[A-Z]{26}$/.test(wiring)) {
throw new OperationError("Rotor wiring must be 26 unique uppercase letters");
throw new OperationError(
"Rotor wiring must be 26 unique uppercase letters",
);
}
if (!/^[A-Z]{0,26}$/.test(steps)) {
throw new OperationError("Rotor steps must be 0-26 unique uppercase letters");
throw new OperationError(
"Rotor steps must be 0-26 unique uppercase letters",
);
}
if (!/^[A-Z]$/.test(ringSetting)) {
throw new OperationError("Rotor ring setting must be exactly one uppercase letter");
throw new OperationError(
"Rotor ring setting must be exactly one uppercase letter",
);
}
if (!/^[A-Z]$/.test(initialPosition)) {
throw new OperationError("Rotor initial position must be exactly one uppercase letter");
throw new OperationError(
"Rotor initial position must be exactly one uppercase letter",
);
}
this.map = new Array(26);
this.revMap = new Array(26);
@ -113,7 +121,9 @@ export class Rotor {
uniq[b] = true;
}
if (Object.keys(uniq).length !== LETTERS.length) {
throw new OperationError("Rotor wiring must have each letter exactly once");
throw new OperationError(
"Rotor wiring must have each letter exactly once",
);
}
const rs = a2i(ringSetting);
this.steps = new Set();
@ -152,7 +162,10 @@ export class Rotor {
* @returns {number}
*/
revTransform(c) {
return Utils.mod(this.revMap[Utils.mod(c + this.pos, 26)] - this.pos, 26);
return Utils.mod(
this.revMap[Utils.mod(c + this.pos, 26)] - this.pos,
26,
);
}
}
@ -175,20 +188,28 @@ class PairMapBase {
if (pairs === "") {
return;
}
pairs.split(/\s+/).forEach(pair => {
pairs.split(/\s+/).forEach((pair) => {
if (!/^[A-Z]{2}$/.test(pair)) {
throw new OperationError(name + " must be a whitespace-separated list of uppercase letter pairs");
throw new OperationError(
name +
" must be a whitespace-separated list of uppercase letter pairs",
);
}
const a = a2i(pair[0]), b = a2i(pair[1]);
const a = a2i(pair[0]),
b = a2i(pair[1]);
if (a === b) {
// self-stecker
return;
}
if (Object.prototype.hasOwnProperty.call(this.map, a)) {
throw new OperationError(`${name} connects ${pair[0]} more than once`);
throw new OperationError(
`${name} connects ${pair[0]} more than once`,
);
}
if (Object.prototype.hasOwnProperty.call(this.map, b)) {
throw new OperationError(`${name} connects ${pair[1]} more than once`);
throw new OperationError(
`${name} connects ${pair[1]} more than once`,
);
}
this.map[a] = b;
this.map[b] = a;
@ -234,7 +255,9 @@ export class Reflector extends PairMapBase {
super(pairs, "Reflector");
const s = Object.keys(this.map).length;
if (s !== 26) {
throw new OperationError("Reflector must have exactly 13 pairs covering every letter");
throw new OperationError(
"Reflector must have exactly 13 pairs covering every letter",
);
}
const optMap = new Array(26);
for (const x of Object.keys(this.map)) {

View file

@ -18,7 +18,13 @@
* @param {boolean} [unique=false] - Whether to unique the results
* @returns {string}
*/
export function search(input, searchRegex, removeRegex=null, sortBy=null, unique=false) {
export function search(
input,
searchRegex,
removeRegex = null,
sortBy = null,
unique = false,
) {
let results = [];
let match;
@ -28,8 +34,7 @@ export function search(input, searchRegex, removeRegex=null, sortBy=null, unique
searchRegex.lastIndex++;
}
if (removeRegex && removeRegex.test(match[0]))
continue;
if (removeRegex && removeRegex.test(match[0])) continue;
results.push(match[0]);
}
@ -45,20 +50,23 @@ export function search(input, searchRegex, removeRegex=null, sortBy=null, unique
return results;
}
/**
* URL regular expression
*/
const protocol = "[A-Z]+://",
hostname = "[-\\w]+(?:\\.\\w[-\\w]*)+",
port = ":\\d+",
path = "/[^.!,?\"<>\\[\\]{}\\s\\x7F-\\xFF]*" +
"(?:[.!,?]+[^.!,?\"<>\\[\\]{}\\s\\x7F-\\xFF]+)*";
export const URL_REGEX = new RegExp(protocol + hostname + "(?:" + port + ")?(?:" + path + ")?", "ig");
path =
'/[^.!,?"<>\\[\\]{}\\s\\x7F-\\xFF]*' +
'(?:[.!,?]+[^.!,?"<>\\[\\]{}\\s\\x7F-\\xFF]+)*';
export const URL_REGEX = new RegExp(
protocol + hostname + "(?:" + port + ")?(?:" + path + ")?",
"ig",
);
/**
* Domain name regular expression
*/
export const DOMAIN_REGEX = /\b((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,63}\b/ig;
export const DOMAIN_REGEX =
/\b((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,63}\b/gi;

File diff suppressed because it is too large Load diff

View file

@ -9,7 +9,6 @@
import { FILE_SIGNATURES } from "./FileSignatures.mjs";
import { sendStatusMessage } from "../Utils.mjs";
/**
* Checks whether a signature matches a buffer.
*
@ -36,7 +35,6 @@ function signatureMatches(sig, buf, offset=0) {
}
}
/**
* Checks whether a set of bytes match the given buffer.
*
@ -52,25 +50,23 @@ function bytesMatch(sig, buf, offset=0) {
const pos = parseInt(sigoffset, 10) + offset;
switch (typeof sig[sigoffset]) {
case "number": // Static check
if (buf[pos] !== sig[sigoffset])
return false;
if (buf[pos] !== sig[sigoffset]) return false;
break;
case "object": // Array of options
if (sig[sigoffset].indexOf(buf[pos]) < 0)
return false;
if (sig[sigoffset].indexOf(buf[pos]) < 0) return false;
break;
case "function": // More complex calculation
if (!sig[sigoffset](buf[pos]))
return false;
if (!sig[sigoffset](buf[pos])) return false;
break;
default:
throw new Error(`Unrecognised signature type at offset ${sigoffset}`);
throw new Error(
`Unrecognised signature type at offset ${sigoffset}`,
);
}
}
return true;
}
/**
* Given a buffer, detects magic byte sequences at specific positions and returns the
* extension and mime type.
@ -104,7 +100,7 @@ export function detectFileType(buf, categories=Object.keys(FILE_SIGNATURES)) {
for (const cat in signatures) {
const category = signatures[cat];
category.forEach(filetype => {
category.forEach((filetype) => {
if (signatureMatches(filetype.signature, buf)) {
matchingFiles.push(filetype);
}
@ -113,7 +109,6 @@ export function detectFileType(buf, categories=Object.keys(FILE_SIGNATURES)) {
return matchingFiles;
}
/**
* Given a buffer, searches for magic byte sequences at all possible positions and returns
* the extensions and mime types.
@ -128,7 +123,10 @@ export function detectFileType(buf, categories=Object.keys(FILE_SIGNATURES)) {
* @returns {string} foundFiles.fileDetails.mime - Mime type
* @returns {string} [foundFiles.fileDetails.desc] - Description
*/
export function scanForFileTypes(buf, categories=Object.keys(FILE_SIGNATURES)) {
export function scanForFileTypes(
buf,
categories = Object.keys(FILE_SIGNATURES),
) {
if (!(buf && buf.length > 1)) {
return [];
}
@ -147,16 +145,20 @@ export function scanForFileTypes(buf, categories=Object.keys(FILE_SIGNATURES)) {
for (let i = 0; i < category.length; i++) {
const filetype = category[i];
const sigs = filetype.signature.length ? filetype.signature : [filetype.signature];
const sigs = filetype.signature.length
? filetype.signature
: [filetype.signature];
sigs.forEach(sig => {
sigs.forEach((sig) => {
let pos = 0;
while ((pos = locatePotentialSig(buf, sig, pos)) >= 0) {
if (bytesMatch(sig, buf, pos)) {
sendStatusMessage(`Found potential signature for ${filetype.name} at pos ${pos}`);
sendStatusMessage(
`Found potential signature for ${filetype.name} at pos ${pos}`,
);
foundFiles.push({
offset: pos,
fileDetails: filetype
fileDetails: filetype,
});
}
pos++;
@ -171,7 +173,6 @@ export function scanForFileTypes(buf, categories=Object.keys(FILE_SIGNATURES)) {
});
}
/**
* Fastcheck function to quickly scan the buffer for the first byte in a signature.
*
@ -202,7 +203,6 @@ function locatePotentialSig(buf, sig, offset) {
}
}
/**
* Detects whether the given buffer is a file of the type specified.
*
@ -230,7 +230,6 @@ export function isType(type, buf) {
}
}
/**
* Detects whether the given buffer contains an image file.
*
@ -241,7 +240,6 @@ export function isImage(buf) {
return isType("image", buf);
}
/**
* Attempts to extract a file from a data stream given its offset and extractor function.
*
@ -255,13 +253,21 @@ export function isImage(buf) {
*/
export function extractFile(bytes, fileDetail, offset) {
if (fileDetail.extractor) {
sendStatusMessage(`Attempting to extract ${fileDetail.name} at pos ${offset}...`);
sendStatusMessage(
`Attempting to extract ${fileDetail.name} at pos ${offset}...`,
);
const fileData = fileDetail.extractor(bytes, offset);
const ext = fileDetail.extension.split(",")[0];
return new File([fileData], `extracted_at_0x${offset.toString(16)}.${ext}`, {
type: fileDetail.mime
});
return new File(
[fileData],
`extracted_at_0x${offset.toString(16)}.${ext}`,
{
type: fileDetail.mime,
},
);
}
throw new Error(`No extraction algorithm available for "${fileDetail.mime}" files`);
throw new Error(
`No extraction algorithm available for "${fileDetail.mime}" files`,
);
}

View file

@ -15,6 +15,6 @@
*/
export function getLabelIndex(name, state) {
return state.opList.findIndex((operation) => {
return (operation.name === "Label") && (name === operation.ingValues[0]);
return operation.name === "Label" && name === operation.ingValues[0];
});
}

View file

@ -24,7 +24,7 @@ export const DEFAULT_WEIGHTS = {
leadingLetterPenalty: -5, // penalty applied for every letter in str before the first match
maxLeadingLetterPenalty: -15, // maximum penalty for leading letters
unmatchedLetterPenalty: -1
unmatchedLetterPenalty: -1,
};
/**
@ -35,7 +35,12 @@ export const DEFAULT_WEIGHTS = {
* @returns [boolean, number] a boolean which tells if pattern was
* found or not and a search score
*/
export function fuzzyMatch(pattern, str, global=false, weights=DEFAULT_WEIGHTS) {
export function fuzzyMatch(
pattern,
str,
global = false,
weights = DEFAULT_WEIGHTS,
) {
const recursionCount = 0;
const recursionLimit = 10;
const matches = [];
@ -53,7 +58,7 @@ export function fuzzyMatch(pattern, str, global=false, weights=DEFAULT_WEIGHTS)
0 /* nextMatch */,
recursionCount,
recursionLimit,
weights
weights,
);
}
@ -76,7 +81,7 @@ export function fuzzyMatch(pattern, str, global=false, weights=DEFAULT_WEIGHTS)
0 /* nextMatch */,
recursionCount,
recursionLimit,
weights
weights,
);
if (foundMatch) results.push([foundMatch, score, [...idxs]]);
strCurrIndex = idxs[idxs.length - 1] + 1;
@ -98,7 +103,7 @@ function fuzzyMatchRecursive(
nextMatch,
recursionCount,
recursionLimit,
weights
weights,
) {
let outScore = 0;
@ -122,7 +127,8 @@ function fuzzyMatchRecursive(
while (patternCurIndex < pattern.length && strCurrIndex < str.length) {
// Match found.
if (
pattern[patternCurIndex].toLowerCase() === str[strCurrIndex].toLowerCase()
pattern[patternCurIndex].toLowerCase() ===
str[strCurrIndex].toLowerCase()
) {
if (nextMatch >= maxMatches) {
return [false, outScore, []];
@ -133,7 +139,8 @@ function fuzzyMatchRecursive(
firstMatch = false;
}
const [matched, recursiveScore, recursiveMatches] = fuzzyMatchRecursive(
const [matched, recursiveScore, recursiveMatches] =
fuzzyMatchRecursive(
pattern,
str,
patternCurIndex,
@ -144,7 +151,7 @@ function fuzzyMatchRecursive(
nextMatch,
recursionCount,
recursionLimit,
weights
weights,
);
if (matched) {
@ -170,9 +177,9 @@ function fuzzyMatchRecursive(
// Apply leading letter penalty
let penalty = weights.leadingLetterPenalty * matches[0];
penalty =
penalty < weights.maxLeadingLetterPenalty ?
weights.maxLeadingLetterPenalty :
penalty;
penalty < weights.maxLeadingLetterPenalty
? weights.maxLeadingLetterPenalty
: penalty;
outScore += penalty;
// Apply unmatched penalty
@ -201,7 +208,8 @@ function fuzzyMatchRecursive(
) {
outScore += weights.camelBonus;
}
const isNeighbourSeparator = neighbor === "_" || neighbor === " ";
const isNeighbourSeparator =
neighbor === "_" || neighbor === " ";
if (isNeighbourSeparator) {
outScore += weights.separatorBonus;
}
@ -239,7 +247,7 @@ export function calcMatchRanges(matches) {
let start = matches[0],
curr = start;
matches.forEach(m => {
matches.forEach((m) => {
if (m === curr || m === curr + 1) curr = m;
else {
ranges.push([start, curr - start + 1]);

View file

@ -10,7 +10,6 @@
import Utils from "../Utils.mjs";
import CryptoApi from "crypto-api/src/crypto-api.mjs";
/**
* Generic hash function.
*
@ -25,4 +24,3 @@ export function runHash(name, input, options={}) {
hasher.update(msg);
return CryptoApi.encoder.toHex(hasher.finalize());
}

View file

@ -9,7 +9,6 @@
import Utils from "../Utils.mjs";
import OperationError from "../errors/OperationError.mjs";
/**
* Convert a byte array into a hex string.
*
@ -28,12 +27,18 @@ import OperationError from "../errors/OperationError.mjs";
* // returns "0x0a,0x14,0x1e"
* toHex([10,20,30], "0x", 2, ",")
*/
export function toHex(data, delim=" ", padding=2, extraDelim="", lineSize=0) {
export function toHex(
data,
delim = " ",
padding = 2,
extraDelim = "",
lineSize = 0,
) {
if (!data) return "";
if (data instanceof ArrayBuffer) data = new Uint8Array(data);
let output = "";
const prepend = (delim === "0x" || delim === "\\x");
const prepend = delim === "0x" || delim === "\\x";
for (let i = 0; i < data.length; i++) {
const hex = data[i].toString(16).padStart(padding, "0");
@ -43,7 +48,7 @@ export function toHex(data, delim=" ", padding=2, extraDelim="", lineSize=0) {
output += extraDelim;
}
// Add LF after each lineSize amount of bytes but not at the end
if ((i !== data.length - 1) && ((i + 1) % lineSize === 0)) {
if (i !== data.length - 1 && (i + 1) % lineSize === 0) {
output += "\n";
}
}
@ -59,7 +64,6 @@ export function toHex(data, delim=" ", padding=2, extraDelim="", lineSize=0) {
}
}
/**
* Convert a byte array into a hex string as efficiently as possible with no options.
*
@ -84,7 +88,6 @@ export function toHexFast(data) {
return output.join("");
}
/**
* Convert a hex string into a byte array.
*
@ -105,7 +108,8 @@ export function fromHex(data, delim="Auto", byteLen=2) {
throw new OperationError("Byte length must be a positive integer");
if (delim !== "None") {
const delimRegex = delim === "Auto" ? /[^a-f\d]|0x/gi : Utils.regexRep(delim);
const delimRegex =
delim === "Auto" ? /[^a-f\d]|0x/gi : Utils.regexRep(delim);
data = data.split(delimRegex);
} else {
data = [data];
@ -120,12 +124,22 @@ export function fromHex(data, delim="Auto", byteLen=2) {
return output;
}
/**
* To Hexadecimal delimiters.
*/
export const TO_HEX_DELIM_OPTIONS = ["Space", "Percent", "Comma", "Semi-colon", "Colon", "Line feed", "CRLF", "0x", "0x with comma", "\\x", "None"];
export const TO_HEX_DELIM_OPTIONS = [
"Space",
"Percent",
"Comma",
"Semi-colon",
"Colon",
"Line feed",
"CRLF",
"0x",
"0x with comma",
"\\x",
"None",
];
/**
* From Hexadecimal delimiters.

View file

@ -20,7 +20,12 @@ import OperationError from "../errors/OperationError.mjs";
* @param {boolean} allowLargeList
* @returns {string}
*/
export function ipv4CidrRange(cidr, includeNetworkInfo, enumerateAddresses, allowLargeList) {
export function ipv4CidrRange(
cidr,
includeNetworkInfo,
enumerateAddresses,
allowLargeList,
) {
const network = strToIpv4(cidr[1]),
cidrRange = parseInt(cidr[2], 10);
let output = "";
@ -29,7 +34,7 @@ export function ipv4CidrRange(cidr, includeNetworkInfo, enumerateAddresses, allo
throw new OperationError("IPv4 CIDR must be less than 32");
}
const mask = ~(0xFFFFFFFF >>> cidrRange),
const mask = ~(0xffffffff >>> cidrRange),
ip1 = network & mask,
ip2 = ip1 | ~mask;
@ -38,7 +43,8 @@ export function ipv4CidrRange(cidr, includeNetworkInfo, enumerateAddresses, allo
output += "CIDR: " + cidrRange + "\n";
output += "Mask: " + ipv4ToStr(mask) + "\n";
output += "Range: " + ipv4ToStr(ip1) + " - " + ipv4ToStr(ip2) + "\n";
output += "Total addresses in range: " + (((ip2 - ip1) >>> 0) + 1) + "\n\n";
output +=
"Total addresses in range: " + (((ip2 - ip1) >>> 0) + 1) + "\n\n";
}
if (enumerateAddresses) {
@ -74,10 +80,9 @@ export function ipv6CidrRange(cidr, includeNetworkInfo) {
const mask = genIpv6Mask(cidrRange);
let totalDiff = "";
for (let i = 0; i < 8; i++) {
ip1[i] = network[i] & mask[i];
ip2[i] = ip1[i] | (~mask[i] & 0x0000FFFF);
ip2[i] = ip1[i] | (~mask[i] & 0x0000ffff);
totalDiff = (ip2[i] - ip1[i]).toString(2);
if (totalDiff !== "0") {
@ -93,7 +98,10 @@ export function ipv6CidrRange(cidr, includeNetworkInfo) {
output += "CIDR: " + cidrRange + "\n";
output += "Mask: " + ipv6ToStr(mask) + "\n";
output += "Range: " + ipv6ToStr(ip1) + " - " + ipv6ToStr(ip2) + "\n";
output += "Total addresses in range: " + (parseInt(total.join(""), 2) + 1) + "\n\n";
output +=
"Total addresses in range: " +
(parseInt(total.join(""), 2) + 1) +
"\n\n";
}
return output;
@ -109,7 +117,12 @@ export function ipv6CidrRange(cidr, includeNetworkInfo) {
* @param {boolean} allowLargeList
* @returns {string}
*/
export function ipv4HyphenatedRange(range, includeNetworkInfo, enumerateAddresses, allowLargeList) {
export function ipv4HyphenatedRange(
range,
includeNetworkInfo,
enumerateAddresses,
allowLargeList,
) {
const ip1 = strToIpv4(range[0].split("-")[0].trim()),
ip2 = strToIpv4(range[0].split("-")[1].trim());
@ -137,16 +150,16 @@ export function ipv4HyphenatedRange(range, includeNetworkInfo, enumerateAddresse
\tCIDR: ${cidr}
\tMask: ${ipv4ToStr(mask)}
\tSubnet range: ${ipv4ToStr(subIp1)} - ${ipv4ToStr(subIp2)}
\tTotal addresses in subnet: ${(((subIp2 - subIp1) >>> 0) + 1)}
\tTotal addresses in subnet: ${((subIp2 - subIp1) >>> 0) + 1}
Range: ${ipv4ToStr(ip1)} - ${ipv4ToStr(ip2)}
Total addresses in range: ${(((ip2 - ip1) >>> 0) + 1)}
Total addresses in range: ${((ip2 - ip1) >>> 0) + 1}
`;
}
if (enumerateAddresses) {
if (((ip2 - ip1) >>> 0) <= 65536 || allowLargeList) {
if ((ip2 - ip1) >>> 0 <= 65536 || allowLargeList) {
output += generateIpv4Range(ip1, ip2).join("\n");
} else {
output += _LARGE_RANGE_ERROR;
@ -182,8 +195,16 @@ export function ipv6HyphenatedRange(range, includeNetworkInfo) {
if (includeNetworkInfo) {
output += "Range: " + ipv6ToStr(ip1) + " - " + ipv6ToStr(ip2) + "\n";
output += "Shorthand range: " + ipv6ToStr(ip1, true) + " - " + ipv6ToStr(ip2, true) + "\n";
output += "Total addresses in range: " + (parseInt(total.join(""), 2) + 1) + "\n\n";
output +=
"Shorthand range: " +
ipv6ToStr(ip1, true) +
" - " +
ipv6ToStr(ip2, true) +
"\n";
output +=
"Total addresses in range: " +
(parseInt(total.join(""), 2) + 1) +
"\n\n";
}
return output;
@ -199,8 +220,12 @@ export function ipv6HyphenatedRange(range, includeNetworkInfo) {
* @param {boolean} allowLargeList
* @returns {string}
*/
export function ipv4ListedRange(match, includeNetworkInfo, enumerateAddresses, allowLargeList) {
export function ipv4ListedRange(
match,
includeNetworkInfo,
enumerateAddresses,
allowLargeList,
) {
let ipv4List = match[0].split("\n");
ipv4List = ipv4List.filter(Boolean);
@ -213,7 +238,7 @@ export function ipv4ListedRange(match, includeNetworkInfo, enumerateAddresses, a
if (cidrRange < 0 || cidrRange > 31) {
throw new OperationError("IPv4 CIDR must be less than 32");
}
const mask = ~(0xFFFFFFFF >>> cidrRange),
const mask = ~(0xffffffff >>> cidrRange),
cidrIp1 = network & mask,
cidrIp2 = cidrIp1 | ~mask;
ipv4List.splice(ipv4List.indexOf(ipv4CidrList[i]), 1);
@ -224,7 +249,12 @@ export function ipv4ListedRange(match, includeNetworkInfo, enumerateAddresses, a
const ip1 = ipv4List[0];
const ip2 = ipv4List[ipv4List.length - 1];
const range = [ip1 + " - " + ip2];
return ipv4HyphenatedRange(range, includeNetworkInfo, enumerateAddresses, allowLargeList);
return ipv4HyphenatedRange(
range,
includeNetworkInfo,
enumerateAddresses,
allowLargeList,
);
}
/**
@ -236,7 +266,6 @@ export function ipv4ListedRange(match, includeNetworkInfo, enumerateAddresses, a
* @returns {string}
*/
export function ipv6ListedRange(match, includeNetworkInfo) {
let ipv6List = match[0].split("\n");
ipv6List = ipv6List.filter(function (str) {
return str.trim();
@ -249,7 +278,6 @@ export function ipv6ListedRange(match, includeNetworkInfo) {
});
for (let i = 0; i < ipv6CidrList.length; i++) {
const network = strToIpv6(ipv6CidrList[i].split("/")[0]);
const cidrRange = parseInt(ipv6CidrList[i].split("/")[1], 10);
@ -264,7 +292,7 @@ export function ipv6ListedRange(match, includeNetworkInfo) {
for (let j = 0; j < 8; j++) {
cidrIp1[j] = network[j] & mask[j];
cidrIp2[j] = cidrIp1[j] | (~mask[j] & 0x0000FFFF);
cidrIp2[j] = cidrIp1[j] | (~mask[j] & 0x0000ffff);
}
ipv6List.splice(ipv6List.indexOf(ipv6CidrList[i]), 1);
ipv6List.push(ipv6ToStr(cidrIp1), ipv6ToStr(cidrIp2));
@ -334,7 +362,6 @@ export function ipv4ToStr(ipInt) {
return blockA + "." + blockB + "." + blockC + "." + blockD;
}
/**
* Converts an IPv6 address from string format to numerical array format.
*
@ -354,7 +381,7 @@ export function strToIpv6(ipStr) {
for (let i = 0; i < 8; i++) {
if (isNaN(numBlocks[j])) {
ipv6[i] = 0;
if (i === (8-numBlocks.slice(j).length)) j++;
if (i === 8 - numBlocks.slice(j).length) j++;
} else {
ipv6[i] = numBlocks[j];
j++;
@ -403,12 +430,13 @@ export function ipv6ToStr(ipv6, compact) {
e = -1;
for (i = 0; i < 8; i++) {
if (ipv6[i] === 0 && e === (i-1)) {
if (ipv6[i] === 0 && e === i - 1) {
e = i;
} else if (ipv6[i] === 0) {
s = i; e = i;
s = i;
e = i;
}
if (e >= 0 && (e-s) > (end - start)) {
if (e >= 0 && e - s > end - start) {
start = s;
end = e;
}
@ -423,8 +451,7 @@ export function ipv6ToStr(ipv6, compact) {
if (end === 7) output += ":";
}
}
if (output[0] === ":")
output = ":" + output;
if (output[0] === ":") output = ":" + output;
} else {
for (i = 0; i < 8; i++) {
output += Utils.hex(ipv6[i], 4) + ":";
@ -467,12 +494,12 @@ export function genIpv6Mask(cidr) {
let shift;
for (let i = 0; i < 8; i++) {
if (cidr > ((i+1)*16)) {
mask[i] = 0x0000FFFF;
if (cidr > (i + 1) * 16) {
mask[i] = 0x0000ffff;
} else {
shift = cidr-(i*16);
shift = cidr - i * 16;
if (shift < 0) shift = 0;
mask[i] = ~((0x0000FFFF >>> shift) | 0xFFFF0000);
mask[i] = ~((0x0000ffff >>> shift) | 0xffff0000);
}
}
@ -498,7 +525,6 @@ export function ipv4Compare(a, b) {
* @returns {number}
*/
export function ipv6Compare(a, b) {
const a_ = strToIpv6(a),
b_ = strToIpv6(b);
@ -510,7 +536,8 @@ export function ipv6Compare(a, b) {
return 0;
}
const _LARGE_RANGE_ERROR = "The specified range contains more than 65,536 addresses. Running this query could crash your browser. If you want to run it, select the \"Allow large queries\" option. You are advised to turn off \"Auto Bake\" whilst editing large ranges.";
const _LARGE_RANGE_ERROR =
'The specified range contains more than 65,536 addresses. Running this query could crash your browser. If you want to run it, select the "Allow large queries" option. You are advised to turn off "Auto Bake" whilst editing large ranges.';
/**
* A regular expression that matches an IPv4 address
@ -520,7 +547,8 @@ export const IPV4_REGEX = /^\s*((?:\d{1,3}\.){3}\d{1,3})\s*$/;
/**
* A regular expression that matches an IPv6 address
*/
export const IPV6_REGEX = /^\s*(((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\4)::|:\b|(?![\dA-F])))|(?!\3\4)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4}))\s*$/i;
export const IPV6_REGEX =
/^\s*(((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\4)::|:\b|(?![\dA-F])))|(?!\3\4)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4}))\s*$/i;
/**
* Lookup table for Internet Protocols.
@ -536,7 +564,10 @@ export const protocolLookup = {
6: { keyword: "TCP", protocol: "Transmission Control" },
7: { keyword: "CBT", protocol: "CBT" },
8: { keyword: "EGP", protocol: "Exterior Gateway Protocol" },
9: {keyword: "IGP", protocol: "any private interior gateway (used by Cisco for their IGRP)"},
9: {
keyword: "IGP",
protocol: "any private interior gateway (used by Cisco for their IGRP)",
},
10: { keyword: "BBN-RCC-MON", protocol: "BBN RCC Monitoring" },
11: { keyword: "NVP-II", protocol: "Network Voice Protocol" },
12: { keyword: "PUP", protocol: "PUP" },
@ -565,7 +596,10 @@ export const protocolLookup = {
35: { keyword: "IDPR", protocol: "Inter-Domain Policy Routing Protocol" },
36: { keyword: "XTP", protocol: "XTP" },
37: { keyword: "DDP", protocol: "Datagram Delivery Protocol" },
38: {keyword: "IDPR-CMTP", protocol: "IDPR Control Message Transport Proto"},
38: {
keyword: "IDPR-CMTP",
protocol: "IDPR Control Message Transport Proto",
},
39: { keyword: "TP++", protocol: "TP++ Transport Protocol" },
40: { keyword: "IL", protocol: "IL Transport Protocol" },
41: { keyword: "IPv6", protocol: "IPv6 encapsulation" },
@ -583,7 +617,11 @@ export const protocolLookup = {
53: { keyword: "SWIPE (deprecated)", protocol: "IP with Encryption" },
54: { keyword: "NARP", protocol: "NBMA Address Resolution Protocol" },
55: { keyword: "MOBILE", protocol: "IP Mobility" },
56: {keyword: "TLSP", protocol: "Transport Layer Security Protocol using Kryptonet key management"},
56: {
keyword: "TLSP",
protocol:
"Transport Layer Security Protocol using Kryptonet key management",
},
57: { keyword: "SKIP", protocol: "SKIP" },
58: { keyword: "IPv6-ICMP", protocol: "ICMP for IPv6" },
59: { keyword: "IPv6-NoNxt", protocol: "No Next Header for IPv6" },
@ -622,7 +660,10 @@ export const protocolLookup = {
92: { keyword: "MTP", protocol: "Multicast Transport Protocol" },
93: { keyword: "AX.25", protocol: "AX.25 Frames" },
94: { keyword: "IPIP", protocol: "IP-within-IP Encapsulation Protocol" },
95: {keyword: "MICP (deprecated)", protocol: "Mobile Internetworking Control Pro."},
95: {
keyword: "MICP (deprecated)",
protocol: "Mobile Internetworking Control Pro.",
},
96: { keyword: "SCC-SP", protocol: "Semaphore Communications Sec. Pro." },
97: { keyword: "ETHERIP", protocol: "Ethernet-within-IP Encapsulation" },
98: { keyword: "ENCAP", protocol: "Encapsulation Header" },
@ -668,9 +709,12 @@ export const protocolLookup = {
138: { keyword: "manet", protocol: "MANET Protocols" },
139: { keyword: "HIP", protocol: "Host Identity Protocol" },
140: { keyword: "Shim6", protocol: "Shim6 Protocol" },
141: {keyword: "WESP", protocol: "Wrapped Encapsulating Security Payload"},
141: {
keyword: "WESP",
protocol: "Wrapped Encapsulating Security Payload",
},
142: { keyword: "ROHC", protocol: "Robust Header Compression" },
253: { keyword: "", protocol: "Use for experimentation and testing" },
254: { keyword: "", protocol: "Use for experimentation and testing" },
255: {keyword: "Reserved", protocol: ""}
255: { keyword: "Reserved", protocol: "" },
};

View file

@ -37,7 +37,7 @@ export function gaussianBlur (input, radius) {
* @returns {Array}
*/
function boxesForGauss(radius, numBoxes) {
const idealWidth = Math.sqrt((12 * radius * radius / numBoxes) + 1);
const idealWidth = Math.sqrt((12 * radius * radius) / numBoxes + 1);
let wl = Math.floor(idealWidth);
@ -47,7 +47,12 @@ function boxesForGauss(radius, numBoxes) {
const wu = wl + 2;
const mIdeal = (12 * radius * radius - numBoxes * wl * wl - 4 * numBoxes * wl - 3 * numBoxes) / (-4 * wl - 4);
const mIdeal =
(12 * radius * radius -
numBoxes * wl * wl -
4 * numBoxes * wl -
3 * numBoxes) /
(-4 * wl - 4);
const m = Math.round(mIdeal);
const sizes = [];
@ -133,9 +138,12 @@ function boxBlurH (source, output, width, height, radius) {
const riIdx = source.getPixelIndex(ri++, i);
const liIdx = source.getPixelIndex(li++, i);
red += source.bitmap.data[riIdx] - source.bitmap.data[liIdx];
green += source.bitmap.data[riIdx + 1] - source.bitmap.data[liIdx + 1];
blue += source.bitmap.data[riIdx + 2] - source.bitmap.data[liIdx + 2];
alpha += source.bitmap.data[riIdx + 3] - source.bitmap.data[liIdx + 3];
green +=
source.bitmap.data[riIdx + 1] - source.bitmap.data[liIdx + 1];
blue +=
source.bitmap.data[riIdx + 2] - source.bitmap.data[liIdx + 2];
alpha +=
source.bitmap.data[riIdx + 3] - source.bitmap.data[liIdx + 3];
const tiIdx = source.getPixelIndex(ti++, i);
output.bitmap.data[tiIdx] = Math.round(red * iarr);
@ -222,9 +230,12 @@ function boxBlurV (source, output, width, height, radius) {
const riIdx = source.getPixelIndex(i, ri++);
const liIdx = source.getPixelIndex(i, li++);
red += source.bitmap.data[riIdx] - source.bitmap.data[liIdx];
green += source.bitmap.data[riIdx + 1] - source.bitmap.data[liIdx + 1];
blue += source.bitmap.data[riIdx + 2] - source.bitmap.data[liIdx + 2];
alpha += source.bitmap.data[riIdx + 3] - source.bitmap.data[liIdx + 3];
green +=
source.bitmap.data[riIdx + 1] - source.bitmap.data[liIdx + 1];
blue +=
source.bitmap.data[riIdx + 2] - source.bitmap.data[liIdx + 2];
alpha +=
source.bitmap.data[riIdx + 3] - source.bitmap.data[liIdx + 3];
const tiIdx = source.getPixelIndex(i, ti++);
output.bitmap.data[tiIdx] = Math.round(red * iarr);

View file

@ -6,7 +6,6 @@
* @license Apache-2.0
*/
/**
* List of the JWT algorithms that can be used
*/
@ -20,5 +19,5 @@ export const JWT_ALGORITHMS = [
"ES256",
"ES384",
"ES512",
"None"
"None",
];

View file

@ -27,8 +27,7 @@ export function initTiles() {
*/
function rotateDown(key, col, n) {
const lines = [];
for (let i = 0; i < 7; i++)
lines.push(key.slice(i*7, (i + 1) * 7));
for (let i = 0; i < 7; i++) lines.push(key.slice(i * 7, (i + 1) * 7));
const lefts = [];
let mids = [];
const rights = [];
@ -37,11 +36,10 @@ function rotateDown(key, col, n) {
mids.push(element.charAt(col));
rights.push(element.slice(col + 1));
});
n = (7 - n % 7) % 7;
n = (7 - (n % 7)) % 7;
mids = mids.slice(n).concat(mids.slice(0, n));
let result = "";
for (let i = 0; i < 7; i++)
result += lefts[i] + mids[i] + rights[i];
for (let i = 0; i < 7; i++) result += lefts[i] + mids[i] + rights[i];
return result;
}
@ -55,8 +53,13 @@ function rotateDown(key, col, n) {
*/
function rotateRight(key, row, n) {
const mid = key.slice(row * 7, (row + 1) * 7);
n = (7 - n % 7) % 7;
return key.slice(0, 7 * row) + mid.slice(n) + mid.slice(0, n) + key.slice(7 * (row + 1));
n = (7 - (n % 7)) % 7;
return (
key.slice(0, 7 * row) +
mid.slice(n) +
mid.slice(0, n) +
key.slice(7 * (row + 1))
);
}
/**
@ -67,8 +70,7 @@ function rotateRight(key, row, n) {
*/
function findIx(letter) {
for (let i = 0; i < tiles.length; i++)
if (tiles[i][0] === letter)
return tiles[i][1];
if (tiles[i][0] === letter) return tiles[i][1];
throw new OperationError("Letter " + letter + " is not included in LS47");
}
@ -98,8 +100,7 @@ function checkKey(key) {
if (key.length !== letters.length)
throw new OperationError("Wrong key size");
const counts = new Array();
for (let i = 0; i < letters.length; i++)
counts[letters.charAt(i)] = 0;
for (let i = 0; i < letters.length; i++) counts[letters.charAt(i)] = 0;
for (const elem of letters) {
if (letters.indexOf(elem) === -1)
throw new OperationError("Letter " + elem + " not in LS47");
@ -118,8 +119,7 @@ function checkKey(key) {
*/
function findPos(key, letter) {
const index = key.indexOf(letter);
if (index >= 0 && index < 49)
return [Math.floor(index/7), index%7];
if (index >= 0 && index < 49) return [Math.floor(index / 7), index % 7];
throw new OperationError("Letter " + letter + " is not in the key");
}
@ -131,7 +131,7 @@ function findPos (key, letter) {
* @returns {string}
*/
function findAtPos(key, coord) {
return key.charAt(coord[1] + (coord[0] * 7));
return key.charAt(coord[1] + coord[0] * 7);
}
/**
@ -157,7 +157,7 @@ function addPos(a, b) {
function subPos(a, b) {
const asub = a[0] - b[0];
const bsub = a[1] - b[1];
return [asub - (Math.floor(asub/7) * 7), bsub - (Math.floor(bsub/7) * 7)];
return [asub - Math.floor(asub / 7) * 7, bsub - Math.floor(bsub / 7) * 7];
}
/**

View file

@ -39,7 +39,10 @@ export function decompress(compressed) {
while (coffset + 2 <= compressed.length) {
const doffset = decompressed.length;
const blockHeader = Utils.byteArrayToInt(compressed.slice(coffset, coffset + 2), "little");
const blockHeader = Utils.byteArrayToInt(
compressed.slice(coffset, coffset + 2),
"little",
);
coffset += 2;
const size = blockHeader & SIZE_MASK;
@ -48,7 +51,9 @@ export function decompress(compressed) {
if (size === 0) {
break;
} else if (compressed.length < coffset + size) {
throw new OperationError("Malformed LZNT1 stream: Block too small! Has the stream been truncated?");
throw new OperationError(
"Malformed LZNT1 stream: Block too small! Has the stream been truncated?",
);
}
if ((blockHeader & COMPRESSED_MASK) !== 0) {
@ -59,18 +64,31 @@ export function decompress(compressed) {
if ((header & 1) === 0) {
decompressed.push(compressed[coffset++]);
} else {
const pointer = Utils.byteArrayToInt(compressed.slice(coffset, coffset + 2), "little");
const pointer = Utils.byteArrayToInt(
compressed.slice(coffset, coffset + 2),
"little",
);
coffset += 2;
const displacement = getDisplacement(decompressed.length - doffset - 1);
const symbolOffset = (pointer >> (12 - displacement)) + 1;
const symbolLength = (pointer & (0xFFF >> displacement)) + 2;
const displacement = getDisplacement(
decompressed.length - doffset - 1,
);
const symbolOffset =
(pointer >> (12 - displacement)) + 1;
const symbolLength =
(pointer & (0xfff >> displacement)) + 2;
const shiftOffset = decompressed.length - symbolOffset;
for (let shiftDelta = 0; shiftDelta < symbolLength + 1; shiftDelta++) {
for (
let shiftDelta = 0;
shiftDelta < symbolLength + 1;
shiftDelta++
) {
const shift = shiftOffset + shiftDelta;
if (shift < 0 || decompressed.length <= shift) {
throw new OperationError("Malformed LZNT1 stream: Invalid shift!");
throw new OperationError(
"Malformed LZNT1 stream: Invalid shift!",
);
}
decompressed.push(decompressed[shift]);
}

View file

@ -10,12 +10,12 @@ import LZString from "lz-string";
export const COMPRESSION_OUTPUT_FORMATS = ["default", "UTF16", "Base64"];
export const COMPRESSION_FUNCTIONS = {
"default": LZString.compress,
"UTF16": LZString.compressToUTF16,
"Base64": LZString.compressToBase64,
default: LZString.compress,
UTF16: LZString.compressToUTF16,
Base64: LZString.compressToBase64,
};
export const DECOMPRESSION_FUNCTIONS = {
"default": LZString.decompress,
"UTF16": LZString.decompressFromUTF16,
"Base64": LZString.decompressFromBase64,
default: LZString.decompress,
UTF16: LZString.decompressFromUTF16,
Base64: LZString.decompressFromBase64,
};

View file

@ -15,21 +15,29 @@
export function GenerateParagraphs(length = 3) {
const paragraphs = [];
while (paragraphs.length < length) {
const paragraphLength = getRandomLength(PARAGRAPH_LENGTH_MEAN, PARAGRAPH_LENGTH_STD_DEV);
const paragraphLength = getRandomLength(
PARAGRAPH_LENGTH_MEAN,
PARAGRAPH_LENGTH_STD_DEV,
);
const sentences = [];
while (sentences.length < paragraphLength) {
const sentenceLength = getRandomLength(SENTENCE_LENGTH_MEAN, SENTENCE_LENGTH_STD_DEV);
const sentenceLength = getRandomLength(
SENTENCE_LENGTH_MEAN,
SENTENCE_LENGTH_STD_DEV,
);
const sentence = getWords(sentenceLength);
sentences.push(formatSentence(sentence));
}
paragraphs.push(formatParagraph(sentences));
}
paragraphs[paragraphs.length-1] = paragraphs[paragraphs.length-1].slice(0, -2);
paragraphs[paragraphs.length - 1] = paragraphs[paragraphs.length - 1].slice(
0,
-2,
);
paragraphs[0] = replaceStart(paragraphs[0]);
return paragraphs.join("");
}
/**
* Generate lorem ipsum sentences.
*
@ -39,7 +47,10 @@ export function GenerateParagraphs(length=3) {
export function GenerateSentences(length = 3) {
const sentences = [];
while (sentences.length < length) {
const sentenceLength = getRandomLength(SENTENCE_LENGTH_MEAN, SENTENCE_LENGTH_STD_DEV);
const sentenceLength = getRandomLength(
SENTENCE_LENGTH_MEAN,
SENTENCE_LENGTH_STD_DEV,
);
const sentence = getWords(sentenceLength);
sentences.push(formatSentence(sentence));
}
@ -47,7 +58,6 @@ export function GenerateSentences(length=3) {
return paragraphs.join("");
}
/**
* Generate lorem ipsum words.
*
@ -61,7 +71,6 @@ export function GenerateWords(length=3) {
return paragraphs.join("");
}
/**
* Generate lorem ipsum bytes.
*
@ -73,7 +82,6 @@ export function GenerateBytes(length=3) {
return str.slice(0, length);
}
/**
* Get array of randomly selected words from the lorem ipsum wordList.
*
@ -95,7 +103,6 @@ function getWords(length=3) {
return words;
}
/**
* Convert an array of words into an array of sentences
*
@ -106,7 +113,10 @@ function getWords(length=3) {
function wordsToSentences(words) {
const sentences = [];
while (words.length > 0) {
const sentenceLength = getRandomLength(SENTENCE_LENGTH_MEAN, SENTENCE_LENGTH_STD_DEV);
const sentenceLength = getRandomLength(
SENTENCE_LENGTH_MEAN,
SENTENCE_LENGTH_STD_DEV,
);
if (sentenceLength <= words.length) {
sentences.push(formatSentence(words.splice(0, sentenceLength)));
} else {
@ -116,7 +126,6 @@ function wordsToSentences(words) {
return sentences;
}
/**
* Convert an array of sentences into an array of paragraphs
*
@ -127,15 +136,20 @@ function wordsToSentences(words) {
function sentencesToParagraphs(sentences) {
const paragraphs = [];
while (sentences.length > 0) {
const paragraphLength = getRandomLength(PARAGRAPH_LENGTH_MEAN, PARAGRAPH_LENGTH_STD_DEV);
const paragraphLength = getRandomLength(
PARAGRAPH_LENGTH_MEAN,
PARAGRAPH_LENGTH_STD_DEV,
);
paragraphs.push(formatParagraph(sentences.splice(0, paragraphLength)));
}
paragraphs[paragraphs.length-1] = paragraphs[paragraphs.length-1].slice(0, -1);
paragraphs[paragraphs.length - 1] = paragraphs[paragraphs.length - 1].slice(
0,
-1,
);
paragraphs[0] = replaceStart(paragraphs[0]);
return paragraphs;
}
/**
* Format an array of words into a sentence.
*
@ -155,7 +169,6 @@ function formatSentence(words) {
return sentence;
}
/**
* Format an array of sentences into a paragraph.
*
@ -169,7 +182,6 @@ function formatParagraph(sentences) {
return paragraph;
}
/**
* Get a random number based on a mean and standard deviation.
*
@ -181,12 +193,17 @@ function formatParagraph(sentences) {
function getRandomLength(mean, stdDev) {
let length;
do {
length = Math.round((Math.random()*2-1)+(Math.random()*2-1)+(Math.random()*2-1)*stdDev+mean);
length = Math.round(
Math.random() * 2 -
1 +
(Math.random() * 2 - 1) +
(Math.random() * 2 - 1) * stdDev +
mean,
);
} while (length <= 0);
return length;
}
/**
* Replace first 5 words with "Lorem ipsum dolor sit amet"
*
@ -208,7 +225,6 @@ function replaceStart(str) {
}
}
const SENTENCE_LENGTH_MEAN = 15;
const SENTENCE_LENGTH_STD_DEV = 9;
const PARAGRAPH_LENGTH_MEAN = 5;
@ -216,15 +232,66 @@ const PARAGRAPH_LENGTH_STD_DEV = 2;
const PROBABILITY_OF_A_COMMA = 0.35;
const wordList = [
"ad", "adipisicing", "aliqua", "aliquip", "amet", "anim",
"aute", "cillum", "commodo", "consectetur", "consequat", "culpa",
"cupidatat", "deserunt", "do", "dolor", "dolore", "duis",
"ea", "eiusmod", "elit", "enim", "esse", "est",
"et", "eu", "ex", "excepteur", "exercitation", "fugiat",
"id", "in", "incididunt", "ipsum", "irure", "labore",
"laboris", "laborum", "Lorem", "magna", "minim", "mollit",
"nisi", "non", "nostrud", "nulla", "occaecat", "officia",
"pariatur", "proident", "qui", "quis", "reprehenderit", "sint",
"sit", "sunt", "tempor", "ullamco", "ut", "velit",
"veniam", "voluptate",
"ad",
"adipisicing",
"aliqua",
"aliquip",
"amet",
"anim",
"aute",
"cillum",
"commodo",
"consectetur",
"consequat",
"culpa",
"cupidatat",
"deserunt",
"do",
"dolor",
"dolore",
"duis",
"ea",
"eiusmod",
"elit",
"enim",
"esse",
"est",
"et",
"eu",
"ex",
"excepteur",
"exercitation",
"fugiat",
"id",
"in",
"incididunt",
"ipsum",
"irure",
"labore",
"laboris",
"laborum",
"Lorem",
"magna",
"minim",
"mollit",
"nisi",
"non",
"nostrud",
"nulla",
"occaecat",
"officia",
"pariatur",
"proident",
"qui",
"quis",
"reprehenderit",
"sint",
"sit",
"sunt",
"tempor",
"ullamco",
"ut",
"velit",
"veniam",
"voluptate",
];

View file

@ -9,48 +9,48 @@
export const SWITCHES = [
{ name: "Up (.)", value: "." },
{ name: "Centre", value: "" },
{name: "Down (x)", value: "x"}
{ name: "Down (x)", value: "x" },
];
export const VALID_ITA2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ34589+-./";
export const ITA2_TABLE = {
"A": "11000",
"B": "10011",
"C": "01110",
"D": "10010",
"E": "10000",
"F": "10110",
"G": "01011",
"H": "00101",
"I": "01100",
"J": "11010",
"K": "11110",
"L": "01001",
"M": "00111",
"N": "00110",
"O": "00011",
"P": "01101",
"Q": "11101",
"R": "01010",
"S": "10100",
"T": "00001",
"U": "11100",
"V": "01111",
"W": "11001",
"X": "10111",
"Y": "10101",
"Z": "10001",
"3": "00010",
"4": "01000",
"9": "00100",
A: "11000",
B: "10011",
C: "01110",
D: "10010",
E: "10000",
F: "10110",
G: "01011",
H: "00101",
I: "01100",
J: "11010",
K: "11110",
L: "01001",
M: "00111",
N: "00110",
O: "00011",
P: "01101",
Q: "11101",
R: "01010",
S: "10100",
T: "00001",
U: "11100",
V: "01111",
W: "11001",
X: "10111",
Y: "10101",
Z: "10001",
3: "00010",
4: "01000",
9: "00100",
"/": "00000",
" ": "00100",
".": "00100",
"8": "11111",
"5": "11011",
8: "11111",
5: "11011",
"-": "11111",
"+": "11011"
"+": "11011",
};
export const ROTOR_SIZES = {
@ -65,7 +65,7 @@ export const ROTOR_SIZES = {
X2: 31,
X3: 29,
X4: 26,
X5: 23
X5: 23,
};
/**
@ -73,84 +73,251 @@ export const ROTOR_SIZES = {
*/
export const INIT_PATTERNS = {
"No Pattern": {
"X": {
1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
2: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
3: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
4: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
5: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
X: {
1: [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
],
2: [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
],
3: [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
],
4: [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
],
5: [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0,
],
},
"S": {
1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
2: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
3: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
4: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
5: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
S: {
1: [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0,
],
2: [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0,
],
3: [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0,
],
4: [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
],
5: [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
],
},
M: {
1: [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
],
2: [
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
],
},
"M": {
1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
2: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
}
},
"KH Pattern": {
"X": {
1: [0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0],
2: [1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0],
3: [0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0],
4: [1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0],
5: [1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0]
X: {
1: [
0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1,
0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0,
],
2: [
1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0,
1, 0, 0, 1, 1, 0, 1, 1, 0, 0,
],
3: [
0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1,
0, 0, 1, 1, 0, 1, 1, 0,
],
4: [
1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0,
0, 0, 1, 0, 0,
],
5: [
1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1,
0, 0,
],
},
"S": {
1: [0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1],
2: [0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1],
3: [0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1],
4: [0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0],
5: [1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0]
S: {
1: [
0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0,
1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0,
1,
],
2: [
0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1,
1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1,
0, 1, 0, 0, 1,
],
3: [
0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1,
0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0,
1, 1, 0, 0, 1, 0, 1, 0, 1,
],
4: [
0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0,
1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
],
5: [
1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1,
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1,
1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0,
],
},
M: {
1: [
0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1,
1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1,
1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0,
],
2: [
1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0,
0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0,
],
},
"M": {
1: [0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0],
2: [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0]
}
},
"ZMUG Pattern": {
"X": {
1: [0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0],
2: [1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0],
3: [0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0],
4: [1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1],
5: [0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1]
X: {
1: [
0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0,
1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0,
],
2: [
1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0,
0, 1, 1, 0, 0, 1, 1, 0, 0, 0,
],
3: [
0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0,
1, 1, 0, 1, 1, 1, 1, 0,
],
4: [
1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1,
0, 0, 1, 0, 1,
],
5: [
0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1,
0, 1,
],
},
"S": {
1: [1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0],
2: [0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1],
3: [0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1],
4: [0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1],
5: [1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0]
S: {
1: [
1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0,
1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0,
0,
],
2: [
0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0,
0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0,
0, 1, 0, 1, 1,
],
3: [
0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0,
0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0,
0, 0, 1, 1, 0, 0, 1, 1, 1,
],
4: [
0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0,
0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0,
0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1,
],
5: [
1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1,
1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0,
0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0,
],
},
M: {
1: [
1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1,
1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1,
0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1,
],
2: [
0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0,
1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1,
],
},
"M": {
1: [1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1],
2: [0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1]
}
},
"BREAM Pattern": {
"X": {
1: [0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
2: [0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1],
3: [1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0],
4: [1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0],
5: [0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0]
X: {
1: [
0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1,
1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0,
],
2: [
0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0,
1, 1, 0, 1, 1, 1, 0, 0, 1, 1,
],
3: [
1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0,
1, 1, 0, 1, 1, 1, 0, 0,
],
4: [
1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0,
0, 1, 1, 0, 0,
],
5: [
0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0,
1, 0,
],
},
S: {
1: [
0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1,
1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
0,
],
2: [
1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0,
0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1,
1, 0, 1, 0, 0,
],
3: [
1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0,
0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0,
1, 0, 1, 0, 1, 0, 1, 0, 1,
],
4: [
0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0,
1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0,
1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1,
],
5: [
1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0,
0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0,
1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0,
],
},
M: {
1: [
1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1,
0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1,
0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1,
],
2: [
0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0,
1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1,
],
},
"S": {
1: [0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0],
2: [1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0],
3: [1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
4: [0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1],
5: [1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0]
},
"M": {
1: [1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1],
2: [0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1]
}
}
};

File diff suppressed because it is too large Load diff

View file

@ -14,13 +14,15 @@ import OperationError from "../errors/OperationError.mjs";
import { isWorkerEnvironment } from "../Utils.mjs";
import kbpgp from "kbpgp";
import * as es6promisify from "es6-promisify";
const promisify = es6promisify.default ? es6promisify.default.promisify : es6promisify.promisify;
const promisify = es6promisify.default
? es6promisify.default.promisify
: es6promisify.promisify;
/**
* Progress callback
*/
export const ASP = kbpgp.ASP({
"progress_hook": info => {
progress_hook: (info) => {
let msg = "";
switch (info.what) {
@ -46,9 +48,8 @@ export const ASP = kbpgp.ASP({
msg = `Stage: ${info.what}`;
}
if (isWorkerEnvironment())
self.sendStatusMessage(msg);
}
if (isWorkerEnvironment()) self.sendStatusMessage(msg);
},
});
/**
@ -79,16 +80,18 @@ export async function importPrivateKey(privateKey, passphrase) {
const key = await promisify(kbpgp.KeyManager.import_from_armored_pgp)({
armored: privateKey,
opts: {
"no_check_keys": true
}
no_check_keys: true,
},
});
if (key.is_pgp_locked()) {
if (passphrase) {
await promisify(key.unlock_pgp.bind(key))({
passphrase
passphrase,
});
} else {
throw new OperationError("Did not provide passphrase with locked private key.");
throw new OperationError(
"Did not provide passphrase with locked private key.",
);
}
}
return key;
@ -108,8 +111,8 @@ export async function importPublicKey (publicKey) {
const key = await promisify(kbpgp.KeyManager.import_from_armored_pgp)({
armored: publicKey,
opts: {
"no_check_keys": true
}
no_check_keys: true,
},
});
return key;
} catch (err) {

View file

@ -13,7 +13,6 @@ import protobuf from "protobufjs";
* @license Apache-2.0
*/
class Protobuf {
/**
* Protobuf constructor
*
@ -125,7 +124,8 @@ class Protobuf {
try {
this.parsedProto = protobuf.parse(protoText);
if (this.parsedProto.package) {
this.parsedProto.root = this.parsedProto.root.nested[this.parsedProto.package];
this.parsedProto.root =
this.parsedProto.root.nested[this.parsedProto.package];
}
this.updateMainMessageName();
} catch (error) {
@ -140,12 +140,14 @@ class Protobuf {
static updateMainMessageName() {
const messageNames = [];
const fieldTypes = [];
this.parsedProto.root.nestedArray.forEach(block => {
this.parsedProto.root.nestedArray.forEach((block) => {
if (block instanceof protobuf.Type) {
messageNames.push(block.name);
this.parsedProto.root.nested[block.name].fieldsArray.forEach(field => {
this.parsedProto.root.nested[block.name].fieldsArray.forEach(
(field) => {
fieldTypes.push(field.type);
});
},
);
}
});
@ -175,7 +177,9 @@ class Protobuf {
if (this.showTypes) {
rawDecode = this.showRawTypes(rawDecode, pb.fieldTypes);
this.parsedProto.root = this.appendTypesToFieldNames(this.parsedProto.root);
this.parsedProto.root = this.appendTypesToFieldNames(
this.parsedProto.root,
);
}
try {
@ -184,18 +188,20 @@ class Protobuf {
bytes: String,
longs: Number,
enums: String,
defaults: true
defaults: true,
});
const output = {};
if (this.showUnknownFields) {
output[message.name] = packageDecode;
output["Unknown Fields"] = this.compareFields(rawDecode, message);
output["Unknown Fields"] = this.compareFields(
rawDecode,
message,
);
return output;
} else {
return packageDecode;
}
} catch (error) {
if (message) {
throw new Error("Input " + error);
@ -214,9 +220,20 @@ class Protobuf {
static appendTypesToFieldNames(schemaRoot) {
for (const block of schemaRoot.nestedArray) {
if (block instanceof protobuf.Type) {
for (const [fieldName, fieldData] of Object.entries(block.fields)) {
schemaRoot.nested[block.name].remove(block.fields[fieldName]);
schemaRoot.nested[block.name].add(new protobuf.Field(`${fieldName} (${fieldData.type})`, fieldData.id, fieldData.type, fieldData.rule));
for (const [fieldName, fieldData] of Object.entries(
block.fields,
)) {
schemaRoot.nested[block.name].remove(
block.fields[fieldName],
);
schemaRoot.nested[block.name].add(
new protobuf.Field(
`${fieldName} (${fieldData.type})`,
fieldData.id,
fieldData.type,
fieldData.rule,
),
);
}
}
}
@ -244,8 +261,10 @@ class Protobuf {
if (Array.isArray(value)) {
const fieldInstances = [];
for (const instance of Object.keys(value)) {
if (typeof(value[instance]) !== "string") {
fieldInstances.push(this.showRawTypes(value[instance], fieldType));
if (typeof value[instance] !== "string") {
fieldInstances.push(
this.showRawTypes(value[instance], fieldType),
);
} else {
fieldInstances.push(value[instance]);
}
@ -264,7 +283,9 @@ class Protobuf {
}
// Substitute fieldNum with field number and type
rawDecode[`field #${fieldNum}: ${this.getTypeInfo(outputFieldType)}`] = outputFieldValue;
rawDecode[
`field #${fieldNum}: ${this.getTypeInfo(outputFieldType)}`
] = outputFieldValue;
delete rawDecode[fieldNum];
}
return rawDecode;
@ -281,7 +302,10 @@ class Protobuf {
// Define message data using raw decode output and schema
const schemaFieldProperties = {};
const schemaFieldNames = Object.keys(schemaMessage.fields);
schemaFieldNames.forEach(field => schemaFieldProperties[schemaMessage.fields[field].id] = field);
schemaFieldNames.forEach(
(field) =>
(schemaFieldProperties[schemaMessage.fields[field].id] = field),
);
// Loop over each field present in the raw decode output
for (const fieldName in rawDecodedMessage) {
@ -302,21 +326,26 @@ class Protobuf {
// Check for repeated fields
if (Array.isArray(rawFieldData) && !schemaField.repeated) {
rawDecodedMessage[`(${schemaMessage.name}) ${schemaFieldName} is a repeated field`] = rawFieldData;
rawDecodedMessage[
`(${schemaMessage.name}) ${schemaFieldName} is a repeated field`
] = rawFieldData;
}
// Check for submessage fields
if (schemaField.resolvedType instanceof protobuf.Type) {
const subMessageType = schemaMessage.fields[schemaFieldName].type;
const schemaSubMessage = this.parsedProto.root.nested[subMessageType];
const subMessageType =
schemaMessage.fields[schemaFieldName].type;
const schemaSubMessage =
this.parsedProto.root.nested[subMessageType];
const rawSubMessages = rawDecodedMessage[fieldName];
let rawDecodedSubMessage = {};
// Squash multiple submessage instances into one submessage
if (Array.isArray(rawSubMessages)) {
rawSubMessages.forEach(subMessageInstance => {
const instanceFields = Object.entries(subMessageInstance);
instanceFields.forEach(subField => {
rawSubMessages.forEach((subMessageInstance) => {
const instanceFields =
Object.entries(subMessageInstance);
instanceFields.forEach((subField) => {
rawDecodedSubMessage[subField[0]] = subField[1];
});
});
@ -325,9 +354,14 @@ class Protobuf {
}
// Treat submessage as own message and compare its fields
rawDecodedSubMessage = Protobuf.compareFields(rawDecodedSubMessage, schemaSubMessage);
rawDecodedSubMessage = Protobuf.compareFields(
rawDecodedSubMessage,
schemaSubMessage,
);
if (Object.entries(rawDecodedSubMessage).length !== 0) {
rawDecodedMessage[`${schemaFieldName} (${subMessageType}) has missing fields`] = rawDecodedSubMessage;
rawDecodedMessage[
`${schemaFieldName} (${subMessageType}) has missing fields`
] = rawDecodedSubMessage;
}
}
delete rawDecodedMessage[fieldName];
@ -392,11 +426,11 @@ class Protobuf {
// Get the field key/values
const key = field.key;
const value = field.value;
object[key] = Object.prototype.hasOwnProperty.call(object, key) ?
object[key] instanceof Array ?
object[key].concat([value]) :
[object[key], value] :
value;
object[key] = Object.prototype.hasOwnProperty.call(object, key)
? object[key] instanceof Array
? object[key].concat([value])
: [object[key], value]
: value;
return object;
}
@ -412,23 +446,23 @@ class Protobuf {
const type = header.type;
const key = header.key;
if (typeof(this.fieldTypes[key]) !== "object") {
if (typeof this.fieldTypes[key] !== "object") {
this.fieldTypes[key] = type;
}
switch (type) {
// varint
case 0:
return { "key": key, "value": this._varInt() };
return { key: key, value: this._varInt() };
// fixed 64
case 1:
return { "key": key, "value": this._uint64() };
return { key: key, value: this._uint64() };
// length delimited
case 2:
return { "key": key, "value": this._lenDelim(key) };
return { key: key, value: this._lenDelim(key) };
// fixed 32
case 5:
return { "key": key, "value": this._uint32() };
return { key: key, value: this._uint32() };
// unknown type
default:
throw new Error("Unknown type 0x" + type.toString(16));
@ -443,7 +477,7 @@ class Protobuf {
*/
_fieldHeader() {
// Make sure we call type then number to preserve offset
return { "type": this._fieldType(), "key": this._fieldNumber() };
return { type: this._fieldType(), key: this._fieldNumber() };
}
/**
@ -472,11 +506,13 @@ class Protobuf {
let shift = -3;
let fieldNumber = 0;
do {
fieldNumber += shift < 28 ?
shift === -3 ?
(this.data[this.offset] & this.NUMBER) >> -shift :
(this.data[this.offset] & this.VALUE) << shift :
(this.data[this.offset] & this.VALUE) * Math.pow(2, shift);
fieldNumber +=
shift < 28
? shift === -3
? (this.data[this.offset] & this.NUMBER) >> -shift
: (this.data[this.offset] & this.VALUE) << shift
: (this.data[this.offset] & this.VALUE) *
Math.pow(2, shift);
shift += 7;
} while ((this.data[this.offset++] & this.MSB) === this.MSB);
return fieldNumber;
@ -495,9 +531,11 @@ class Protobuf {
let shift = 0;
// Keep reading while upper bit set
do {
value += shift < 28 ?
(this.data[this.offset] & this.VALUE) << shift :
(this.data[this.offset] & this.VALUE) * Math.pow(2, shift);
value +=
shift < 28
? (this.data[this.offset] & this.VALUE) << shift
: (this.data[this.offset] & this.VALUE) *
Math.pow(2, shift);
shift += 7;
} while ((this.data[this.offset++] & this.MSB) === this.MSB);
return value;
@ -511,8 +549,16 @@ class Protobuf {
*/
_uint64() {
// Read off a Uint64 with little-endian
const lowerHalf = this.data[this.offset++] + (this.data[this.offset++] * 0x100) + (this.data[this.offset++] * 0x10000) + this.data[this.offset++] * 0x1000000;
const upperHalf = this.data[this.offset++] + (this.data[this.offset++] * 0x100) + (this.data[this.offset++] * 0x10000) + this.data[this.offset++] * 0x1000000;
const lowerHalf =
this.data[this.offset++] +
this.data[this.offset++] * 0x100 +
this.data[this.offset++] * 0x10000 +
this.data[this.offset++] * 0x1000000;
const upperHalf =
this.data[this.offset++] +
this.data[this.offset++] * 0x100 +
this.data[this.offset++] * 0x10000 +
this.data[this.offset++] * 0x1000000;
return upperHalf * 0x100000000 + lowerHalf;
}
@ -533,8 +579,10 @@ class Protobuf {
field = pbObject._parse();
// Set field types object
this.fieldTypes[fieldNum] = {...this.fieldTypes[fieldNum], ...pbObject.fieldTypes};
this.fieldTypes[fieldNum] = {
...this.fieldTypes[fieldNum],
...pbObject.fieldTypes,
};
} catch (err) {
// Otherwise treat as bytes
field = Utils.byteArrayToChars(fieldBytes);
@ -552,7 +600,10 @@ class Protobuf {
*/
_uint32() {
// Use a dataview to read off the integer
const dataview = new DataView(new Uint8Array(this.data.slice(this.offset, this.offset + 4)).buffer);
const dataview = new DataView(
new Uint8Array(this.data.slice(this.offset, this.offset + 4))
.buffer,
);
const value = dataview.getUint32(0, true);
this.offset += 4;
return value;

View file

@ -17,8 +17,12 @@ import {toHexFast} from "../lib/Hex.mjs";
*/
export function objToTable(obj, nested = false) {
let html = `<table
class='table table-sm table-nonfluid ${nested ? "mb-0 table-borderless" : "table-bordered"}'
style='table-layout: fixed; ${nested ? "margin: -1px !important;" : ""}'>`;
class='table table-sm table-nonfluid ${
nested ? "mb-0 table-borderless" : "table-bordered"
}'
style='table-layout: fixed; ${
nested ? "margin: -1px !important;" : ""
}'>`;
if (!nested)
html += `<tr>
<th>Field</th>
@ -29,8 +33,7 @@ export function objToTable(obj, nested=false) {
html += `<tr><td style='word-wrap: break-word'>${key}</td>`;
if (typeof obj[key] === "object")
html += `<td style='padding: 0'>${objToTable(obj[key], true)}</td>`;
else
html += `<td>${obj[key]}</td>`;
else html += `<td>${obj[key]}</td>`;
html += "</tr>";
}
html += "</table>";

View file

@ -35,7 +35,6 @@ export function formatDnObj(dnObj, indent) {
return output.slice(0, -1);
}
/**
* Formats byte strings by adding line breaks and delimiters.
*

View file

@ -30,7 +30,7 @@ export async function parseQrCode(input, normalise) {
try {
if (normalise) {
image.rgba(false);
image.background(0xFFFFFFFF);
image.background(0xffffffff);
image.normalize();
image.greyscale();
image = await image.getBufferAsync(jimp.MIME_JPEG);
@ -58,7 +58,13 @@ export async function parseQrCode(input, normalise) {
* @param {string} errorCorrection
* @returns {ArrayBuffer}
*/
export function generateQrCode(input, format, moduleSize, margin, errorCorrection) {
export function generateQrCode(
input,
format,
moduleSize,
margin,
errorCorrection,
) {
const formats = ["SVG", "EPS", "PDF", "PNG"];
if (!formats.includes(format.toUpperCase())) {
throw new OperationError("Unsupported QR code format.");
@ -70,7 +76,7 @@ export function generateQrCode(input, format, moduleSize, margin, errorCorrectio
type: format,
size: moduleSize,
margin: margin,
"ec_level": errorCorrection.charAt(0).toUpperCase()
ec_level: errorCorrection.charAt(0).toUpperCase(),
});
} catch (err) {
throw new OperationError(`Error generating QR code. (${err})`);

View file

@ -10,7 +10,7 @@ import forge from "node-forge";
export const MD_ALGORITHMS = {
"SHA-1": forge.md.sha1,
"MD5": forge.md.md5,
MD5: forge.md.md5,
"SHA-256": forge.md.sha256,
"SHA-384": forge.md.sha384,
"SHA-512": forge.md.sha512,

View file

@ -8,7 +8,6 @@
* @todo Support for UTF16
*/
/**
* Runs rotation operations across the input data.
*
@ -29,7 +28,6 @@ export function rot(data, amount, algo) {
return result;
}
/**
* Rotate right bitwise op.
*
@ -49,10 +47,9 @@ export function rotr(b) {
*/
export function rotl(b) {
const bit = (b >> 7) & 1;
return ((b << 1) | bit) & 0xFF;
return ((b << 1) | bit) & 0xff;
}
/**
* Rotates a byte array to the right by a specific amount as a whole, so that bits are wrapped
* from the end of the array to the beginning.
@ -77,7 +74,6 @@ export function rotrCarry(data, amount) {
return result;
}
/**
* Rotates a byte array to the left by a specific amount as a whole, so that bits are wrapped
* from the beginning of the array to the end.
@ -94,9 +90,9 @@ export function rotlCarry(data, amount) {
amount = amount % 8;
for (let i = data.length - 1; i >= 0; i--) {
const oldByte = data[i];
newByte = ((oldByte << amount) | carryBits) & 0xFF;
newByte = ((oldByte << amount) | carryBits) & 0xff;
carryBits = (oldByte >> (8 - amount)) & (Math.pow(2, amount) - 1);
result[i] = (newByte);
result[i] = newByte;
}
result[data.length - 1] = result[data.length - 1] | carryBits;
return result;

View file

@ -19,7 +19,7 @@ export const CR_ROTORS = [
{ name: "Example 7", value: "TBYIUMKZDJSOPEWXVANHLCFQGR" },
{ name: "Example 8", value: "QZUPDTFNYIAOMLEBWJXCGHKRSV" },
{ name: "Example 9", value: "CZWNHEMPOVXLKRSIDGJFYBTQAU" },
{name: "Example 10", value: "ENPXJVKYQBFZTICAGMOHWRLDUS"}
{ name: "Example 10", value: "ENPXJVKYQBFZTICAGMOHWRLDUS" },
];
/**
@ -30,7 +30,7 @@ export const I_ROTORS = [
{ name: "Example 2", value: "6147253089" },
{ name: "Example 3", value: "8239647510" },
{ name: "Example 4", value: "7194835260" },
{name: "Example 5", value: "4873205916"}
{ name: "Example 5", value: "4873205916" },
];
export const NUMBERS = "0123456789".split("");
@ -53,7 +53,6 @@ export function convToUpperCase(letter) {
* The SIGABA machine consisting of the 3 rotor banks: cipher, control and index banks.
*/
export class SigabaMachine {
/**
* SigabaMachine constructor
*
@ -137,14 +136,12 @@ export class SigabaMachine {
}
return plaintext;
}
}
/**
* The cipher rotor bank consists of 5 cipher rotors in either a forward or reversed orientation.
*/
export class CipherBank {
/**
* CipherBank constructor
*
@ -187,7 +184,13 @@ export class CipherBank {
* @param {number[]} indexInputs - the inputs from the index rotors
*/
step(indexInputs) {
const logicDict = {0: [0, 9], 1: [7, 8], 2: [5, 6], 3: [3, 4], 4: [1, 2]};
const logicDict = {
0: [0, 9],
1: [7, 8],
2: [5, 6],
3: [3, 4],
4: [1, 2],
};
const rotorsToMove = [];
for (const key in logicDict) {
const item = logicDict[key];
@ -202,14 +205,12 @@ export class CipherBank {
rotor.step();
}
}
}
/**
* The control rotor bank consists of 5 control rotors in either a forward or reversed orientation. Signals to the control rotor bank always go from right-to-left.
*/
export class ControlBank {
/**
* ControlBank constructor. The rotors have been reversed as signals go from right-to-left through the control rotors.
*
@ -238,8 +239,23 @@ export class ControlBank {
* @returns {number[]}
*/
getOutputs() {
const outputs = [this.crypt("F"), this.crypt("G"), this.crypt("H"), this.crypt("I")];
const logicDict = {1: "B", 2: "C", 3: "DE", 4: "FGH", 5: "IJK", 6: "LMNO", 7: "PQRST", 8: "UVWXYZ", 9: "A"};
const outputs = [
this.crypt("F"),
this.crypt("G"),
this.crypt("H"),
this.crypt("I"),
];
const logicDict = {
1: "B",
2: "C",
3: "DE",
4: "FGH",
5: "IJK",
6: "LMNO",
7: "PQRST",
8: "UVWXYZ",
9: "A",
};
const numberOutputs = [];
for (const key in logicDict) {
const item = logicDict[key];
@ -257,7 +273,9 @@ export class ControlBank {
* Steps the control rotors. Only 3 of the control rotors step: one after every encryption, one after every 26, and one after every 26 squared.
*/
step() {
const MRotor = this.rotors[1], FRotor = this.rotors[2], SRotor = this.rotors[3];
const MRotor = this.rotors[1],
FRotor = this.rotors[2],
SRotor = this.rotors[3];
// 14 is the offset of "O" from "A" - the next rotor steps once the previous rotor reaches "O"
if (FRotor.state === 14) {
if (MRotor.state === 14) {
@ -278,14 +296,12 @@ export class ControlBank {
this.step();
return outputs;
}
}
/**
* The index rotor bank consists of 5 index rotors all placed in the forwards orientation.
*/
export class IndexBank {
/**
* IndexBank constructor
*
@ -321,14 +337,12 @@ export class IndexBank {
}
return outputs;
}
}
/**
* Rotor class
*/
export class Rotor {
/**
* Rotor constructor
*
@ -418,14 +432,12 @@ export class Rotor {
this.posMapping.splice(0, 0, lastNum);
this.state = this.posMapping[0];
}
}
/**
* A CRRotor is a cipher (C) or control (R) rotor. These rotors are identical and interchangeable. A C or R rotor consists of 26 contacts, one for each letter, and may be put into either a forwards of reversed orientation.
*/
export class CRRotor extends Rotor {
/**
* CRRotor constructor
*
@ -470,14 +482,12 @@ export class CRRotor extends Rotor {
const outPos = this.cryptNum(inputPos, direction);
return CRRotor.numToLetter(outPos);
}
}
/**
* An IRotor is an index rotor, which consists of 10 contacts each numbered from 0 to 9. Unlike C and R rotors, they cannot be put in the reversed orientation. The index rotors do not step at any point during encryption or decryption.
*/
export class IRotor extends Rotor {
/**
* IRotor constructor
*
@ -498,5 +508,4 @@ export class IRotor extends Rotor {
crypt(inputPos) {
return this.cryptNum(inputPos, "leftToRight");
}
}

View file

@ -23,34 +23,38 @@ const BLOCKSIZE = 16;
/** The S box, 256 8-bit values */
const Sbox = [
0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2, 0x28, 0xfb, 0x2c, 0x05,
0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3, 0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99,
0x9c, 0x42, 0x50, 0xf4, 0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62,
0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa, 0x75, 0x8f, 0x3f, 0xa6,
0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba, 0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8,
0x68, 0x6b, 0x81, 0xb2, 0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35,
0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b, 0x01, 0x21, 0x78, 0x87,
0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52, 0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e,
0xea, 0xbf, 0x8a, 0xd2, 0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1,
0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30, 0xf5, 0x8c, 0xb1, 0xe3,
0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60, 0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f,
0xd5, 0xdb, 0x37, 0x45, 0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51,
0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41, 0x1f, 0x10, 0x5a, 0xd8,
0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd, 0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0,
0x89, 0x69, 0x97, 0x4a, 0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,
0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e, 0xd7, 0xcb, 0x39, 0x48
0xd6, 0x90, 0xe9, 0xfe, 0xcc, 0xe1, 0x3d, 0xb7, 0x16, 0xb6, 0x14, 0xc2,
0x28, 0xfb, 0x2c, 0x05, 0x2b, 0x67, 0x9a, 0x76, 0x2a, 0xbe, 0x04, 0xc3,
0xaa, 0x44, 0x13, 0x26, 0x49, 0x86, 0x06, 0x99, 0x9c, 0x42, 0x50, 0xf4,
0x91, 0xef, 0x98, 0x7a, 0x33, 0x54, 0x0b, 0x43, 0xed, 0xcf, 0xac, 0x62,
0xe4, 0xb3, 0x1c, 0xa9, 0xc9, 0x08, 0xe8, 0x95, 0x80, 0xdf, 0x94, 0xfa,
0x75, 0x8f, 0x3f, 0xa6, 0x47, 0x07, 0xa7, 0xfc, 0xf3, 0x73, 0x17, 0xba,
0x83, 0x59, 0x3c, 0x19, 0xe6, 0x85, 0x4f, 0xa8, 0x68, 0x6b, 0x81, 0xb2,
0x71, 0x64, 0xda, 0x8b, 0xf8, 0xeb, 0x0f, 0x4b, 0x70, 0x56, 0x9d, 0x35,
0x1e, 0x24, 0x0e, 0x5e, 0x63, 0x58, 0xd1, 0xa2, 0x25, 0x22, 0x7c, 0x3b,
0x01, 0x21, 0x78, 0x87, 0xd4, 0x00, 0x46, 0x57, 0x9f, 0xd3, 0x27, 0x52,
0x4c, 0x36, 0x02, 0xe7, 0xa0, 0xc4, 0xc8, 0x9e, 0xea, 0xbf, 0x8a, 0xd2,
0x40, 0xc7, 0x38, 0xb5, 0xa3, 0xf7, 0xf2, 0xce, 0xf9, 0x61, 0x15, 0xa1,
0xe0, 0xae, 0x5d, 0xa4, 0x9b, 0x34, 0x1a, 0x55, 0xad, 0x93, 0x32, 0x30,
0xf5, 0x8c, 0xb1, 0xe3, 0x1d, 0xf6, 0xe2, 0x2e, 0x82, 0x66, 0xca, 0x60,
0xc0, 0x29, 0x23, 0xab, 0x0d, 0x53, 0x4e, 0x6f, 0xd5, 0xdb, 0x37, 0x45,
0xde, 0xfd, 0x8e, 0x2f, 0x03, 0xff, 0x6a, 0x72, 0x6d, 0x6c, 0x5b, 0x51,
0x8d, 0x1b, 0xaf, 0x92, 0xbb, 0xdd, 0xbc, 0x7f, 0x11, 0xd9, 0x5c, 0x41,
0x1f, 0x10, 0x5a, 0xd8, 0x0a, 0xc1, 0x31, 0x88, 0xa5, 0xcd, 0x7b, 0xbd,
0x2d, 0x74, 0xd0, 0x12, 0xb8, 0xe5, 0xb4, 0xb0, 0x89, 0x69, 0x97, 0x4a,
0x0c, 0x96, 0x77, 0x7e, 0x65, 0xb9, 0xf1, 0x09, 0xc5, 0x6e, 0xc6, 0x84,
0x18, 0xf0, 0x7d, 0xec, 0x3a, 0xdc, 0x4d, 0x20, 0x79, 0xee, 0x5f, 0x3e,
0xd7, 0xcb, 0x39, 0x48,
];
/** "Fixed parameter CK" used in key expansion */
const CK = [
0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269,
0x70777e85, 0x8c939aa1, 0xa8afb6bd, 0xc4cbd2d9,
0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9,
0xc0c7ced5, 0xdce3eaf1, 0xf8ff060d, 0x141b2229,
0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209,
0x10171e25, 0x2c333a41, 0x484f565d, 0x646b7279
0x00070e15, 0x1c232a31, 0x383f464d, 0x545b6269, 0x70777e85, 0x8c939aa1,
0xa8afb6bd, 0xc4cbd2d9, 0xe0e7eef5, 0xfc030a11, 0x181f262d, 0x343b4249,
0x50575e65, 0x6c737a81, 0x888f969d, 0xa4abb2b9, 0xc0c7ced5, 0xdce3eaf1,
0xf8ff060d, 0x141b2229, 0x30373e45, 0x4c535a61, 0x686f767d, 0x848b9299,
0xa0a7aeb5, 0xbcc3cad1, 0xd8dfe6ed, 0xf4fb0209, 0x10171e25, 0x2c333a41,
0x484f565d, 0x646b7279,
];
/** "System parameter FK" */
@ -73,8 +77,11 @@ function ROL(i, n) {
*/
function transformL(b) {
/* Replace each of the 4 bytes in b with the value at its offset in the Sbox */
b = (Sbox[(b >>> 24) & 0xFF] << 24) | (Sbox[(b >>> 16) & 0xFF] << 16) |
(Sbox[(b >>> 8) & 0xFF] << 8) | Sbox[b & 0xFF];
b =
(Sbox[(b >>> 24) & 0xff] << 24) |
(Sbox[(b >>> 16) & 0xff] << 16) |
(Sbox[(b >>> 8) & 0xff] << 8) |
Sbox[b & 0xff];
/* circular rotate and xor */
return b ^ ROL(b, 2) ^ ROL(b, 10) ^ ROL(b, 18) ^ ROL(b, 24);
}
@ -86,8 +93,11 @@ function transformL(b) {
*/
function transformLprime(b) {
/* Replace each of the 4 bytes in b with the value at its offset in the Sbox */
b = (Sbox[(b >>> 24) & 0xFF] << 24) | (Sbox[(b >>> 16) & 0xFF] << 16) |
(Sbox[(b >>> 8) & 0xFF] << 8) | Sbox[b & 0xFF];
b =
(Sbox[(b >>> 24) & 0xff] << 24) |
(Sbox[(b >>> 16) & 0xff] << 16) |
(Sbox[(b >>> 8) & 0xff] << 8) |
Sbox[b & 0xff];
return b ^ ROL(b, 13) ^ ROL(b, 23); /* circular rotate and XOR */
}
@ -98,7 +108,8 @@ function initSM4RoundKey(rawkey) {
const K = rawkey.map((a, i) => a ^ FK[i]); /* K = rawkey ^ FK */
const roundKey = [];
for (let i = 0; i < 32; i++)
roundKey[i] = K[i + 4] = K[i] ^ transformLprime(K[i + 1] ^ K[i + 2] ^ K[i + 3] ^ CK[i]);
roundKey[i] = K[i + 4] =
K[i] ^ transformLprime(K[i + 1] ^ K[i + 2] ^ K[i + 3] ^ CK[i]);
return roundKey;
}
@ -111,7 +122,8 @@ function initSM4RoundKey(rawkey) {
*/
function encryptBlockSM4(X, roundKey) {
for (let i = 0; i < NROUNDS; i++)
X[i + 4] = X[i] ^ transformL(X[i + 1] ^ X[i + 2] ^ X[i + 3] ^ roundKey[i]);
X[i + 4] =
X[i] ^ transformL(X[i + 1] ^ X[i + 2] ^ X[i + 3] ^ roundKey[i]);
return [X[35], X[34], X[33], X[32]];
}
@ -124,13 +136,29 @@ function encryptBlockSM4(X, roundKey) {
*/
function bytesToInts(bArray, offs = 0) {
let offset = offs;
const A = (bArray[offset] << 24) | (bArray[offset + 1] << 16) | (bArray[offset + 2] << 8) | bArray[offset + 3];
const A =
(bArray[offset] << 24) |
(bArray[offset + 1] << 16) |
(bArray[offset + 2] << 8) |
bArray[offset + 3];
offset += 4;
const B = (bArray[offset] << 24) | (bArray[offset + 1] << 16) | (bArray[offset + 2] << 8) | bArray[offset + 3];
const B =
(bArray[offset] << 24) |
(bArray[offset + 1] << 16) |
(bArray[offset + 2] << 8) |
bArray[offset + 3];
offset += 4;
const C = (bArray[offset] << 24) | (bArray[offset + 1] << 16) | (bArray[offset + 2] << 8) | bArray[offset + 3];
const C =
(bArray[offset] << 24) |
(bArray[offset + 1] << 16) |
(bArray[offset + 2] << 8) |
bArray[offset + 3];
offset += 4;
const D = (bArray[offset] << 24) | (bArray[offset + 1] << 16) | (bArray[offset + 2] << 8) | bArray[offset + 3];
const D =
(bArray[offset] << 24) |
(bArray[offset + 1] << 16) |
(bArray[offset + 2] << 8) |
bArray[offset + 3];
return [A, B, C, D];
}
@ -141,10 +169,10 @@ function bytesToInts(bArray, offs=0) {
function intsToBytes(ints) {
const bArr = [];
for (let i = 0; i < ints.length; i++) {
bArr.push((ints[i] >> 24) & 0xFF);
bArr.push((ints[i] >> 16) & 0xFF);
bArr.push((ints[i] >> 8) & 0xFF);
bArr.push(ints[i] & 0xFF);
bArr.push((ints[i] >> 24) & 0xff);
bArr.push((ints[i] >> 16) & 0xff);
bArr.push((ints[i] >> 8) & 0xff);
bArr.push(ints[i] & 0xff);
}
return bArr;
}
@ -161,36 +189,42 @@ function intsToBytes(ints) {
*/
export function encryptSM4(message, key, iv, mode = "ECB", noPadding = false) {
const messageLength = message.length;
if (messageLength === 0)
return [];
if (messageLength === 0) return [];
const roundKey = initSM4RoundKey(bytesToInts(key, 0));
/* Pad with PKCS#7 if requested for ECB/CBC else add zeroes (which are sliced off at the end) */
let padByte = 0;
let nPadding = 16 - (message.length & 0xF);
let nPadding = 16 - (message.length & 0xf);
if (mode === "ECB" || mode === "CBC") {
if (noPadding) {
if (nPadding !== 16)
throw new OperationError(`No padding requested in ${mode} mode but input is not a 16-byte multiple.`);
throw new OperationError(
`No padding requested in ${mode} mode but input is not a 16-byte multiple.`,
);
nPadding = 0;
} else
padByte = nPadding;
} else padByte = nPadding;
}
for (let i = 0; i < nPadding; i++)
message.push(padByte);
for (let i = 0; i < nPadding; i++) message.push(padByte);
const cipherText = [];
switch (mode) {
case "ECB":
for (let i = 0; i < message.length; i += BLOCKSIZE)
Array.prototype.push.apply(cipherText, intsToBytes(encryptBlockSM4(bytesToInts(message, i), roundKey)));
Array.prototype.push.apply(
cipherText,
intsToBytes(
encryptBlockSM4(bytesToInts(message, i), roundKey),
),
);
break;
case "CBC":
iv = bytesToInts(iv, 0);
for (let i = 0; i < message.length; i += BLOCKSIZE) {
const block = bytesToInts(message, i);
block[0] ^= iv[0]; block[1] ^= iv[1];
block[2] ^= iv[2]; block[3] ^= iv[3];
block[0] ^= iv[0];
block[1] ^= iv[1];
block[2] ^= iv[2];
block[3] ^= iv[3];
iv = encryptBlockSM4(block, roundKey);
Array.prototype.push.apply(cipherText, intsToBytes(iv));
}
@ -200,8 +234,10 @@ export function encryptSM4(message, key, iv, mode="ECB", noPadding=false) {
for (let i = 0; i < message.length; i += BLOCKSIZE) {
iv = encryptBlockSM4(iv, roundKey);
const block = bytesToInts(message, i);
block[0] ^= iv[0]; block[1] ^= iv[1];
block[2] ^= iv[2]; block[3] ^= iv[3];
block[0] ^= iv[0];
block[1] ^= iv[1];
block[2] ^= iv[2];
block[3] ^= iv[3];
Array.prototype.push.apply(cipherText, intsToBytes(block));
iv = block;
}
@ -211,8 +247,10 @@ export function encryptSM4(message, key, iv, mode="ECB", noPadding=false) {
for (let i = 0; i < message.length; i += BLOCKSIZE) {
iv = encryptBlockSM4(iv, roundKey);
const block = bytesToInts(message, i);
block[0] ^= iv[0]; block[1] ^= iv[1];
block[2] ^= iv[2]; block[3] ^= iv[3];
block[0] ^= iv[0];
block[1] ^= iv[1];
block[2] ^= iv[2];
block[3] ^= iv[3];
Array.prototype.push.apply(cipherText, intsToBytes(block));
}
break;
@ -220,11 +258,15 @@ export function encryptSM4(message, key, iv, mode="ECB", noPadding=false) {
iv = bytesToInts(iv, 0);
for (let i = 0; i < message.length; i += BLOCKSIZE) {
let iv2 = [...iv]; /* containing the IV + counter */
iv2[3] += (i >> 4);/* Using a 32 bit counter here. 64 Gb encrypts should be enough for everyone. */
iv2[3] +=
i >>
4; /* Using a 32 bit counter here. 64 Gb encrypts should be enough for everyone. */
iv2 = encryptBlockSM4(iv2, roundKey);
const block = bytesToInts(message, i);
block[0] ^= iv2[0]; block[1] ^= iv2[1];
block[2] ^= iv2[2]; block[3] ^= iv2[3];
block[0] ^= iv2[0];
block[1] ^= iv2[1];
block[2] ^= iv2[2];
block[3] ^= iv2[3];
Array.prototype.push.apply(cipherText, intsToBytes(block));
}
break;
@ -246,34 +288,53 @@ export function encryptSM4(message, key, iv, mode="ECB", noPadding=false) {
* @param {boolean] ignorePadding - If true, ignore padding issues in ECB/CBC mode.
* @returns {byteArray} - The cipher text.
*/
export function decryptSM4(cipherText, key, iv, mode="ECB", ignorePadding=false) {
export function decryptSM4(
cipherText,
key,
iv,
mode = "ECB",
ignorePadding = false,
) {
const originalLength = cipherText.length;
if (originalLength === 0)
return [];
if (originalLength === 0) return [];
let roundKey = initSM4RoundKey(bytesToInts(key, 0));
if (mode === "ECB" || mode === "CBC") {
/* Init decryption key */
roundKey = roundKey.reverse();
if ((originalLength & 0xF) !== 0 && !ignorePadding)
throw new OperationError(`With ECB or CBC modes, the input must be divisible into 16 byte blocks. (${cipherText.length & 0xF} bytes extra)`);
} else { /* Pad dummy bytes for other modes, chop them off at the end */
while ((cipherText.length & 0xF) !== 0)
cipherText.push(0);
if ((originalLength & 0xf) !== 0 && !ignorePadding)
throw new OperationError(
`With ECB or CBC modes, the input must be divisible into 16 byte blocks. (${
cipherText.length & 0xf
} bytes extra)`,
);
} else {
/* Pad dummy bytes for other modes, chop them off at the end */
while ((cipherText.length & 0xf) !== 0) cipherText.push(0);
}
const clearText = [];
switch (mode) {
case "ECB":
for (let i = 0; i < cipherText.length; i += BLOCKSIZE)
Array.prototype.push.apply(clearText, intsToBytes(encryptBlockSM4(bytesToInts(cipherText, i), roundKey)));
Array.prototype.push.apply(
clearText,
intsToBytes(
encryptBlockSM4(bytesToInts(cipherText, i), roundKey),
),
);
break;
case "CBC":
iv = bytesToInts(iv, 0);
for (let i = 0; i < cipherText.length; i += BLOCKSIZE) {
const block = encryptBlockSM4(bytesToInts(cipherText, i), roundKey);
block[0] ^= iv[0]; block[1] ^= iv[1];
block[2] ^= iv[2]; block[3] ^= iv[3];
const block = encryptBlockSM4(
bytesToInts(cipherText, i),
roundKey,
);
block[0] ^= iv[0];
block[1] ^= iv[1];
block[2] ^= iv[2];
block[3] ^= iv[3];
Array.prototype.push.apply(clearText, intsToBytes(block));
iv = bytesToInts(cipherText, i);
}
@ -283,8 +344,10 @@ export function decryptSM4(cipherText, key, iv, mode="ECB", ignorePadding=false)
for (let i = 0; i < cipherText.length; i += BLOCKSIZE) {
iv = encryptBlockSM4(iv, roundKey);
const block = bytesToInts(cipherText, i);
block[0] ^= iv[0]; block[1] ^= iv[1];
block[2] ^= iv[2]; block[3] ^= iv[3];
block[0] ^= iv[0];
block[1] ^= iv[1];
block[2] ^= iv[2];
block[3] ^= iv[3];
Array.prototype.push.apply(clearText, intsToBytes(block));
iv = bytesToInts(cipherText, i);
}
@ -294,8 +357,10 @@ export function decryptSM4(cipherText, key, iv, mode="ECB", ignorePadding=false)
for (let i = 0; i < cipherText.length; i += BLOCKSIZE) {
iv = encryptBlockSM4(iv, roundKey);
const block = bytesToInts(cipherText, i);
block[0] ^= iv[0]; block[1] ^= iv[1];
block[2] ^= iv[2]; block[3] ^= iv[3];
block[0] ^= iv[0];
block[1] ^= iv[1];
block[2] ^= iv[2];
block[3] ^= iv[3];
Array.prototype.push.apply(clearText, intsToBytes(block));
}
break;
@ -303,11 +368,15 @@ export function decryptSM4(cipherText, key, iv, mode="ECB", ignorePadding=false)
iv = bytesToInts(iv, 0);
for (let i = 0; i < cipherText.length; i += BLOCKSIZE) {
let iv2 = [...iv]; /* containing the IV + counter */
iv2[3] += (i >> 4);/* Using a 32 bit counter here. 64 Gb encrypts should be enough for everyone. */
iv2[3] +=
i >>
4; /* Using a 32 bit counter here. 64 Gb encrypts should be enough for everyone. */
iv2 = encryptBlockSM4(iv2, roundKey);
const block = bytesToInts(cipherText, i);
block[0] ^= iv2[0]; block[1] ^= iv2[1];
block[2] ^= iv2[2]; block[3] ^= iv2[3];
block[0] ^= iv2[0];
block[1] ^= iv2[1];
block[2] ^= iv2[2];
block[3] ^= iv2[3];
Array.prototype.push.apply(clearText, intsToBytes(block));
}
break;
@ -316,11 +385,9 @@ export function decryptSM4(cipherText, key, iv, mode="ECB", ignorePadding=false)
}
/* Check PKCS#7 padding */
if (mode === "ECB" || mode === "CBC") {
if (ignorePadding)
return clearText;
if (ignorePadding) return clearText;
const padByte = clearText[clearText.length - 1];
if (padByte > 16)
throw new OperationError("Invalid PKCS#7 padding.");
if (padByte > 16) throw new OperationError("Invalid PKCS#7 padding.");
for (let i = 0; i < padByte; i++)
if (clearText[clearText.length - i - 1] !== padByte)
throw new OperationError("Invalid PKCS#7 padding.");
@ -328,4 +395,3 @@ export function decryptSM4(cipherText, key, iv, mode="ECB", ignorePadding=false)
}
return clearText.slice(0, originalLength);
}

View file

@ -18,7 +18,6 @@ export function caseInsensitiveSort(a, b) {
return a.toLowerCase().localeCompare(b.toLowerCase());
}
/**
* Comparison operation for sorting of IPv4 addresses.
*
@ -59,7 +58,8 @@ export function numericSort(a, b) {
const ret = a_[i].localeCompare(b_[i]); // Compare strings
if (ret !== 0) return ret;
}
if (!isNaN(a_[i]) && !isNaN(b_[i])) { // Compare numbers
if (!isNaN(a_[i]) && !isNaN(b_[i])) {
// Compare numbers
if (a_[i] - b_[i] !== 0) return a_[i] - b_[i];
}
}
@ -79,12 +79,12 @@ export function hexadecimalSort(a, b) {
let a_ = a.split(/([^\da-f]+)/i),
b_ = b.split(/([^\da-f]+)/i);
a_ = a_.map(v => {
a_ = a_.map((v) => {
const t = parseInt(v, 16);
return isNaN(t) ? v : t;
});
b_ = b_.map(v => {
b_ = b_.map((v) => {
const t = parseInt(v, 16);
return isNaN(t) ? v : t;
});
@ -96,7 +96,8 @@ export function hexadecimalSort(a, b) {
const ret = a_[i].localeCompare(b_[i]); // Compare strings
if (ret !== 0) return ret;
}
if (!isNaN(a_[i]) && !isNaN(b_[i])) { // Compare numbers
if (!isNaN(a_[i]) && !isNaN(b_[i])) {
// Compare numbers
if (a_[i] - b_[i] !== 0) return a_[i] - b_[i];
}
}
@ -114,4 +115,3 @@ export function hexadecimalSort(a, b) {
export function lengthSort(a, b) {
return a.length - b.length;
}

View file

@ -13,7 +13,6 @@
* as various data types.
*/
export default class Stream {
/**
* Stream constructor.
*
@ -35,9 +34,8 @@ export default class Stream {
getBytes(numBytes = null) {
if (this.position > this.length) return undefined;
const newPosition = numBytes !== null ?
this.position + numBytes :
this.length;
const newPosition =
numBytes !== null ? this.position + numBytes : this.length;
const bytes = this.bytes.slice(this.position, newPosition);
this.position = newPosition;
this.bitPos = 0;
@ -84,7 +82,11 @@ export default class Stream {
val |= this.bytes[i];
}
} else {
for (let i = this.position + numBytes - 1; i >= this.position; i--) {
for (
let i = this.position + numBytes - 1;
i >= this.position;
i--
) {
val = val << 8;
val |= this.bytes[i];
}
@ -117,18 +119,15 @@ export default class Stream {
while (bitBufLen < numBits) {
if (endianness === "be")
bitBuf = (bitBuf << bitBufLen) | this.bytes[this.position++];
else
bitBuf |= this.bytes[this.position++] << bitBufLen;
else bitBuf |= this.bytes[this.position++] << bitBufLen;
bitBufLen += 8;
}
// Reverse back to numBits
if (bitBufLen > numBits) {
const excess = bitBufLen - numBits;
if (endianness === "be")
bitBuf >>>= excess;
else
bitBuf &= (1 << numBits) - 1;
if (endianness === "be") bitBuf >>>= excess;
else bitBuf &= (1 << numBits) - 1;
bitBufLen -= excess;
this.position--;
this.bitPos = 8 - excess;
@ -143,9 +142,9 @@ export default class Stream {
* @returns {number} The bit mask
*/
function bitMask(bitPos) {
return endianness === "be" ?
(1 << (8 - bitPos)) - 1 :
256 - (1 << bitPos);
return endianness === "be"
? (1 << (8 - bitPos)) - 1
: 256 - (1 << bitPos);
}
}
@ -160,7 +159,10 @@ export default class Stream {
this.bitPos = 0;
if (typeof val === "number") {
while (++this.position < this.length && this.bytes[this.position] !== val) {
while (
++this.position < this.length &&
this.bytes[this.position] !== val
) {
continue;
}
return;
@ -193,7 +195,10 @@ export default class Stream {
while (this.position < this.length) {
// Until we hit the final element of val in the stream.
while ((this.position < this.length) && (this.bytes[this.position++] !== initial));
while (
this.position < this.length &&
this.bytes[this.position++] !== initial
);
found = true;
@ -214,7 +219,6 @@ export default class Stream {
}
}
/**
* Consume bytes if they match the supplied value.
*
@ -250,7 +254,9 @@ export default class Stream {
moveForwardsBy(numBytes) {
const pos = this.position + numBytes;
if (pos < 0 || pos > this.length)
throw new Error("Cannot move to position " + pos + " in stream. Out of bounds.");
throw new Error(
"Cannot move to position " + pos + " in stream. Out of bounds.",
);
this.position = pos;
this.bitPos = 0;
}
@ -263,7 +269,9 @@ export default class Stream {
moveBackwardsBy(numBytes) {
const pos = this.position - numBytes;
if (pos < 0 || pos > this.length)
throw new Error("Cannot move to position " + pos + " in stream. Out of bounds.");
throw new Error(
"Cannot move to position " + pos + " in stream. Out of bounds.",
);
this.position = pos;
this.bitPos = 0;
}
@ -298,7 +306,9 @@ export default class Stream {
*/
moveTo(pos) {
if (pos < 0 || pos > this.length)
throw new Error("Cannot move to position " + pos + " in stream. Out of bounds.");
throw new Error(
"Cannot move to position " + pos + " in stream. Out of bounds.",
);
this.position = pos;
this.bitPos = 0;
}
@ -323,5 +333,4 @@ export default class Stream {
if (this.bitPos > 0) finish++;
return this.bytes.slice(start, finish);
}
}

View file

@ -10,14 +10,13 @@
const defaults = {
location: 0,
bytesInLength: 1,
basicEncodingRules: false
basicEncodingRules: false,
};
/**
* TLVParser library
*/
export default class TLVParser {
/**
* TLVParser constructor
*

View file

@ -34,9 +34,28 @@ export const REFLECTORS = [
// Special character handling on Typex keyboard
const KEYBOARD = {
"Q": "1", "W": "2", "E": "3", "R": "4", "T": "5", "Y": "6", "U": "7", "I": "8", "O": "9", "P": "0",
"A": "-", "S": "/", "D": "Z", "F": "%", "G": "X", "H": "£", "K": "(", "L": ")",
"C": "V", "B": "'", "N": ",", "M": "."
Q: "1",
W: "2",
E: "3",
R: "4",
T: "5",
Y: "6",
U: "7",
I: "8",
O: "9",
P: "0",
A: "-",
S: "/",
D: "Z",
F: "%",
G: "X",
H: "£",
K: "(",
L: ")",
C: "V",
B: "'",
N: ",",
M: ".",
};
const KEYBOARD_REV = {};
for (const i of Object.keys(KEYBOARD)) {
@ -160,7 +179,9 @@ export class Rotor extends Enigma.Rotor {
// wiring[i] is the original output
// Enigma.LETTERS[i] is the original input
const input = Utils.mod(26 - Enigma.a2i(wiring[i]), 26);
const output = Enigma.i2a(Utils.mod(26 - Enigma.a2i(Enigma.LETTERS[i]), 26));
const output = Enigma.i2a(
Utils.mod(26 - Enigma.a2i(Enigma.LETTERS[i]), 26),
);
outMap[input] = output;
}
wiringMod = outMap.join("");
@ -192,10 +213,12 @@ export class Plugboard extends Enigma.Rotor {
// We're going to achieve this by mapping the plugboard settings through an additional
// transform that mirrors the alphabet before we pass it to the superclass.
if (!/^[A-Z]{26}$/.test(wiring)) {
throw new OperationError("Plugboard wiring must be 26 unique uppercase letters");
throw new OperationError(
"Plugboard wiring must be 26 unique uppercase letters",
);
}
const reversed = "AZYXWVUTSRQPONMLKJIHGFEDCB";
wiring = wiring.replace(/./g, x => {
wiring = wiring.replace(/./g, (x) => {
return reversed[Enigma.a2i(x)];
});
try {
@ -222,6 +245,9 @@ export class Plugboard extends Enigma.Rotor {
* @returns {number}
*/
revTransform(c) {
return Utils.mod(this.revMap[Utils.mod(c + this.pos, 26)] - this.pos, 26);
return Utils.mod(
this.revMap[Utils.mod(c + this.pos, 26)] - this.pos,
26,
);
}
}

View file

@ -10,7 +10,11 @@ import zlibAndGzip from "zlibjs/bin/zlib_and_gzip.min.js";
const Zlib = zlibAndGzip.Zlib;
export const COMPRESSION_TYPE = ["Dynamic Huffman Coding", "Fixed Huffman Coding", "None (Store)"];
export const COMPRESSION_TYPE = [
"Dynamic Huffman Coding",
"Fixed Huffman Coding",
"None (Store)",
];
export const INFLATE_BUFFER_TYPE = ["Adaptive", "Block"];
export const ZLIB_COMPRESSION_TYPE_LOOKUP = {
"Fixed Huffman Coding": Zlib.Deflate.CompressionType.FIXED,

View file

@ -13,7 +13,6 @@ import OperationError from "../errors/OperationError.mjs";
* A1Z26 Cipher Decode operation
*/
class A1Z26CipherDecode extends Operation {
/**
* A1Z26CipherDecode constructor
*/
@ -22,7 +21,8 @@ class A1Z26CipherDecode extends Operation {
this.name = "A1Z26 Cipher Decode";
this.module = "Ciphers";
this.description = "Converts alphabet order numbers into their corresponding alphabet character.<br><br>e.g. <code>1</code> becomes <code>a</code> and <code>2</code> becomes <code>b</code>.";
this.description =
"Converts alphabet order numbers into their corresponding alphabet character.<br><br>e.g. <code>1</code> becomes <code>a</code> and <code>2</code> becomes <code>b</code>.";
this.infoURL = "";
this.inputType = "string";
this.outputType = "string";
@ -30,40 +30,40 @@ class A1Z26CipherDecode extends Operation {
{
name: "Delimiter",
type: "option",
value: DELIM_OPTIONS
}
value: DELIM_OPTIONS,
},
];
this.checks = [
{
pattern: "^\\s*([12]?[0-9] )+[12]?[0-9]\\s*$",
flags: "",
args: ["Space"]
args: ["Space"],
},
{
pattern: "^\\s*([12]?[0-9],)+[12]?[0-9]\\s*$",
flags: "",
args: ["Comma"]
args: ["Comma"],
},
{
pattern: "^\\s*([12]?[0-9];)+[12]?[0-9]\\s*$",
flags: "",
args: ["Semi-colon"]
args: ["Semi-colon"],
},
{
pattern: "^\\s*([12]?[0-9]:)+[12]?[0-9]\\s*$",
flags: "",
args: ["Colon"]
args: ["Colon"],
},
{
pattern: "^\\s*([12]?[0-9]\\n)+[12]?[0-9]\\s*$",
flags: "",
args: ["Line feed"]
args: ["Line feed"],
},
{
pattern: "^\\s*([12]?[0-9]\\r\\n)+[12]?[0-9]\\s*$",
flags: "",
args: ["CRLF"]
}
args: ["CRLF"],
},
];
}
@ -83,13 +83,14 @@ class A1Z26CipherDecode extends Operation {
let latin1 = "";
for (let i = 0; i < bites.length; i++) {
if (bites[i] < 1 || bites[i] > 26) {
throw new OperationError("Error: all numbers must be between 1 and 26.");
throw new OperationError(
"Error: all numbers must be between 1 and 26.",
);
}
latin1 += Utils.chr(parseInt(bites[i], 10) + 96);
}
return latin1;
}
}
export default A1Z26CipherDecode;

View file

@ -12,7 +12,6 @@ import {DELIM_OPTIONS} from "../lib/Delim.mjs";
* A1Z26 Cipher Encode operation
*/
class A1Z26CipherEncode extends Operation {
/**
* A1Z26CipherEncode constructor
*/
@ -21,7 +20,8 @@ class A1Z26CipherEncode extends Operation {
this.name = "A1Z26 Cipher Encode";
this.module = "Ciphers";
this.description = "Converts alphabet characters into their corresponding alphabet order number.<br><br>e.g. <code>a</code> becomes <code>1</code> and <code>b</code> becomes <code>2</code>.<br><br>Non-alphabet characters are dropped.";
this.description =
"Converts alphabet characters into their corresponding alphabet order number.<br><br>e.g. <code>a</code> becomes <code>1</code> and <code>b</code> becomes <code>2</code>.<br><br>Non-alphabet characters are dropped.";
this.infoURL = "";
this.inputType = "string";
this.outputType = "string";
@ -29,8 +29,8 @@ class A1Z26CipherEncode extends Operation {
{
name: "Delimiter",
type: "option",
value: DELIM_OPTIONS
}
value: DELIM_OPTIONS,
},
];
}
@ -55,7 +55,6 @@ class A1Z26CipherEncode extends Operation {
}
return output.slice(0, -delim.length);
}
}
export default A1Z26CipherEncode;

View file

@ -12,7 +12,6 @@ import { bitOp, add, BITWISE_OP_DELIMS } from "../lib/BitwiseOp.mjs";
* ADD operation
*/
class ADD extends Operation {
/**
* ADD constructor
*/
@ -21,17 +20,19 @@ class ADD extends Operation {
this.name = "ADD";
this.module = "Default";
this.description = "ADD the input with the given key (e.g. <code>fe023da5</code>), MOD 255";
this.infoURL = "https://wikipedia.org/wiki/Bitwise_operation#Bitwise_operators";
this.description =
"ADD the input with the given key (e.g. <code>fe023da5</code>), MOD 255";
this.infoURL =
"https://wikipedia.org/wiki/Bitwise_operation#Bitwise_operators";
this.inputType = "byteArray";
this.outputType = "byteArray";
this.args = [
{
"name": "Key",
"type": "toggleString",
"value": "",
"toggleValues": BITWISE_OP_DELIMS
}
name: "Key",
type: "toggleString",
value: "",
toggleValues: BITWISE_OP_DELIMS,
},
];
}
@ -41,7 +42,10 @@ class ADD extends Operation {
* @returns {byteArray}
*/
run(input, args) {
const key = Utils.convertToByteArray(args[0].string || "", args[0].option);
const key = Utils.convertToByteArray(
args[0].string || "",
args[0].option,
);
return bitOp(input, key, add);
}
@ -71,7 +75,6 @@ class ADD extends Operation {
highlightReverse(pos, args) {
return pos;
}
}
export default ADD;

View file

@ -13,7 +13,6 @@ import OperationError from "../errors/OperationError.mjs";
* AES Decrypt operation
*/
class AESDecrypt extends Operation {
/**
* AESDecrypt constructor
*/
@ -22,83 +21,85 @@ class AESDecrypt extends Operation {
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 as a default.<br><br><b>GCM Tag:</b> This field is ignored unless 'GCM' mode is used.";
this.infoURL = "https://wikipedia.org/wiki/Advanced_Encryption_Standard";
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 as a default.<br><br><b>GCM Tag:</b> This field is ignored unless 'GCM' mode is used.";
this.infoURL =
"https://wikipedia.org/wiki/Advanced_Encryption_Standard";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
"name": "Key",
"type": "toggleString",
"value": "",
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
name: "Key",
type: "toggleString",
value: "",
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"],
},
{
"name": "IV",
"type": "toggleString",
"value": "",
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
name: "IV",
type: "toggleString",
value: "",
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"],
},
{
"name": "Mode",
"type": "argSelector",
"value": [
name: "Mode",
type: "argSelector",
value: [
{
name: "CBC",
off: [5, 6]
off: [5, 6],
},
{
name: "CFB",
off: [5, 6]
off: [5, 6],
},
{
name: "OFB",
off: [5, 6]
off: [5, 6],
},
{
name: "CTR",
off: [5, 6]
off: [5, 6],
},
{
name: "GCM",
on: [5, 6]
on: [5, 6],
},
{
name: "ECB",
off: [5, 6]
off: [5, 6],
},
{
name: "CBC/NoPadding",
off: [5, 6]
off: [5, 6],
},
{
name: "ECB/NoPadding",
off: [5, 6]
}
]
off: [5, 6],
},
],
},
{
"name": "Input",
"type": "option",
"value": ["Hex", "Raw"]
name: "Input",
type: "option",
value: ["Hex", "Raw"],
},
{
"name": "Output",
"type": "option",
"value": ["Raw", "Hex"]
name: "Output",
type: "option",
value: ["Raw", "Hex"],
},
{
"name": "GCM Tag",
"type": "toggleString",
"value": "",
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
name: "GCM Tag",
type: "toggleString",
value: "",
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"],
},
{
"name": "Additional Authenticated Data",
"type": "toggleString",
"value": "",
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
}
name: "Additional Authenticated Data",
type: "toggleString",
value: "",
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"],
},
];
}
@ -142,18 +143,21 @@ The following algorithms will be used based on the size of the key:
decipher.start({
iv: iv.length === 0 ? "" : iv,
tag: mode === "GCM" ? gcmTag : undefined,
additionalData: mode === "GCM" ? aad : undefined
additionalData: mode === "GCM" ? aad : undefined,
});
decipher.update(forge.util.createBuffer(input));
const result = decipher.finish();
if (result) {
return outputType === "Hex" ? decipher.output.toHex() : decipher.output.getBytes();
return outputType === "Hex"
? decipher.output.toHex()
: decipher.output.getBytes();
} else {
throw new OperationError("Unable to decrypt input with these parameters.");
throw new OperationError(
"Unable to decrypt input with these parameters.",
);
}
}
}
export default AESDecrypt;

View file

@ -13,7 +13,6 @@ import OperationError from "../errors/OperationError.mjs";
* AES Encrypt operation
*/
class AESEncrypt extends Operation {
/**
* AESEncrypt constructor
*/
@ -22,69 +21,71 @@ class AESEncrypt extends Operation {
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.infoURL = "https://wikipedia.org/wiki/Advanced_Encryption_Standard";
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.infoURL =
"https://wikipedia.org/wiki/Advanced_Encryption_Standard";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
"name": "Key",
"type": "toggleString",
"value": "",
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
name: "Key",
type: "toggleString",
value: "",
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"],
},
{
"name": "IV",
"type": "toggleString",
"value": "",
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
name: "IV",
type: "toggleString",
value: "",
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"],
},
{
"name": "Mode",
"type": "argSelector",
"value": [
name: "Mode",
type: "argSelector",
value: [
{
name: "CBC",
off: [5]
off: [5],
},
{
name: "CFB",
off: [5]
off: [5],
},
{
name: "OFB",
off: [5]
off: [5],
},
{
name: "CTR",
off: [5]
off: [5],
},
{
name: "GCM",
on: [5]
on: [5],
},
{
name: "ECB",
off: [5]
}
]
off: [5],
},
],
},
{
"name": "Input",
"type": "option",
"value": ["Raw", "Hex"]
name: "Input",
type: "option",
value: ["Raw", "Hex"],
},
{
"name": "Output",
"type": "option",
"value": ["Hex", "Raw"]
name: "Output",
type: "option",
value: ["Hex", "Raw"],
},
{
"name": "Additional Authenticated Data",
"type": "toggleString",
"value": "",
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
}
name: "Additional Authenticated Data",
type: "toggleString",
value: "",
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"],
},
];
}
@ -117,26 +118,33 @@ The following algorithms will be used based on the size of the key:
const cipher = forge.cipher.createCipher("AES-" + mode, key);
cipher.start({
iv: iv,
additionalData: mode === "GCM" ? aad : undefined
additionalData: mode === "GCM" ? aad : undefined,
});
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() +
"\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() +
"\n\n" +
"Tag: " +
cipher.mode.tag.getBytes()
);
}
return cipher.output.getBytes();
}
}
}
export default AESEncrypt;

View file

@ -14,7 +14,6 @@ import OperationError from "../errors/OperationError.mjs";
* AES Key Unwrap operation
*/
class AESKeyUnwrap extends Operation {
/**
* AESKeyUnwrap constructor
*/
@ -23,32 +22,33 @@ class AESKeyUnwrap extends Operation {
this.name = "AES Key Unwrap";
this.module = "Ciphers";
this.description = "Decryptor for a key wrapping algorithm defined in RFC3394, which is used to protect keys in untrusted storage or communications, using AES.<br><br>This algorithm uses an AES key (KEK: key-encryption key) and a 64-bit IV to decrypt 64-bit blocks.";
this.description =
"Decryptor for a key wrapping algorithm defined in RFC3394, which is used to protect keys in untrusted storage or communications, using AES.<br><br>This algorithm uses an AES key (KEK: key-encryption key) and a 64-bit IV to decrypt 64-bit blocks.";
this.infoURL = "https://wikipedia.org/wiki/Key_wrap";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
"name": "Key (KEK)",
"type": "toggleString",
"value": "",
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
name: "Key (KEK)",
type: "toggleString",
value: "",
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"],
},
{
"name": "IV",
"type": "toggleString",
"value": "a6a6a6a6a6a6a6a6",
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
name: "IV",
type: "toggleString",
value: "a6a6a6a6a6a6a6a6",
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"],
},
{
"name": "Input",
"type": "option",
"value": ["Hex", "Raw"]
name: "Input",
type: "option",
value: ["Hex", "Raw"],
},
{
"name": "Output",
"type": "option",
"value": ["Hex", "Raw"]
name: "Output",
type: "option",
value: ["Hex", "Raw"],
},
];
}
@ -65,14 +65,24 @@ class AESKeyUnwrap extends Operation {
outputType = args[3];
if (kek.length !== 16 && kek.length !== 24 && kek.length !== 32) {
throw new OperationError("KEK must be either 16, 24, or 32 bytes (currently " + kek.length + " bytes)");
throw new OperationError(
"KEK must be either 16, 24, or 32 bytes (currently " +
kek.length +
" bytes)",
);
}
if (iv.length !== 8) {
throw new OperationError("IV must be 8 bytes (currently " + iv.length + " bytes)");
throw new OperationError(
"IV must be 8 bytes (currently " + iv.length + " bytes)",
);
}
const inputData = Utils.convertToByteString(input, inputType);
if (inputData.length % 8 !== 0 || inputData.length < 24) {
throw new OperationError("input must be 8n (n>=3) bytes (currently " + inputData.length + " bytes)");
throw new OperationError(
"input must be 8n (n>=3) bytes (currently " +
inputData.length +
" bytes)",
);
}
const cipher = forge.cipher.createCipher("AES-ECB", kek);
@ -90,8 +100,8 @@ class AESKeyUnwrap extends Operation {
}
let cntLower = R.length >>> 0;
let cntUpper = (R.length / ((1 << 30) * 4)) >>> 0;
cntUpper = cntUpper * 6 + ((cntLower * 6 / ((1 << 30) * 4)) >>> 0);
cntLower = cntLower * 6 >>> 0;
cntUpper = cntUpper * 6 + (((cntLower * 6) / ((1 << 30) * 4)) >>> 0);
cntLower = (cntLower * 6) >>> 0;
for (let j = 5; j >= 0; j--) {
for (let i = R.length - 1; i >= 0; i--) {
const aBuffer = Utils.strToArrayBuffer(A);
@ -100,7 +110,9 @@ class AESKeyUnwrap extends Operation {
aView.setUint32(4, aView.getUint32(4) ^ cntLower);
A = Utils.arrayBufferToStr(aBuffer, false);
decipher.start();
decipher.update(forge.util.createBuffer(A + R[i] + paddingBlock));
decipher.update(
forge.util.createBuffer(A + R[i] + paddingBlock),
);
decipher.finish();
const B = decipher.output.getBytes();
A = B.substring(0, 8);
@ -122,7 +134,6 @@ class AESKeyUnwrap extends Operation {
}
return P;
}
}
export default AESKeyUnwrap;

View file

@ -14,7 +14,6 @@ import OperationError from "../errors/OperationError.mjs";
* AES Key Wrap operation
*/
class AESKeyWrap extends Operation {
/**
* AESKeyWrap constructor
*/
@ -23,32 +22,33 @@ class AESKeyWrap extends Operation {
this.name = "AES Key Wrap";
this.module = "Ciphers";
this.description = "A key wrapping algorithm defined in RFC3394, which is used to protect keys in untrusted storage or communications, using AES.<br><br>This algorithm uses an AES key (KEK: key-encryption key) and a 64-bit IV to encrypt 64-bit blocks.";
this.description =
"A key wrapping algorithm defined in RFC3394, which is used to protect keys in untrusted storage or communications, using AES.<br><br>This algorithm uses an AES key (KEK: key-encryption key) and a 64-bit IV to encrypt 64-bit blocks.";
this.infoURL = "https://wikipedia.org/wiki/Key_wrap";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
"name": "Key (KEK)",
"type": "toggleString",
"value": "",
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
name: "Key (KEK)",
type: "toggleString",
value: "",
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"],
},
{
"name": "IV",
"type": "toggleString",
"value": "a6a6a6a6a6a6a6a6",
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
name: "IV",
type: "toggleString",
value: "a6a6a6a6a6a6a6a6",
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"],
},
{
"name": "Input",
"type": "option",
"value": ["Hex", "Raw"]
name: "Input",
type: "option",
value: ["Hex", "Raw"],
},
{
"name": "Output",
"type": "option",
"value": ["Hex", "Raw"]
name: "Output",
type: "option",
value: ["Hex", "Raw"],
},
];
}
@ -65,14 +65,24 @@ class AESKeyWrap extends Operation {
outputType = args[3];
if (kek.length !== 16 && kek.length !== 24 && kek.length !== 32) {
throw new OperationError("KEK must be either 16, 24, or 32 bytes (currently " + kek.length + " bytes)");
throw new OperationError(
"KEK must be either 16, 24, or 32 bytes (currently " +
kek.length +
" bytes)",
);
}
if (iv.length !== 8) {
throw new OperationError("IV must be 8 bytes (currently " + iv.length + " bytes)");
throw new OperationError(
"IV must be 8 bytes (currently " + iv.length + " bytes)",
);
}
const inputData = Utils.convertToByteString(input, inputType);
if (inputData.length % 8 !== 0 || inputData.length < 16) {
throw new OperationError("input must be 8n (n>=2) bytes (currently " + inputData.length + " bytes)");
throw new OperationError(
"input must be 8n (n>=2) bytes (currently " +
inputData.length +
" bytes)",
);
}
const cipher = forge.cipher.createCipher("AES-ECB", kek);
@ -82,7 +92,8 @@ class AESKeyWrap extends Operation {
for (let i = 0; i < inputData.length; i += 8) {
R.push(inputData.substring(i, i + 8));
}
let cntLower = 1, cntUpper = 0;
let cntLower = 1,
cntUpper = 0;
for (let j = 0; j < 6; j++) {
for (let i = 0; i < R.length; i++) {
cipher.start();
@ -109,7 +120,6 @@ class AESKeyWrap extends Operation {
}
return C;
}
}
export default AESKeyWrap;

View file

@ -12,7 +12,6 @@ import { AMF0, AMF3 } from "@astronautlabs/amf";
* AMF Decode operation
*/
class AMFDecode extends Operation {
/**
* AMFDecode constructor
*/
@ -21,7 +20,8 @@ class AMFDecode extends Operation {
this.name = "AMF Decode";
this.module = "Encodings";
this.description = "Action Message Format (AMF) is a binary format used to serialize object graphs such as ActionScript objects and XML, or send messages between an Adobe Flash client and a remote service, usually a Flash Media Server or third party alternatives.";
this.description =
"Action Message Format (AMF) is a binary format used to serialize object graphs such as ActionScript objects and XML, or send messages between an Adobe Flash client and a remote service, usually a Flash Media Server or third party alternatives.";
this.infoURL = "https://wikipedia.org/wiki/Action_Message_Format";
this.inputType = "ArrayBuffer";
this.outputType = "JSON";
@ -30,8 +30,8 @@ class AMFDecode extends Operation {
name: "Format",
type: "option",
value: ["AMF0", "AMF3"],
defaultIndex: 1
}
defaultIndex: 1,
},
];
}
@ -46,7 +46,6 @@ class AMFDecode extends Operation {
const encoded = new Uint8Array(input);
return handler.Value.deserialize(encoded);
}
}
export default AMFDecode;

View file

@ -12,7 +12,6 @@ import { AMF0, AMF3 } from "@astronautlabs/amf";
* AMF Encode operation
*/
class AMFEncode extends Operation {
/**
* AMFEncode constructor
*/
@ -21,7 +20,8 @@ class AMFEncode extends Operation {
this.name = "AMF Encode";
this.module = "Encodings";
this.description = "Action Message Format (AMF) is a binary format used to serialize object graphs such as ActionScript objects and XML, or send messages between an Adobe Flash client and a remote service, usually a Flash Media Server or third party alternatives.";
this.description =
"Action Message Format (AMF) is a binary format used to serialize object graphs such as ActionScript objects and XML, or send messages between an Adobe Flash client and a remote service, usually a Flash Media Server or third party alternatives.";
this.infoURL = "https://wikipedia.org/wiki/Action_Message_Format";
this.inputType = "JSON";
this.outputType = "ArrayBuffer";
@ -30,8 +30,8 @@ class AMFEncode extends Operation {
name: "Format",
type: "option",
value: ["AMF0", "AMF3"],
defaultIndex: 1
}
defaultIndex: 1,
},
];
}
@ -46,7 +46,6 @@ class AMFEncode extends Operation {
const output = handler.Value.any(input).serialize();
return output.buffer;
}
}
export default AMFEncode;

View file

@ -12,7 +12,6 @@ import { bitOp, and, BITWISE_OP_DELIMS } from "../lib/BitwiseOp.mjs";
* AND operation
*/
class AND extends Operation {
/**
* AND constructor
*/
@ -21,17 +20,18 @@ class AND extends Operation {
this.name = "AND";
this.module = "Default";
this.description = "AND the input with the given key.<br>e.g. <code>fe023da5</code>";
this.description =
"AND the input with the given key.<br>e.g. <code>fe023da5</code>";
this.infoURL = "https://wikipedia.org/wiki/Bitwise_operation#AND";
this.inputType = "byteArray";
this.outputType = "byteArray";
this.args = [
{
"name": "Key",
"type": "toggleString",
"value": "",
"toggleValues": BITWISE_OP_DELIMS
}
name: "Key",
type: "toggleString",
value: "",
toggleValues: BITWISE_OP_DELIMS,
},
];
}
@ -41,7 +41,10 @@ class AND extends Operation {
* @returns {byteArray}
*/
run(input, args) {
const key = Utils.convertToByteArray(args[0].string || "", args[0].option);
const key = Utils.convertToByteArray(
args[0].string || "",
args[0].option,
);
return bitOp(input, key, and);
}
@ -71,7 +74,6 @@ class AND extends Operation {
highlightReverse(pos, args) {
return pos;
}
}
export default AND;

View file

@ -10,7 +10,6 @@ import Operation from "../Operation.mjs";
* Add line numbers operation
*/
class AddLineNumbers extends Operation {
/**
* AddLineNumbers constructor
*/
@ -36,11 +35,11 @@ class AddLineNumbers extends Operation {
let output = "";
for (let n = 0; n < lines.length; n++) {
output += (n+1).toString().padStart(width, " ") + " " + lines[n] + "\n";
output +=
(n + 1).toString().padStart(width, " ") + " " + lines[n] + "\n";
}
return output.slice(0, output.length - 1);
}
}
export default AddLineNumbers;

View file

@ -15,7 +15,6 @@ import jimp from "jimp";
* Add Text To Image operation
*/
class AddTextToImage extends Operation {
/**
* AddTextToImage constructor
*/
@ -24,7 +23,8 @@ class AddTextToImage extends Operation {
this.name = "Add Text To Image";
this.module = "Image";
this.description = "Adds text onto an image.<br><br>Text can be horizontally or vertically aligned, or the position can be manually specified.<br>Variants of the Roboto font face are available in any size or colour.";
this.description =
"Adds text onto an image.<br><br>Text can be horizontally or vertically aligned, or the position can be manually specified.<br>Variants of the Roboto font face are available in any size or colour.";
this.infoURL = "";
this.inputType = "ArrayBuffer";
this.outputType = "ArrayBuffer";
@ -33,72 +33,67 @@ class AddTextToImage extends Operation {
{
name: "Text",
type: "string",
value: ""
value: "",
},
{
name: "Horizontal align",
type: "option",
value: ["None", "Left", "Center", "Right"]
value: ["None", "Left", "Center", "Right"],
},
{
name: "Vertical align",
type: "option",
value: ["None", "Top", "Middle", "Bottom"]
value: ["None", "Top", "Middle", "Bottom"],
},
{
name: "X position",
type: "number",
value: 0
value: 0,
},
{
name: "Y position",
type: "number",
value: 0
value: 0,
},
{
name: "Size",
type: "number",
value: 32,
min: 8
min: 8,
},
{
name: "Font face",
type: "option",
value: [
"Roboto",
"Roboto Black",
"Roboto Mono",
"Roboto Slab"
]
value: ["Roboto", "Roboto Black", "Roboto Mono", "Roboto Slab"],
},
{
name: "Red",
type: "number",
value: 255,
min: 0,
max: 255
max: 255,
},
{
name: "Green",
type: "number",
value: 255,
min: 0,
max: 255
max: 255,
},
{
name: "Blue",
type: "number",
value: 255,
min: 0,
max: 255
max: 255,
},
{
name: "Alpha",
type: "number",
value: 255,
min: 0,
max: 255
}
max: 255,
},
];
}
@ -137,33 +132,49 @@ class AddTextToImage extends Operation {
const fontsMap = {};
const fonts = [
import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/Roboto72White.fnt"),
import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoBlack72White.fnt"),
import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoMono72White.fnt"),
import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoSlab72White.fnt")
import(
/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/Roboto72White.fnt"
),
import(
/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoBlack72White.fnt"
),
import(
/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoMono72White.fnt"
),
import(
/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoSlab72White.fnt"
),
];
await Promise.all(fonts)
.then(fonts => {
await Promise.all(fonts).then((fonts) => {
fontsMap.Roboto = fonts[0];
fontsMap["Roboto Black"] = fonts[1];
fontsMap["Roboto Mono"] = fonts[2];
fontsMap["Roboto Slab"] = fonts[3];
});
// Make Webpack load the png font images
await Promise.all([
import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/Roboto72White.png"),
import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoSlab72White.png"),
import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoMono72White.png"),
import(/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoBlack72White.png")
import(
/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/Roboto72White.png"
),
import(
/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoSlab72White.png"
),
import(
/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoMono72White.png"
),
import(
/* webpackMode: "eager" */ "../../web/static/fonts/bmfonts/RobotoBlack72White.png"
),
]);
const font = fontsMap[fontFace];
// LoadFont needs an absolute url, so append the font name to self.docURL
const jimpFont = await jimp.loadFont(self.docURL + "/" + font.default);
const jimpFont = await jimp.loadFont(
self.docURL + "/" + font.default,
);
jimpFont.pages.forEach(function (page) {
if (page.bitmap) {
@ -175,22 +186,31 @@ class AddTextToImage extends Operation {
const idx = (iy * pageWidth + ix) << 2;
const newRed = page.bitmap.data[idx] - (255 - red);
const newGreen = page.bitmap.data[idx + 1] - (255 - green);
const newBlue = page.bitmap.data[idx + 2] - (255 - blue);
const newAlpha = page.bitmap.data[idx + 3] - (255 - alpha);
const newGreen =
page.bitmap.data[idx + 1] - (255 - green);
const newBlue =
page.bitmap.data[idx + 2] - (255 - blue);
const newAlpha =
page.bitmap.data[idx + 3] - (255 - alpha);
// Make sure the bitmap values don't go below 0 as that makes jimp very unhappy
page.bitmap.data[idx] = (newRed > 0) ? newRed : 0;
page.bitmap.data[idx + 1] = (newGreen > 0) ? newGreen : 0;
page.bitmap.data[idx + 2] = (newBlue > 0) ? newBlue : 0;
page.bitmap.data[idx + 3] = (newAlpha > 0) ? newAlpha : 0;
page.bitmap.data[idx] = newRed > 0 ? newRed : 0;
page.bitmap.data[idx + 1] =
newGreen > 0 ? newGreen : 0;
page.bitmap.data[idx + 2] =
newBlue > 0 ? newBlue : 0;
page.bitmap.data[idx + 3] =
newAlpha > 0 ? newAlpha : 0;
}
}
}
});
// Create a temporary image to hold the rendered text
const textImage = new jimp(jimp.measureText(jimpFont, text), jimp.measureTextHeight(jimpFont, text));
const textImage = new jimp(
jimp.measureText(jimpFont, text),
jimp.measureTextHeight(jimpFont, text),
);
textImage.print(jimpFont, 0, 0, text);
// Scale the rendered text image to the correct size
@ -210,7 +230,7 @@ class AddTextToImage extends Operation {
xPos = 0;
break;
case "Center":
xPos = (image.getWidth() / 2) - (textImage.getWidth() / 2);
xPos = image.getWidth() / 2 - textImage.getWidth() / 2;
break;
case "Right":
xPos = image.getWidth() - textImage.getWidth();
@ -222,7 +242,7 @@ class AddTextToImage extends Operation {
yPos = 0;
break;
case "Middle":
yPos = (image.getHeight() / 2) - (textImage.getHeight() / 2);
yPos = image.getHeight() / 2 - textImage.getHeight() / 2;
break;
case "Bottom":
yPos = image.getHeight() - textImage.getHeight();
@ -261,7 +281,6 @@ class AddTextToImage extends Operation {
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
}
}
export default AddTextToImage;

View file

@ -11,7 +11,6 @@ import Utils from "../Utils.mjs";
* Adler-32 Checksum operation
*/
class Adler32Checksum extends Operation {
/**
* Adler32Checksum constructor
*/
@ -20,7 +19,8 @@ class Adler32Checksum extends Operation {
this.name = "Adler-32 Checksum";
this.module = "Crypto";
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.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.infoURL = "https://wikipedia.org/wiki/Adler-32";
this.inputType = "ArrayBuffer";
this.outputType = "string";
@ -48,7 +48,6 @@ class Adler32Checksum extends Operation {
return Utils.hex(((b << 16) | a) >>> 0, 8);
}
}
export default Adler32Checksum;

View file

@ -12,7 +12,6 @@ import OperationError from "../errors/OperationError.mjs";
* Affine Cipher Decode operation
*/
class AffineCipherDecode extends Operation {
/**
* AffineCipherDecode constructor
*/
@ -21,21 +20,22 @@ class AffineCipherDecode extends Operation {
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.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.infoURL = "https://wikipedia.org/wiki/Affine_cipher";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
"name": "a",
"type": "number",
"value": 1
name: "a",
type: "number",
value: 1,
},
{
"name": "b",
"type": "number",
"value": 0
}
name: "b",
type: "number",
value: 0,
},
];
}
@ -53,7 +53,9 @@ class AffineCipherDecode extends Operation {
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.");
throw new OperationError(
"The values of a and b can only be integers.",
);
}
if (Utils.gcd(a, 26) !== 1) {
@ -63,10 +65,23 @@ class AffineCipherDecode extends Operation {
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)];
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();
output +=
alphabet[
Utils.mod(
(alphabet.indexOf(input[i].toLowerCase()) - b) *
aModInv,
26,
)
].toUpperCase();
} else {
// Non-alphabetic characters
output += input[i];
@ -100,7 +115,6 @@ class AffineCipherDecode extends Operation {
highlightReverse(pos, args) {
return pos;
}
}
export default AffineCipherDecode;

View file

@ -11,7 +11,6 @@ import { affineEncode } from "../lib/Ciphers.mjs";
* Affine Cipher Encode operation
*/
class AffineCipherEncode extends Operation {
/**
* AffineCipherEncode constructor
*/
@ -20,21 +19,22 @@ class AffineCipherEncode extends Operation {
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.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.infoURL = "https://wikipedia.org/wiki/Affine_cipher";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
"name": "a",
"type": "number",
"value": 1
name: "a",
type: "number",
value: 1,
},
{
"name": "b",
"type": "number",
"value": 0
}
name: "b",
type: "number",
value: 0,
},
];
}
@ -72,7 +72,6 @@ class AffineCipherEncode extends Operation {
highlightReverse(pos, args) {
return pos;
}
}
export default AffineCipherEncode;

View file

@ -11,7 +11,6 @@ import OperationError from "../errors/OperationError.mjs";
* Analyse hash operation
*/
class AnalyseHash extends Operation {
/**
* AnalyseHash constructor
*/
@ -20,8 +19,10 @@ class AnalyseHash extends Operation {
this.name = "Analyse hash";
this.module = "Crypto";
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.infoURL = "https://wikipedia.org/wiki/Comparison_of_cryptographic_hash_functions";
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.infoURL =
"https://wikipedia.org/wiki/Comparison_of_cryptographic_hash_functions";
this.inputType = "string";
this.outputType = "string";
this.args = [];
@ -44,9 +45,16 @@ class AnalyseHash extends Operation {
throw new OperationError("Invalid hash");
}
output += "Hash length: " + input.length + "\n" +
"Byte length: " + byteLength + "\n" +
"Bit length: " + bitLength + "\n\n" +
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) {
@ -58,31 +66,21 @@ class AnalyseHash extends Operation {
];
break;
case 8:
possibleHashFunctions = [
"Fletcher-8",
];
possibleHashFunctions = ["Fletcher-8"];
break;
case 16:
possibleHashFunctions = [
"BSD checksum",
"CRC-16",
"SYSV checksum",
"Fletcher-16"
"Fletcher-16",
];
break;
case 32:
possibleHashFunctions = [
"CRC-32",
"Fletcher-32",
"Adler-32",
];
possibleHashFunctions = ["CRC-32", "Fletcher-32", "Adler-32"];
break;
case 64:
possibleHashFunctions = [
"CRC-64",
"RIPEMD-64",
"SipHash",
];
possibleHashFunctions = ["CRC-64", "RIPEMD-64", "SipHash"];
break;
case 128:
possibleHashFunctions = [
@ -107,10 +105,7 @@ class AnalyseHash extends Operation {
];
break;
case 192:
possibleHashFunctions = [
"Tiger",
"HAVAL-192",
];
possibleHashFunctions = ["Tiger", "HAVAL-192"];
break;
case 224:
possibleHashFunctions = [
@ -137,9 +132,7 @@ class AnalyseHash extends Operation {
];
break;
case 320:
possibleHashFunctions = [
"RIPEMD-320",
];
possibleHashFunctions = ["RIPEMD-320"];
break;
case 384:
possibleHashFunctions = [
@ -165,20 +158,15 @@ class AnalyseHash extends Operation {
];
break;
case 1024:
possibleHashFunctions = [
"Fowler-Noll-Vo",
];
possibleHashFunctions = ["Fowler-Noll-Vo"];
break;
default:
possibleHashFunctions = [
"Unknown"
];
possibleHashFunctions = ["Unknown"];
break;
}
return output + possibleHashFunctions.join("\n");
}
}
export default AnalyseHash;

View file

@ -13,7 +13,6 @@ import argon2 from "argon2-browser";
* Argon2 operation
*/
class Argon2 extends Operation {
/**
* Argon2 constructor
*/
@ -22,48 +21,49 @@ class Argon2 extends Operation {
this.name = "Argon2";
this.module = "Crypto";
this.description = "Argon2 is a key derivation function that was selected as the winner of the Password Hashing Competition in July 2015. It was designed by Alex Biryukov, Daniel Dinu, and Dmitry Khovratovich from the University of Luxembourg.<br><br>Enter the password in the input to generate its hash.";
this.description =
"Argon2 is a key derivation function that was selected as the winner of the Password Hashing Competition in July 2015. It was designed by Alex Biryukov, Daniel Dinu, and Dmitry Khovratovich from the University of Luxembourg.<br><br>Enter the password in the input to generate its hash.";
this.infoURL = "https://wikipedia.org/wiki/Argon2";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
"name": "Salt",
"type": "toggleString",
"value": "somesalt",
"toggleValues": ["UTF8", "Hex", "Base64", "Latin1"]
name: "Salt",
type: "toggleString",
value: "somesalt",
toggleValues: ["UTF8", "Hex", "Base64", "Latin1"],
},
{
"name": "Iterations",
"type": "number",
"value": 3
name: "Iterations",
type: "number",
value: 3,
},
{
"name": "Memory (KiB)",
"type": "number",
"value": 4096
name: "Memory (KiB)",
type: "number",
value: 4096,
},
{
"name": "Parallelism",
"type": "number",
"value": 1
name: "Parallelism",
type: "number",
value: 1,
},
{
"name": "Hash length (bytes)",
"type": "number",
"value": 32
name: "Hash length (bytes)",
type: "number",
value: 32,
},
{
"name": "Type",
"type": "option",
"value": ["Argon2i", "Argon2d", "Argon2id"],
"defaultIndex": 0
name: "Type",
type: "option",
value: ["Argon2i", "Argon2d", "Argon2id"],
defaultIndex: 0,
},
{
"name": "Output format",
"type": "option",
"value": ["Encoded hash", "Hex hash", "Raw hash"]
}
name: "Output format",
type: "option",
value: ["Encoded hash", "Hex hash", "Raw hash"],
},
];
}
@ -74,12 +74,15 @@ class Argon2 extends Operation {
*/
async run(input, args) {
const argon2Types = {
"Argon2i": argon2.ArgonType.Argon2i,
"Argon2d": argon2.ArgonType.Argon2d,
"Argon2id": argon2.ArgonType.Argon2id
Argon2i: argon2.ArgonType.Argon2i,
Argon2d: argon2.ArgonType.Argon2d,
Argon2id: argon2.ArgonType.Argon2id,
};
const salt = Utils.convertToByteString(args[0].string || "", args[0].option),
const salt = Utils.convertToByteString(
args[0].string || "",
args[0].option,
),
time = args[1],
mem = args[2],
parallelism = args[3],
@ -111,7 +114,6 @@ class Argon2 extends Operation {
throw new OperationError(`Error: ${err.message}`);
}
}
}
export default Argon2;

View file

@ -11,7 +11,6 @@ import argon2 from "argon2-browser";
* Argon2 compare operation
*/
class Argon2Compare extends Operation {
/**
* Argon2Compare constructor
*/
@ -20,16 +19,17 @@ class Argon2Compare extends Operation {
this.name = "Argon2 compare";
this.module = "Crypto";
this.description = "Tests whether the input matches the given Argon2 hash. To test multiple possible passwords, use the 'Fork' operation.";
this.description =
"Tests whether the input matches the given Argon2 hash. To test multiple possible passwords, use the 'Fork' operation.";
this.infoURL = "https://wikipedia.org/wiki/Argon2";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
"name": "Encoded hash",
"type": "string",
"value": ""
}
name: "Encoded hash",
type: "string",
value: "",
},
];
}
@ -44,7 +44,7 @@ class Argon2Compare extends Operation {
try {
await argon2.verify({
pass: input,
encoded
encoded,
});
return `Match: ${input}`;
@ -52,7 +52,6 @@ class Argon2Compare extends Operation {
return "No match";
}
}
}
export default Argon2Compare;

Some files were not shown because too many files have changed in this diff Show more