Merge branch 'pr/5'
6
.babelrc
|
@ -4,9 +4,11 @@
|
|||
"targets": {
|
||||
"chrome": 40,
|
||||
"firefox": 35,
|
||||
"edge": 14
|
||||
"edge": 14,
|
||||
"node": "6.5",
|
||||
},
|
||||
"modules": false
|
||||
"modules": false,
|
||||
"useBuiltIns": true
|
||||
}]
|
||||
]
|
||||
}
|
||||
|
|
|
@ -1 +1,2 @@
|
|||
src/core/lib/**
|
||||
src/core/config/MetaConfig.js
|
|
@ -28,11 +28,7 @@
|
|||
// modify rules from base configurations
|
||||
"no-unused-vars": ["error", {
|
||||
"args": "none",
|
||||
"vars": "local",
|
||||
// Allow vars that start with a capital letter to be unused.
|
||||
// This is mainly for exported module names which are useful to indicate
|
||||
// the name of the module and may be used to refer to itself in future.
|
||||
"varsIgnorePattern": "^[A-Z]"
|
||||
"vars": "all"
|
||||
}],
|
||||
"no-empty": ["error", {
|
||||
"allowEmptyCatch": true
|
||||
|
@ -52,6 +48,9 @@
|
|||
"no-trailing-spaces": "warn",
|
||||
"eol-last": "error",
|
||||
"func-call-spacing": "error",
|
||||
"key-spacing": ["warn", {
|
||||
"mode": "minimum"
|
||||
}],
|
||||
"indent": ["error", 4, {
|
||||
"ArrayExpression": "first",
|
||||
"SwitchCase": 1
|
||||
|
@ -93,6 +92,10 @@
|
|||
"moment": false,
|
||||
|
||||
"COMPILE_TIME": false,
|
||||
"COMPILE_MSG": false
|
||||
"COMPILE_MSG": false,
|
||||
"PKG_VERSION": false,
|
||||
"ENVIRONMENT_IS_WORKER": false,
|
||||
"ENVIRONMENT_IS_NODE": false,
|
||||
"ENVIRONMENT_IS_WEB": false
|
||||
}
|
||||
}
|
||||
|
|
13
.github/ISSUE_TEMPLATE.md
vendored
|
@ -5,21 +5,10 @@
|
|||
<!-- Misc: -->
|
||||
|
||||
### Summary
|
||||
<!-- If you're describing a bug, tell us what's wrong -->
|
||||
<!-- If you're suggesting a change/improvement, tell us what it is and how it should work -->
|
||||
|
||||
|
||||
### Example
|
||||
<!-- If describing a bug, tell us what happens instead of the expected behavior -->
|
||||
<!-- Include a link that triggers the bug if possible -->
|
||||
<!-- If you are requesting a new operation, include example input and output -->
|
||||
|
||||
### Possible solutions
|
||||
<!-- Not obligatory, but suggest a fix/reason for the bug, or ideas for how to -->
|
||||
<!-- implement the addition or change, including links to relevant resources -->
|
||||
|
||||
### Environment
|
||||
<!-- Include any relevant details about the environment you experienced the bug in -->
|
||||
<!-- This information is displayed in the About/Support pane -->
|
||||
* CyberChef compile time:
|
||||
* User-Agent:
|
||||
* [Link to reproduce]()
|
||||
|
|
1
.gitignore
vendored
|
@ -6,3 +6,4 @@ docs/*
|
|||
!docs/*.conf.json
|
||||
!docs/*.ico
|
||||
.vscode
|
||||
src/core/config/MetaConfig.js
|
12
.travis.yml
|
@ -1,6 +1,6 @@
|
|||
language: node_js
|
||||
node_js:
|
||||
- node
|
||||
- "8.4"
|
||||
install: npm install
|
||||
before_script:
|
||||
- npm install -g grunt
|
||||
|
@ -22,7 +22,7 @@ deploy:
|
|||
repo: gchq/CyberChef
|
||||
branch: master
|
||||
- provider: releases
|
||||
skip_cleaup: true
|
||||
skip_cleanup: true
|
||||
api_key:
|
||||
secure: "HV1WSKv4l/0Y2bKKs1iBJocBcmLj08PCRUeEM/jTwA4jqJ8EiLHWiXtER/D5sEg2iibRVKd2OQjfrmS6bo4AiwdeVgAKmv0FtS2Jw+391N8Nd5AkEANHa5Om/IpHLTL2YRAjpJTsDpY72bMUTJIwjQA3TFJkgrpOw6KYfohOcgbxLpZ4XuNJRU3VL4Hsxdv5V9aOVmfFOmMOVPQlakXy7NgtW5POp1f2WJwgcZxylkR1CjwaqMyXmSoVl46pyH3tr5+dptsQoKSGdi6sIHGA60oDotFPcm+0ifa47wZw+vapuuDi4tdNxhrHGaDMG8xiE0WFDHwQUDlk2/+W7j9SEX0H3Em7us371JXRp56EDwEcDa34VpVkC6i8HGcHK55hnxVbMZXGf3qhOFD8wY7qMbjMRvIpucrMHBi86OfkDfv0vDj2LyvIl5APj/AX50BrE0tfH1MZbH26Jkx4NdlkcxQ14GumarmUqfmVvbX/fsoA6oUuAAE9ZgRRi3KHO4wci6KUcRfdm+XOeUkaBFsL86G3EEYIvrtBTuaypdz+Cx7nd1iPZyWMx5Y1gXnVzha4nBdV4+7l9JIsFggD8QVpw2uHXQiS1KXFjOeqA3DBD8tjMB7q26Fl2fD3jkOo4BTbQ2NrRIZUu/iL+fOmMPsyMt2qulB0yaSBCfkbEq8xrUA="
|
||||
file:
|
||||
|
@ -39,4 +39,10 @@ deploy:
|
|||
on:
|
||||
tags: true
|
||||
branch: master
|
||||
|
||||
notifications:
|
||||
webhooks:
|
||||
urls:
|
||||
- https://webhooks.gitter.im/e/83c143a6822e218d5b34
|
||||
on_success: change
|
||||
on_failure: always
|
||||
on_start: never
|
||||
|
|
46
CODE_OF_CONDUCT.md
Normal file
|
@ -0,0 +1,46 @@
|
|||
# Contributor Covenant Code of Conduct
|
||||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at oss@gchq.gov.uk. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
|
||||
|
||||
[homepage]: http://contributor-covenant.org
|
||||
[version]: http://contributor-covenant.org/version/1/4/
|
330
Gruntfile.js
|
@ -1,7 +1,18 @@
|
|||
"use strict";
|
||||
|
||||
const webpack = require("webpack");
|
||||
const ExtractTextPlugin = require("extract-text-webpack-plugin");
|
||||
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
||||
const NodeExternals = require("webpack-node-externals");
|
||||
const Inliner = require("web-resource-inliner");
|
||||
const fs = require("fs");
|
||||
|
||||
/**
|
||||
* Grunt configuration for building the app in various formats.
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
module.exports = function (grunt) {
|
||||
grunt.file.defaultEncoding = "utf8";
|
||||
|
@ -10,15 +21,15 @@ module.exports = function (grunt) {
|
|||
// Tasks
|
||||
grunt.registerTask("dev",
|
||||
"A persistent task which creates a development build whenever source files are modified.",
|
||||
["clean:dev", "webpack:webDev"]);
|
||||
["clean:dev", "concurrent:dev"]);
|
||||
|
||||
grunt.registerTask("node",
|
||||
"Compiles CyberChef into a single NodeJS module.",
|
||||
["clean:node", "webpack:node", "chmod:build"]);
|
||||
["clean:node", "webpack:metaConf", "webpack:node", "chmod:build"]);
|
||||
|
||||
grunt.registerTask("test",
|
||||
"A task which runs all the tests in test/tests.",
|
||||
["clean:test", "webpack:tests", "execute:test"]);
|
||||
["clean:test", "webpack:metaConf", "webpack:tests", "execute:test"]);
|
||||
|
||||
grunt.registerTask("docs",
|
||||
"Compiles documentation in the /docs directory.",
|
||||
|
@ -26,7 +37,7 @@ module.exports = function (grunt) {
|
|||
|
||||
grunt.registerTask("prod",
|
||||
"Creates a production-ready build. Use the --msg flag to add a compile message.",
|
||||
["eslint", "clean:prod", "webpack:webProd", "inline", "chmod"]);
|
||||
["eslint", "clean:prod", "webpack:metaConf", "webpack:web", "inline", "chmod"]);
|
||||
|
||||
grunt.registerTask("default",
|
||||
"Lints the code base",
|
||||
|
@ -34,8 +45,10 @@ module.exports = function (grunt) {
|
|||
|
||||
grunt.registerTask("inline",
|
||||
"Compiles a production build of CyberChef into a single, portable web page.",
|
||||
runInliner);
|
||||
["webpack:webInline", "runInliner", "clean:inlineScripts"]);
|
||||
|
||||
|
||||
grunt.registerTask("runInliner", runInliner);
|
||||
grunt.registerTask("doc", "docs");
|
||||
grunt.registerTask("tests", "test");
|
||||
grunt.registerTask("lint", "eslint");
|
||||
|
@ -51,31 +64,28 @@ module.exports = function (grunt) {
|
|||
grunt.loadNpmTasks("grunt-exec");
|
||||
grunt.loadNpmTasks("grunt-execute");
|
||||
grunt.loadNpmTasks("grunt-accessibility");
|
||||
grunt.loadNpmTasks("grunt-concurrent");
|
||||
|
||||
|
||||
// Project configuration
|
||||
const compileTime = grunt.template.today("UTC:dd/mm/yyyy HH:MM:ss") + " UTC",
|
||||
banner = "/**\n" +
|
||||
"* CyberChef - The Cyber Swiss Army Knife\n" +
|
||||
"*\n" +
|
||||
"* @copyright Crown Copyright 2016\n" +
|
||||
"* @license Apache-2.0\n" +
|
||||
"*\n" +
|
||||
"* Copyright 2016 Crown Copyright\n" +
|
||||
"*\n" +
|
||||
'* Licensed under the Apache License, Version 2.0 (the "License");\n' +
|
||||
"* you may not use this file except in compliance with the License.\n" +
|
||||
"* You may obtain a copy of the License at\n" +
|
||||
"*\n" +
|
||||
"* http://www.apache.org/licenses/LICENSE-2.0\n" +
|
||||
"*\n" +
|
||||
"* Unless required by applicable law or agreed to in writing, software\n" +
|
||||
'* distributed under the License is distributed on an "AS IS" BASIS,\n' +
|
||||
"* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" +
|
||||
"* See the License for the specific language governing permissions and\n" +
|
||||
"* limitations under the License.\n" +
|
||||
"*/\n",
|
||||
pkg = grunt.file.readJSON("package.json");
|
||||
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") || ""),
|
||||
PKG_VERSION: JSON.stringify(pkg.version),
|
||||
ENVIRONMENT_IS_WORKER: function() {
|
||||
return typeof importScripts === "function";
|
||||
},
|
||||
ENVIRONMENT_IS_NODE: function() {
|
||||
return typeof process === "object" && typeof require === "function";
|
||||
},
|
||||
ENVIRONMENT_IS_WEB: function() {
|
||||
return typeof window === "object";
|
||||
}
|
||||
},
|
||||
moduleEntryPoints = listEntryModules();
|
||||
|
||||
/**
|
||||
* Compiles a production build of CyberChef into a single, portable web page.
|
||||
|
@ -104,20 +114,36 @@ module.exports = function (grunt) {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates an entry list for all the modules.
|
||||
*/
|
||||
function listEntryModules() {
|
||||
const path = "./src/core/config/modules/";
|
||||
let entryModules = {};
|
||||
|
||||
fs.readdirSync(path).forEach(file => {
|
||||
if (file !== "Default.js" && file !== "OpModules.js")
|
||||
entryModules[file.split(".js")[0]] = path + file;
|
||||
});
|
||||
|
||||
return entryModules;
|
||||
}
|
||||
|
||||
grunt.initConfig({
|
||||
clean: {
|
||||
dev: ["build/dev/*"],
|
||||
prod: ["build/prod/*"],
|
||||
test: ["build/test/*"],
|
||||
node: ["build/node/*"],
|
||||
docs: ["docs/*", "!docs/*.conf.json", "!docs/*.ico"],
|
||||
dev: ["build/dev/*", "src/core/config/MetaConfig.js"],
|
||||
prod: ["build/prod/*", "src/core/config/MetaConfig.js"],
|
||||
test: ["build/test/*", "src/core/config/MetaConfig.js"],
|
||||
node: ["build/node/*", "src/core/config/MetaConfig.js"],
|
||||
docs: ["docs/*", "!docs/*.conf.json", "!docs/*.ico", "!docs/*.png"],
|
||||
inlineScripts: ["build/prod/scripts.js"],
|
||||
},
|
||||
eslint: {
|
||||
options: {
|
||||
configFile: "./.eslintrc.json"
|
||||
},
|
||||
configs: ["Gruntfile.js"],
|
||||
core: ["src/core/**/*.js", "!src/core/lib/**/*"],
|
||||
core: ["src/core/**/*.js", "!src/core/lib/**/*", "!src/core/config/MetaConfig.js"],
|
||||
web: ["src/web/**/*.js"],
|
||||
node: ["src/node/**/*.js"],
|
||||
tests: ["test/**/*.js"],
|
||||
|
@ -134,9 +160,16 @@ module.exports = function (grunt) {
|
|||
src: [
|
||||
"src/**/*.js",
|
||||
"!src/core/lib/**/*",
|
||||
"!src/core/config/MetaConfig.js"
|
||||
],
|
||||
}
|
||||
},
|
||||
concurrent: {
|
||||
options: {
|
||||
logConcurrentOutput: true
|
||||
},
|
||||
dev: ["webpack:metaConfDev", "webpack-dev-server:start"]
|
||||
},
|
||||
accessibility: {
|
||||
options: {
|
||||
accessibilityLevel: "WCAG2A",
|
||||
|
@ -150,110 +183,47 @@ module.exports = function (grunt) {
|
|||
}
|
||||
},
|
||||
webpack: {
|
||||
options: {
|
||||
plugins: [
|
||||
new webpack.ProvidePlugin({
|
||||
$: "jquery",
|
||||
jQuery: "jquery",
|
||||
moment: "moment-timezone"
|
||||
}),
|
||||
new webpack.BannerPlugin({
|
||||
banner: banner,
|
||||
raw: true,
|
||||
entryOnly: true
|
||||
}),
|
||||
new webpack.DefinePlugin({
|
||||
COMPILE_TIME: JSON.stringify(compileTime),
|
||||
COMPILE_MSG: JSON.stringify(grunt.option("compile-msg") || grunt.option("msg") || "")
|
||||
}),
|
||||
new ExtractTextPlugin("styles.css"),
|
||||
],
|
||||
resolve: {
|
||||
alias: {
|
||||
jquery: "jquery/src/jquery"
|
||||
}
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.js$/,
|
||||
exclude: /node_modules/,
|
||||
loader: "babel-loader?compact=false"
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: ExtractTextPlugin.extract({
|
||||
use: [
|
||||
{ loader: "css-loader?minimize" },
|
||||
{ loader: "postcss-loader" },
|
||||
]
|
||||
})
|
||||
},
|
||||
{
|
||||
test: /\.less$/,
|
||||
use: ExtractTextPlugin.extract({
|
||||
use: [
|
||||
{ loader: "css-loader?minimize" },
|
||||
{ loader: "postcss-loader" },
|
||||
{ loader: "less-loader" }
|
||||
]
|
||||
})
|
||||
},
|
||||
{
|
||||
test: /\.(ico|eot|ttf|woff|woff2)$/,
|
||||
loader: "url-loader",
|
||||
options: {
|
||||
limit: 10000
|
||||
}
|
||||
},
|
||||
// { // First party images are saved as files to be cached
|
||||
// test: /\.(png|jpg|gif|svg)$/,
|
||||
// exclude: /node_modules/,
|
||||
// loader: "file-loader",
|
||||
// options: {
|
||||
// name: "images/[name].[ext]"
|
||||
// }
|
||||
// },
|
||||
{ // Third party images are inlined
|
||||
test: /\.(png|jpg|gif|svg)$/,
|
||||
exclude: /web\/static/,
|
||||
loader: "url-loader",
|
||||
options: {
|
||||
limit: 10000
|
||||
}
|
||||
},
|
||||
]
|
||||
},
|
||||
stats: {
|
||||
children: false,
|
||||
warningsFilter: /source-map/
|
||||
}
|
||||
},
|
||||
webDev: {
|
||||
target: "web",
|
||||
entry: "./src/web/index.js",
|
||||
options: webpackConfig,
|
||||
metaConf: {
|
||||
target: "node",
|
||||
entry: "./src/core/config/OperationConfig.js",
|
||||
output: {
|
||||
filename: "scripts.js",
|
||||
path: __dirname + "/build/dev"
|
||||
filename: "MetaConfig.js",
|
||||
path: __dirname + "/src/core/config/",
|
||||
library: "MetaConfig",
|
||||
libraryTarget: "commonjs2",
|
||||
libraryExport: "default"
|
||||
},
|
||||
plugins: [
|
||||
new HtmlWebpackPlugin({
|
||||
filename: "index.html",
|
||||
template: "./src/web/html/index.html",
|
||||
compileTime: compileTime,
|
||||
version: pkg.version,
|
||||
})
|
||||
],
|
||||
externals: [NodeExternals()],
|
||||
},
|
||||
metaConfDev: {
|
||||
target: "node",
|
||||
entry: "./src/core/config/OperationConfig.js",
|
||||
output: {
|
||||
filename: "MetaConfig.js",
|
||||
path: __dirname + "/src/core/config/",
|
||||
library: "MetaConfig",
|
||||
libraryTarget: "commonjs2",
|
||||
libraryExport: "default"
|
||||
},
|
||||
externals: [NodeExternals()],
|
||||
watch: true
|
||||
},
|
||||
webProd: {
|
||||
web: {
|
||||
target: "web",
|
||||
entry: "./src/web/index.js",
|
||||
entry: Object.assign({
|
||||
main: "./src/web/index.js"
|
||||
}, moduleEntryPoints),
|
||||
output: {
|
||||
filename: "scripts.js",
|
||||
path: __dirname + "/build/prod"
|
||||
},
|
||||
resolve: {
|
||||
alias: {
|
||||
"./config/modules/OpModules.js": "./config/modules/Default.js"
|
||||
}
|
||||
},
|
||||
plugins: [
|
||||
new webpack.DefinePlugin(BUILD_CONSTANTS),
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
compress: {
|
||||
"screw_ie8": true,
|
||||
|
@ -263,9 +233,10 @@ module.exports = function (grunt) {
|
|||
},
|
||||
comments: false,
|
||||
}),
|
||||
new HtmlWebpackPlugin({ // Main version
|
||||
new HtmlWebpackPlugin({
|
||||
filename: "index.html",
|
||||
template: "./src/web/html/index.html",
|
||||
chunks: ["main"],
|
||||
compileTime: compileTime,
|
||||
version: pkg.version,
|
||||
minify: {
|
||||
|
@ -275,7 +246,27 @@ module.exports = function (grunt) {
|
|||
minifyCSS: true
|
||||
}
|
||||
}),
|
||||
new HtmlWebpackPlugin({ // Inline version
|
||||
]
|
||||
},
|
||||
webInline: {
|
||||
target: "web",
|
||||
entry: "./src/web/index.js",
|
||||
output: {
|
||||
filename: "scripts.js",
|
||||
path: __dirname + "/build/prod"
|
||||
},
|
||||
plugins: [
|
||||
new webpack.DefinePlugin(BUILD_CONSTANTS),
|
||||
new webpack.optimize.UglifyJsPlugin({
|
||||
compress: {
|
||||
"screw_ie8": true,
|
||||
"dead_code": true,
|
||||
"unused": true,
|
||||
"warnings": false
|
||||
},
|
||||
comments: false,
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
filename: "cyberchef.htm",
|
||||
template: "./src/web/html/index.html",
|
||||
compileTime: compileTime,
|
||||
|
@ -293,35 +284,96 @@ module.exports = function (grunt) {
|
|||
tests: {
|
||||
target: "node",
|
||||
entry: "./test/index.js",
|
||||
externals: [NodeExternals()],
|
||||
output: {
|
||||
filename: "index.js",
|
||||
path: __dirname + "/build/test"
|
||||
}
|
||||
},
|
||||
plugins: [
|
||||
new webpack.DefinePlugin(BUILD_CONSTANTS)
|
||||
]
|
||||
},
|
||||
node: {
|
||||
target: "node",
|
||||
entry: "./src/node/index.js",
|
||||
externals: [NodeExternals()],
|
||||
output: {
|
||||
filename: "CyberChef.js",
|
||||
path: __dirname + "/build/node",
|
||||
library: "CyberChef",
|
||||
libraryTarget: "commonjs2"
|
||||
},
|
||||
plugins: [
|
||||
new webpack.DefinePlugin(BUILD_CONSTANTS)
|
||||
]
|
||||
}
|
||||
},
|
||||
"webpack-dev-server": {
|
||||
options: {
|
||||
webpack: webpackConfig,
|
||||
host: "0.0.0.0",
|
||||
disableHostCheck: true,
|
||||
overlay: true,
|
||||
inline: false,
|
||||
clientLogLevel: "error",
|
||||
stats: {
|
||||
children: false,
|
||||
chunks: false,
|
||||
modules: false,
|
||||
warningsFilter: /source-map/,
|
||||
}
|
||||
},
|
||||
start: {
|
||||
webpack: {
|
||||
target: "web",
|
||||
entry: Object.assign({
|
||||
main: "./src/web/index.js"
|
||||
}, moduleEntryPoints),
|
||||
resolve: {
|
||||
alias: {
|
||||
"./config/modules/OpModules.js": "./config/modules/Default.js"
|
||||
}
|
||||
},
|
||||
plugins: [
|
||||
new webpack.DefinePlugin(BUILD_CONSTANTS),
|
||||
new HtmlWebpackPlugin({
|
||||
filename: "index.html",
|
||||
template: "./src/web/html/index.html",
|
||||
chunks: ["main"],
|
||||
compileTime: compileTime,
|
||||
version: pkg.version,
|
||||
})
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
copy: {
|
||||
ghPages: {
|
||||
options: {
|
||||
process: function (content) {
|
||||
process: function (content, srcpath) {
|
||||
// Add Google Analytics code to index.html
|
||||
content = content.replace("</body></html>",
|
||||
grunt.file.read("src/web/static/ga.html") + "</body></html>");
|
||||
return grunt.template.process(content);
|
||||
}
|
||||
if (srcpath.indexOf("index.html") >= 0) {
|
||||
content = content.replace("</body></html>",
|
||||
grunt.file.read("src/web/static/ga.html") + "</body></html>");
|
||||
return grunt.template.process(content, srcpath);
|
||||
} else {
|
||||
return content;
|
||||
}
|
||||
},
|
||||
noProcess: ["**", "!**/*.html"]
|
||||
},
|
||||
src: "build/prod/index.html",
|
||||
dest: "build/prod/index.html"
|
||||
},
|
||||
files: [
|
||||
{
|
||||
src: "build/prod/index.html",
|
||||
dest: "build/prod/index.html"
|
||||
},
|
||||
{
|
||||
expand: true,
|
||||
src: "docs/**",
|
||||
dest: "build/prod/"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
chmod: {
|
||||
build: {
|
||||
|
|
47
README.md
|
@ -1,8 +1,11 @@
|
|||
# CyberChef
|
||||
|
||||
[](https://travis-ci.org/gchq/CyberChef)
|
||||
[](https://www.npmjs.com/package/cyberchef)
|
||||

|
||||
[](https://david-dm.org/gchq/CyberChef)
|
||||
[](https://www.npmjs.com/package/cyberchef)
|
||||

|
||||
[](https://github.com/gchq/CyberChef/blob/master/LICENSE)
|
||||
[](https://gitter.im/gchq/CyberChef?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
This is a fork of original CyberChef by GCHQ. This project has implemented my own operations for the daily SoC tasks. Please feel free to clone/test/share/contribute it.
|
||||
|
||||
## Features
|
||||
|
@ -30,9 +33,9 @@ This is a fork of original CyberChef by GCHQ. This project has implemented my ow
|
|||
|
||||
#### *The Cyber Swiss Army Knife*
|
||||
|
||||
CyberChef is a simple, intuitive web app for carrying out all manner of "cyber" operations within a web browser. These operations include creating hexdumps, simple encoding like XOR or Base64, more complex encryption like AES, DES and Blowfish, data compression and decompression, calculating hashes and checksums, IPv6 and X.509 parsing, and much more.
|
||||
CyberChef is a simple, intuitive web app for carrying out all manner of "cyber" operations within a web browser. These operations include simple encoding like XOR or Base64, more complex encryption like AES, DES and Blowfish, creating binary and hexdumps, compression and decompression of data, calculating hashes and checksums, IPv6 and X.509 parsing, changing character encodings, and much more.
|
||||
|
||||
The tool is designed to enable both technical and non-technical analysts to manipulate data in complex ways without having to deal with complex tools or algorithms. It was conceived, designed, built and incrementally improved by an analyst in their 10% innovation time over several years. Every effort has been made to structure the code in a readable and extendable format, however it should be noted that the analyst is not a professional developer and the code has not been peer-reviewed for compliance with a formal specification.
|
||||
The tool is designed to enable both technical and non-technical analysts to manipulate data in complex ways without having to deal with complex tools or algorithms. It was conceived, designed, built and incrementally improved by an analyst in their 10% innovation time over several years. Every effort has been made to structure the code in a readable and extendable format, however it should be noted that the analyst is not a professional developer.
|
||||
|
||||
## Live demo
|
||||
|
||||
|
@ -48,9 +51,9 @@ Cryptographic operations in CyberChef should not be relied upon to provide secur
|
|||
There are four main areas in CyberChef:
|
||||
|
||||
1. The **input** box in the top right, where you can paste, type or drag the data you want to operate on.
|
||||
2. The **output** box in the bottom right, where the outcome of the specified processing will be displayed.
|
||||
2. The **output** box in the bottom right, where the outcome of your processing will be displayed.
|
||||
3. The **operations** list on the far left, where you can find all the operations that CyberChef is capable of in categorised lists, or by searching.
|
||||
4. The **recipe** area in the middle, where you drag the operations that you want to use and specify arguments and options.
|
||||
4. The **recipe** area in the middle, where you can drag the operations that you want to use and specify arguments and options.
|
||||
|
||||
You can use as many operations as you like in simple or complex ways. Some examples are as follows:
|
||||
|
||||
|
@ -58,8 +61,10 @@ You can use as many operations as you like in simple or complex ways. Some examp
|
|||
- [Convert a date and time to a different time zone][3]
|
||||
- [Parse a Teredo IPv6 address][4]
|
||||
- [Convert data from a hexdump, then decompress][5]
|
||||
- [Display multiple timestamps as full dates][6]
|
||||
- [Carry out different operations on data of different types][7]
|
||||
- [Decrypt and disassemble shellcode][6]
|
||||
- [Display multiple timestamps as full dates][7]
|
||||
- [Carry out different operations on data of different types][8]
|
||||
- [Use parts of the input as arguments to operations][9]
|
||||
|
||||
|
||||
## Features
|
||||
|
@ -80,7 +85,7 @@ You can use as many operations as you like in simple or complex ways. Some examp
|
|||
- Search
|
||||
- If you know the name of the operation you want or a word associated with it, start typing it into the search field and any matching operations will immediately be shown.
|
||||
- Highlighting
|
||||
- When you highlight text in the input or output, the offset and length values will be displayed and, if possible, the corresponding data will be highlighted in the output or input respectively (example: [highlight the word 'question' in the input to see where it appears in the output][8]).
|
||||
- When you highlight text in the input or output, the offset and length values will be displayed and, if possible, the corresponding data will be highlighted in the output or input respectively (example: [highlight the word 'question' in the input to see where it appears in the output][10]).
|
||||
- Save to file and load from file
|
||||
- You can save the output to a file at any time or load a file by dragging and dropping it into the input field (note that files larger than about 500kb may cause your browser to hang or even crash due to the way that browsers handle large amounts of textual data).
|
||||
- CyberChef is entirely client-side
|
||||
|
@ -90,12 +95,16 @@ You can use as many operations as you like in simple or complex ways. Some examp
|
|||
|
||||
## Browser support
|
||||
|
||||
CyberChef is built to support Google Chrome 40+, Mozilla Firefox 35+ and Microsoft Edge 14+.
|
||||
CyberChef is built to support
|
||||
|
||||
- Google Chrome 40+
|
||||
- Mozilla Firefox 35+
|
||||
- Microsoft Edge 14+
|
||||
|
||||
|
||||
## Contributing
|
||||
|
||||
An installation walkthrough, how-to guides for adding new operations, descriptions of the repository structure, available data types and coding conventions can all be found in the project [wiki pages](https://github.com/gchq/CyberChef/wiki).
|
||||
An installation walkthrough, how-to guides for adding new operations and themes, descriptions of the repository structure, available data types and coding conventions can all be found in the project [wiki pages](https://github.com/gchq/CyberChef/wiki).
|
||||
|
||||
- Sign the [GCHQ Contributor Licence Agreement](https://github.com/gchq/Gaffer/wiki/GCHQ-OSS-Contributor-License-Agreement-V1.0)
|
||||
- Push your changes to your fork.
|
||||
|
@ -108,10 +117,12 @@ CyberChef is released under the [Apache 2.0 Licence](https://www.apache.org/lice
|
|||
|
||||
|
||||
[1]: https://gchq.github.io/CyberChef
|
||||
[2]: https://gchq.github.io/CyberChef/?recipe=%5B%7B%22op%22%3A%22From%20Base64%22%2C%22args%22%3A%5B%22A-Za-z0-9%2B%2F%3D%22%2Ctrue%5D%7D%5D&input=VTI4Z2JHOXVaeUJoYm1RZ2RHaGhibXR6SUdadmNpQmhiR3dnZEdobElHWnBjMmd1
|
||||
[3]: https://gchq.github.io/CyberChef/?recipe=%5B%7B%22op%22%3A%22Translate%20DateTime%20Format%22%2C%22args%22%3A%5B%22Standard%20date%20and%20time%22%2C%22DD%2FMM%2FYYYY%20HH%3Amm%3Ass%22%2C%22UTC%22%2C%22dddd%20Do%20MMMM%20YYYY%20HH%3Amm%3Ass%20Z%20z%22%2C%22Australia%2FQueensland%22%5D%7D%5D&input=MTUvMDYvMjAxNSAyMDo0NTowMA
|
||||
[4]: https://gchq.github.io/CyberChef/?recipe=%5B%7B%22op%22%3A%22Parse%20IPv6%20address%22%2C%22args%22%3A%5B%5D%7D%5D&input=MjAwMTowMDAwOjQxMzY6ZTM3ODo4MDAwOjYzYmY6M2ZmZjpmZGQy
|
||||
[5]: https://gchq.github.io/CyberChef/?recipe=%5B%7B%22op%22%3A%22From%20Hexdump%22%2C%22args%22%3A%5B%5D%7D%2C%7B%22op%22%3A%22Gunzip%22%2C%22args%22%3A%5B%5D%7D%5D&input=MDAwMDAwMDAgIDFmIDhiIDA4IDAwIDEyIGJjIGYzIDU3IDAwIGZmIDBkIGM3IGMxIDA5IDAwIDIwICB8Li4uLi6881cu%2Fy7HwS4uIHwKMDAwMDAwMTAgIDA4IDA1IGQwIDU1IGZlIDA0IDJkIGQzIDA0IDFmIGNhIDhjIDQ0IDIxIDViIGZmICB8Li7QVf4uLdMuLsouRCFb%2F3wKMDAwMDAwMjAgIDYwIGM3IGQ3IDAzIDE2IGJlIDQwIDFmIDc4IDRhIDNmIDA5IDg5IDBiIDlhIDdkICB8YMfXLi6%2BQC54Sj8uLi4ufXwKMDAwMDAwMzAgIDRlIGM4IDRlIDZkIDA1IDFlIDAxIDhiIDRjIDI0IDAwIDAwIDAwICAgICAgICAgICB8TshObS4uLi5MJC4uLnw
|
||||
[6]: https://gchq.github.io/CyberChef/?recipe=%5B%7B%22op%22%3A%22Fork%22%2C%22args%22%3A%5B%22%5C%5Cn%22%2C%22%5C%5Cn%22%5D%7D%2C%7B%22op%22%3A%22From%20UNIX%20Timestamp%22%2C%22args%22%3A%5B%22Seconds%20(s)%22%5D%7D%5D&input=OTc4MzQ2ODAwCjEwMTI2NTEyMDAKMTA0NjY5NjQwMAoxMDgxMDg3MjAwCjExMTUzMDUyMDAKMTE0OTYwOTYwMA
|
||||
[7]: https://gchq.github.io/CyberChef/?recipe=%5B%7B%22op%22%3A%22Fork%22%2C%22args%22%3A%5B%22%5C%5Cn%22%2C%22%5C%5Cn%22%5D%7D%2C%7B%22op%22%3A%22Conditional%20Jump%22%2C%22args%22%3A%5B%221%22%2C%222%22%2C%2210%22%5D%7D%2C%7B%22op%22%3A%22To%20Hex%22%2C%22args%22%3A%5B%22Space%22%5D%7D%2C%7B%22op%22%3A%22Return%22%2C%22args%22%3A%5B%5D%7D%2C%7B%22op%22%3A%22To%20Base64%22%2C%22args%22%3A%5B%22A-Za-z0-9%2B%2F%3D%22%5D%7D%5D&input=U29tZSBkYXRhIHdpdGggYSAxIGluIGl0ClNvbWUgZGF0YSB3aXRoIGEgMiBpbiBpdA
|
||||
[8]: https://gchq.github.io/CyberChef/?recipe=%5B%7B%22op%22%3A%22XOR%22%2C%22args%22%3A%5B%7B%22option%22%3A%22Hex%22%2C%22string%22%3A%223a%22%7D%2Cfalse%2Cfalse%5D%7D%2C%7B%22op%22%3A%22To%20Hexdump%22%2C%22args%22%3A%5B%2216%22%2Cfalse%2Cfalse%5D%7D%5D&input=VGhlIGFuc3dlciB0byB0aGUgdWx0aW1hdGUgcXVlc3Rpb24gb2YgbGlmZSwgdGhlIFVuaXZlcnNlLCBhbmQgZXZlcnl0aGluZyBpcyA0Mi4
|
||||
[2]: https://gchq.github.io/CyberChef/#recipe=From_Base64('A-Za-z0-9%2B/%3D',true)&input=VTI4Z2JHOXVaeUJoYm1RZ2RHaGhibXR6SUdadmNpQmhiR3dnZEdobElHWnBjMmd1
|
||||
[3]: https://gchq.github.io/CyberChef/#recipe=Translate_DateTime_Format('Standard%20date%20and%20time','DD/MM/YYYY%20HH:mm:ss','UTC','dddd%20Do%20MMMM%20YYYY%20HH:mm:ss%20Z%20z','Australia/Queensland')&input=MTUvMDYvMjAxNSAyMDo0NTowMA
|
||||
[4]: https://gchq.github.io/CyberChef/#recipe=Parse_IPv6_address()&input=MjAwMTowMDAwOjQxMzY6ZTM3ODo4MDAwOjYzYmY6M2ZmZjpmZGQy
|
||||
[5]: https://gchq.github.io/CyberChef/#recipe=From_Hexdump()Gunzip()&input=MDAwMDAwMDAgIDFmIDhiIDA4IDAwIDEyIGJjIGYzIDU3IDAwIGZmIDBkIGM3IGMxIDA5IDAwIDIwICB8Li4uLi6881cu/y7HwS4uIHwKMDAwMDAwMTAgIDA4IDA1IGQwIDU1IGZlIDA0IDJkIGQzIDA0IDFmIGNhIDhjIDQ0IDIxIDViIGZmICB8Li7QVf4uLdMuLsouRCFb/3wKMDAwMDAwMjAgIDYwIGM3IGQ3IDAzIDE2IGJlIDQwIDFmIDc4IDRhIDNmIDA5IDg5IDBiIDlhIDdkICB8YMfXLi6%2BQC54Sj8uLi4ufXwKMDAwMDAwMzAgIDRlIGM4IDRlIDZkIDA1IDFlIDAxIDhiIDRjIDI0IDAwIDAwIDAwICAgICAgICAgICB8TshObS4uLi5MJC4uLnw
|
||||
[6]: https://gchq.github.io/CyberChef/#recipe=RC4(%7B'option':'UTF8','string':'secret'%7D,'Hex','Hex')Disassemble_x86('64','Full%20x86%20architecture',16,0,true,true)&input=MjFkZGQyNTQwMTYwZWU2NWZlMDc3NzEwM2YyYTM5ZmJlNWJjYjZhYTBhYWJkNDE0ZjkwYzZjYWY1MzEyNzU0YWY3NzRiNzZiM2JiY2QxOTNjYjNkZGZkYmM1YTI2NTMzYTY4NmI1OWI4ZmVkNGQzODBkNDc0NDIwMWFlYzIwNDA1MDcxMzhlMmZlMmIzOTUwNDQ2ZGIzMWQyYmM2MjliZTRkM2YyZWIwMDQzYzI5M2Q3YTVkMjk2MmMwMGZlNmRhMzAwNzJkOGM1YTZiNGZlN2Q4NTlhMDQwZWVhZjI5OTczMzYzMDJmNWEwZWMxOQ
|
||||
[7]: https://gchq.github.io/CyberChef/#recipe=Fork('%5C%5Cn','%5C%5Cn',false)From_UNIX_Timestamp('Seconds%20(s)')&input=OTc4MzQ2ODAwCjEwMTI2NTEyMDAKMTA0NjY5NjQwMAoxMDgxMDg3MjAwCjExMTUzMDUyMDAKMTE0OTYwOTYwMA
|
||||
[8]: https://gchq.github.io/CyberChef/#recipe=Fork('%5C%5Cn','%5C%5Cn',false)Conditional_Jump('1',2,10)To_Hex('Space')Return()To_Base64('A-Za-z0-9%2B/%3D')&input=U29tZSBkYXRhIHdpdGggYSAxIGluIGl0ClNvbWUgZGF0YSB3aXRoIGEgMiBpbiBpdA
|
||||
[9]: https://gchq.github.io/CyberChef/#recipe=Register('key%3D(%5B%5C%5Cda-f%5D*)',true,false)Find_/_Replace(%7B'option':'Regex','string':'.*data%3D(.*)'%7D,'$1',true,false,true)RC4(%7B'option':'Hex','string':'$R0'%7D,'Hex','Latin1')&input=aHR0cDovL21hbHdhcmV6LmJpei9iZWFjb24ucGhwP2tleT0wZTkzMmE1YyZkYXRhPThkYjdkNWViZTM4NjYzYTU0ZWNiYjMzNGUzZGIxMQ
|
||||
[10]: https://gchq.github.io/CyberChef/#recipe=XOR(%7B'option':'Hex','string':'3a'%7D,'',false)To_Hexdump(16,false,false)&input=VGhlIGFuc3dlciB0byB0aGUgdWx0aW1hdGUgcXVlc3Rpb24gb2YgbGlmZSwgdGhlIFVuaXZlcnNlLCBhbmQgZXZlcnl0aGluZyBpcyA0Mi4
|
||||
|
|
BIN
docs/favicon.ico
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
|
@ -19,7 +19,7 @@
|
|||
"outputSourcePath": true,
|
||||
"dateFormat": "ddd MMM Do YYYY",
|
||||
"sort": false,
|
||||
"logoFile": "../build/prod/images/cyberchef-32x32.png",
|
||||
"logoFile": "cyberchef-32x32.png",
|
||||
"cleverLinks": false,
|
||||
"monospaceLinks": false,
|
||||
"protocol": "html://",
|
||||
|
|
9246
package-lock.json
generated
Normal file
88
package.json
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "cyberchef",
|
||||
"version": "5.10.1",
|
||||
"version": "6.4.4",
|
||||
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
|
||||
"author": "n1474335 <n1474335@gmail.com>",
|
||||
"homepage": "https://gchq.github.io/CyberChef",
|
||||
|
@ -30,66 +30,76 @@
|
|||
"main": "build/node/CyberChef.js",
|
||||
"bugs": "https://github.com/gchq/CyberChef/issues",
|
||||
"devDependencies": {
|
||||
"babel-core": "^6.24.0",
|
||||
"babel-loader": "^6.4.0",
|
||||
"babel-polyfill": "^6.23.0",
|
||||
"babel-preset-env": "^1.2.2",
|
||||
"css-loader": "^0.27.3",
|
||||
"babel-core": "^6.26.0",
|
||||
"babel-loader": "^7.1.2",
|
||||
"babel-preset-env": "^1.6.0",
|
||||
"css-loader": "^0.28.7",
|
||||
"exports-loader": "^0.6.4",
|
||||
"extract-text-webpack-plugin": "^2.1.0",
|
||||
"file-loader": "^0.10.1",
|
||||
"grunt": ">=0.4.5",
|
||||
"extract-text-webpack-plugin": "^3.0.1",
|
||||
"file-loader": "^1.1.4",
|
||||
"grunt": ">=1.0.1",
|
||||
"grunt-accessibility": "~5.0.0",
|
||||
"grunt-chmod": "~1.1.1",
|
||||
"grunt-contrib-clean": "~1.0.0",
|
||||
"grunt-concurrent": "^2.3.1",
|
||||
"grunt-contrib-clean": "~1.1.0",
|
||||
"grunt-contrib-copy": "~1.0.0",
|
||||
"grunt-eslint": "^19.0.0",
|
||||
"grunt-exec": "~1.0.1",
|
||||
"grunt-eslint": "^20.1.0",
|
||||
"grunt-exec": "~3.0.0",
|
||||
"grunt-execute": "^0.2.2",
|
||||
"grunt-jsdoc": "^2.1.0",
|
||||
"grunt-webpack": "^2.0.1",
|
||||
"html-webpack-plugin": "^2.28.0",
|
||||
"grunt-jsdoc": "^2.2.0",
|
||||
"grunt-webpack": "^3.0.2",
|
||||
"html-webpack-plugin": "^2.30.1",
|
||||
"imports-loader": "^0.7.1",
|
||||
"ink-docstrap": "^1.1.4",
|
||||
"ink-docstrap": "^1.3.0",
|
||||
"jsdoc-babel": "^0.3.0",
|
||||
"less": "^2.7.2",
|
||||
"less-loader": "^4.0.3",
|
||||
"postcss-css-variables": "^0.7.0",
|
||||
"postcss-import": "^10.0.0",
|
||||
"postcss-loader": "^2.0.5",
|
||||
"style-loader": "^0.15.0",
|
||||
"url-loader": "^0.5.8",
|
||||
"web-resource-inliner": "^4.1.0",
|
||||
"webpack": "^2.2.1"
|
||||
"less-loader": "^4.0.5",
|
||||
"postcss-css-variables": "^0.8.0",
|
||||
"postcss-import": "^11.0.0",
|
||||
"postcss-loader": "^2.0.6",
|
||||
"style-loader": "^0.19.0",
|
||||
"url-loader": "^0.6.2",
|
||||
"val-loader": "^1.0.2",
|
||||
"web-resource-inliner": "^4.2.0",
|
||||
"webpack": "^3.6.0",
|
||||
"webpack-dev-server": "^2.9.1",
|
||||
"webpack-node-externals": "^1.6.0",
|
||||
"worker-loader": "^1.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"bootstrap": "^3.3.7",
|
||||
"bootstrap-colorpicker": "^2.5.1",
|
||||
"bootstrap-colorpicker": "^2.5.2",
|
||||
"bootstrap-switch": "^3.3.4",
|
||||
"crypto-api": "^0.6.2",
|
||||
"crypto-api": "^0.7.5",
|
||||
"crypto-js": "^3.1.9-1",
|
||||
"diff": "^3.2.0",
|
||||
"escodegen": "^1.8.1",
|
||||
"diff": "^3.3.1",
|
||||
"escodegen": "^1.9.0",
|
||||
"esmangle": "^1.0.1",
|
||||
"esprima": "^3.1.3",
|
||||
"exif-parser": "^0.1.9",
|
||||
"esprima": "^4.0.0",
|
||||
"exif-parser": "^0.1.12",
|
||||
"google-code-prettify": "^1.0.5",
|
||||
"jquery": "^3.1.1",
|
||||
"jquery": "^3.2.1",
|
||||
"js-crc": "^0.2.0",
|
||||
"js-sha3": "^0.6.1",
|
||||
"jsbn": "^1.1.0",
|
||||
"jsrsasign": "7.1.3",
|
||||
"jsonpath": "^0.2.12",
|
||||
"jsrsasign": "8.0.4",
|
||||
"lodash": "^4.17.4",
|
||||
"moment": "^2.17.1",
|
||||
"moment-timezone": "^0.5.11",
|
||||
"pako": "^1.0.5",
|
||||
"moment": "^2.18.1",
|
||||
"moment-timezone": "^0.5.13",
|
||||
"node-md6": "^0.1.0",
|
||||
"otp": "^0.1.3",
|
||||
"sladex-blowfish": "^0.8.1",
|
||||
"sortablejs": "^1.5.1",
|
||||
"split.js": "^1.2.0",
|
||||
"vkbeautify": "^0.99.1",
|
||||
"sortablejs": "^1.6.1",
|
||||
"split.js": "^1.3.5",
|
||||
"vkbeautify": "^0.99.3",
|
||||
"xmldom": "^0.1.27",
|
||||
"xpath": "0.0.24",
|
||||
"zlibjs": "^0.2.0"
|
||||
"zlibjs": "^0.3.1"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "grunt dev",
|
||||
"build": "grunt prod",
|
||||
"test": "grunt test",
|
||||
"docs": "grunt docs"
|
||||
|
|
|
@ -30,7 +30,6 @@ const Chef = function() {
|
|||
* @returns {string} response.result - The output of the recipe
|
||||
* @returns {string} response.type - The data type of the result
|
||||
* @returns {number} response.progress - The position that we have got to in the recipe
|
||||
* @returns {number} response.options - The app options object (which may have been changed)
|
||||
* @returns {number} response.duration - The number of ms it took to execute the recipe
|
||||
* @returns {number} response.error - The error object thrown by a failed operation (false if no error)
|
||||
*/
|
||||
|
@ -40,12 +39,7 @@ Chef.prototype.bake = async function(inputText, recipeConfig, options, progress,
|
|||
containsFc = recipe.containsFlowControl(),
|
||||
error = false;
|
||||
|
||||
// Reset attemptHighlight flag
|
||||
if (options.hasOwnProperty("attemptHighlight")) {
|
||||
options.attemptHighlight = true;
|
||||
}
|
||||
|
||||
if (containsFc) options.attemptHighlight = false;
|
||||
if (containsFc && ENVIRONMENT_IS_WORKER()) self.setOption("attemptHighlight", false);
|
||||
|
||||
// Clean up progress
|
||||
if (progress >= recipeConfig.length) {
|
||||
|
@ -74,9 +68,10 @@ Chef.prototype.bake = async function(inputText, recipeConfig, options, progress,
|
|||
try {
|
||||
progress = await recipe.execute(this.dish, progress);
|
||||
} catch (err) {
|
||||
// Return the error in the result so that everything else gets correctly updated
|
||||
// rather than throwing it here and losing state info.
|
||||
error = err;
|
||||
console.log(err);
|
||||
error = {
|
||||
displayStr: err.displayStr,
|
||||
};
|
||||
progress = err.progress;
|
||||
}
|
||||
|
||||
|
@ -86,7 +81,6 @@ Chef.prototype.bake = async function(inputText, recipeConfig, options, progress,
|
|||
this.dish.get(Dish.STRING),
|
||||
type: Dish.enumLookup(this.dish.type),
|
||||
progress: progress,
|
||||
options: options,
|
||||
duration: new Date().getTime() - startTime,
|
||||
error: error
|
||||
};
|
||||
|
@ -123,4 +117,38 @@ Chef.prototype.silentBake = function(recipeConfig) {
|
|||
return new Date().getTime() - startTime;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calculates highlight offsets if possible.
|
||||
*
|
||||
* @param {Object[]} recipeConfig
|
||||
* @param {string} direction
|
||||
* @param {Object} pos - The position object for the highlight.
|
||||
* @param {number} pos.start - The start offset.
|
||||
* @param {number} pos.end - The end offset.
|
||||
* @returns {Object}
|
||||
*/
|
||||
Chef.prototype.calculateHighlights = function(recipeConfig, direction, pos) {
|
||||
const recipe = new Recipe(recipeConfig);
|
||||
const highlights = recipe.generateHighlightList();
|
||||
|
||||
if (!highlights) return false;
|
||||
|
||||
for (let i = 0; i < highlights.length; i++) {
|
||||
// Remove multiple highlights before processing again
|
||||
pos = [pos[0]];
|
||||
|
||||
const func = direction === "forward" ? highlights[i].f : highlights[i].b;
|
||||
|
||||
if (typeof func == "function") {
|
||||
pos = func(pos, highlights[i].args);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
pos: pos,
|
||||
direction: direction
|
||||
};
|
||||
};
|
||||
|
||||
export default Chef;
|
||||
|
|
197
src/core/ChefWorker.js
Normal file
|
@ -0,0 +1,197 @@
|
|||
/**
|
||||
* Web Worker to handle communications between the front-end and the core.
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import "babel-polyfill";
|
||||
import Chef from "./Chef.js";
|
||||
import OperationConfig from "./config/MetaConfig.js";
|
||||
import OpModules from "./config/modules/Default.js";
|
||||
|
||||
|
||||
// Set up Chef instance
|
||||
self.chef = new Chef();
|
||||
|
||||
self.OpModules = OpModules;
|
||||
self.OperationConfig = OperationConfig;
|
||||
|
||||
// Tell the app that the worker has loaded and is ready to operate
|
||||
self.postMessage({
|
||||
action: "workerLoaded",
|
||||
data: {}
|
||||
});
|
||||
|
||||
/**
|
||||
* Respond to message from parent thread.
|
||||
*
|
||||
* Messages should have the following format:
|
||||
* {
|
||||
* action: "bake" | "silentBake",
|
||||
* data: {
|
||||
* input: {string},
|
||||
* recipeConfig: {[Object]},
|
||||
* options: {Object},
|
||||
* progress: {number},
|
||||
* step: {boolean}
|
||||
* } | undefined
|
||||
* }
|
||||
*/
|
||||
self.addEventListener("message", function(e) {
|
||||
// Handle message
|
||||
const r = e.data;
|
||||
switch (r.action) {
|
||||
case "bake":
|
||||
bake(r.data);
|
||||
break;
|
||||
case "silentBake":
|
||||
silentBake(r.data);
|
||||
break;
|
||||
case "docURL":
|
||||
// Used to set the URL of the current document so that scripts can be
|
||||
// imported into an inline worker.
|
||||
self.docURL = r.data;
|
||||
break;
|
||||
case "highlight":
|
||||
calculateHighlights(
|
||||
r.data.recipeConfig,
|
||||
r.data.direction,
|
||||
r.data.pos
|
||||
);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Baking handler
|
||||
*
|
||||
* @param {Object} data
|
||||
*/
|
||||
async function bake(data) {
|
||||
// Ensure the relevant modules are loaded
|
||||
loadRequiredModules(data.recipeConfig);
|
||||
|
||||
try {
|
||||
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.progress, // The current position in the recipe
|
||||
data.step // Whether or not to take one step or execute the whole recipe
|
||||
);
|
||||
|
||||
self.postMessage({
|
||||
action: "bakeSuccess",
|
||||
data: response
|
||||
});
|
||||
} catch (err) {
|
||||
self.postMessage({
|
||||
action: "bakeError",
|
||||
data: err
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Silent baking handler
|
||||
*/
|
||||
function silentBake(data) {
|
||||
const duration = self.chef.silentBake(data.recipeConfig);
|
||||
|
||||
self.postMessage({
|
||||
action: "silentBakeComplete",
|
||||
data: duration
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Checks that all required modules are loaded and loads them if not.
|
||||
*
|
||||
* @param {Object} recipeConfig
|
||||
*/
|
||||
function loadRequiredModules(recipeConfig) {
|
||||
recipeConfig.forEach(op => {
|
||||
let module = self.OperationConfig[op.op].module;
|
||||
|
||||
if (!OpModules.hasOwnProperty(module)) {
|
||||
console.log("Loading module " + module);
|
||||
self.sendStatusMessage("Loading module " + module);
|
||||
self.importScripts(self.docURL + "/" + module + ".js");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Calculates highlight offsets if possible.
|
||||
*
|
||||
* @param {Object[]} recipeConfig
|
||||
* @param {string} direction
|
||||
* @param {Object} pos - The position object for the highlight.
|
||||
* @param {number} pos.start - The start offset.
|
||||
* @param {number} pos.end - The end offset.
|
||||
*/
|
||||
function calculateHighlights(recipeConfig, direction, pos) {
|
||||
pos = self.chef.calculateHighlights(recipeConfig, direction, pos);
|
||||
|
||||
self.postMessage({
|
||||
action: "highlightsCalculated",
|
||||
data: pos
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Send status update to the app.
|
||||
*
|
||||
* @param {string} msg
|
||||
*/
|
||||
self.sendStatusMessage = function(msg) {
|
||||
self.postMessage({
|
||||
action: "statusMessage",
|
||||
data: msg
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Send an option value update to the app.
|
||||
*
|
||||
* @param {string} option
|
||||
* @param {*} value
|
||||
*/
|
||||
self.setOption = function(option, value) {
|
||||
self.postMessage({
|
||||
action: "optionUpdate",
|
||||
data: {
|
||||
option: option,
|
||||
value: value
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Send register values back to the app.
|
||||
*
|
||||
* @param {number} opIndex
|
||||
* @param {number} numPrevRegisters
|
||||
* @param {string[]} registers
|
||||
*/
|
||||
self.setRegisters = function(opIndex, numPrevRegisters, registers) {
|
||||
self.postMessage({
|
||||
action: "setRegisters",
|
||||
data: {
|
||||
opIndex: opIndex,
|
||||
numPrevRegisters: numPrevRegisters,
|
||||
registers: registers
|
||||
}
|
||||
});
|
||||
};
|
|
@ -13,22 +13,6 @@ import Dish from "./Dish.js";
|
|||
*/
|
||||
const FlowControl = {
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
FORK_DELIM: "\\n",
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
MERGE_DELIM: "\\n",
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
FORK_IGNORE_ERRORS: false,
|
||||
|
||||
/**
|
||||
* Fork operation.
|
||||
*
|
||||
|
@ -107,15 +91,72 @@ const FlowControl = {
|
|||
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
* Register operation.
|
||||
*
|
||||
* @param {Object} state - The current state of the recipe.
|
||||
* @param {number} state.progress - The current position in the recipe.
|
||||
* @param {Dish} state.dish - The Dish being operated on.
|
||||
* @param {Operation[]} state.opList - The list of operations in the recipe.
|
||||
* @returns {Object} The updated state of the recipe.
|
||||
*/
|
||||
JUMP_NUM: 0,
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
MAX_JUMPS: 10,
|
||||
runRegister: function(state) {
|
||||
const ings = state.opList[state.progress].getIngValues(),
|
||||
extractorStr = ings[0],
|
||||
i = ings[1],
|
||||
m = ings[2];
|
||||
|
||||
let modifiers = "";
|
||||
if (i) modifiers += "i";
|
||||
if (m) modifiers += "m";
|
||||
|
||||
const extractor = new RegExp(extractorStr, modifiers),
|
||||
input = state.dish.get(Dish.STRING),
|
||||
registers = input.match(extractor);
|
||||
|
||||
if (!registers) return state;
|
||||
|
||||
if (ENVIRONMENT_IS_WORKER()) {
|
||||
self.setRegisters(state.progress, state.numRegisters, registers.slice(1));
|
||||
}
|
||||
|
||||
/**
|
||||
* Replaces references to registers (e.g. $R0) with the contents of those registers.
|
||||
*
|
||||
* @param {string} str
|
||||
* @returns {string}
|
||||
*/
|
||||
function replaceRegister(str) {
|
||||
// Replace references to registers ($Rn) with contents of registers
|
||||
return str.replace(/(\\*)\$R(\d{1,2})/g, (match, slashes, regNum) => {
|
||||
const index = parseInt(regNum, 10) + 1;
|
||||
if (index <= state.numRegisters || index >= state.numRegisters + registers.length)
|
||||
return match;
|
||||
if (slashes.length % 2 !== 0) return match.slice(1); // Remove escape
|
||||
return slashes + registers[index - state.numRegisters];
|
||||
});
|
||||
}
|
||||
|
||||
// Step through all subsequent ops and replace registers in args with extracted content
|
||||
for (let i = state.progress + 1; i < state.opList.length; i++) {
|
||||
if (state.opList[i].isDisabled()) continue;
|
||||
|
||||
let args = state.opList[i].getIngValues();
|
||||
args = args.map(arg => {
|
||||
if (typeof arg !== "string" && typeof arg !== "object") return arg;
|
||||
|
||||
if (typeof arg === "object" && arg.hasOwnProperty("string")) {
|
||||
arg.string = replaceRegister(arg.string);
|
||||
return arg;
|
||||
}
|
||||
return replaceRegister(arg);
|
||||
});
|
||||
state.opList[i].setIngValues(args);
|
||||
}
|
||||
|
||||
state.numRegisters += registers.length - 1;
|
||||
return state;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Jump operation.
|
||||
|
|
|
@ -73,7 +73,7 @@ Ingredient.prepare = function(data, type) {
|
|||
case "byteArray":
|
||||
if (typeof data == "string") {
|
||||
data = data.replace(/\s+/g, "");
|
||||
return Utils.hexToByteArray(data);
|
||||
return Utils.fromHex(data);
|
||||
} else {
|
||||
return data;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
import Dish from "./Dish.js";
|
||||
import Ingredient from "./Ingredient.js";
|
||||
import OperationConfig from "./config/MetaConfig.js";
|
||||
import OpModules from "./config/modules/OpModules.js";
|
||||
|
||||
|
||||
/**
|
||||
|
@ -11,10 +13,10 @@ import Ingredient from "./Ingredient.js";
|
|||
*
|
||||
* @class
|
||||
* @param {string} operationName
|
||||
* @param {Object} operationConfig
|
||||
*/
|
||||
const Operation = function(operationName, operationConfig) {
|
||||
const Operation = function(operationName) {
|
||||
this.name = operationName;
|
||||
this.module = "";
|
||||
this.description = "";
|
||||
this.inputType = -1;
|
||||
this.outputType = -1;
|
||||
|
@ -25,8 +27,8 @@ const Operation = function(operationName, operationConfig) {
|
|||
this.disabled = false;
|
||||
this.ingList = [];
|
||||
|
||||
if (operationConfig) {
|
||||
this._parseConfig(operationConfig);
|
||||
if (OperationConfig.hasOwnProperty(this.name)) {
|
||||
this._parseConfig(OperationConfig[this.name]);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -38,19 +40,28 @@ const Operation = function(operationName, operationConfig) {
|
|||
* @param {Object} operationConfig
|
||||
*/
|
||||
Operation.prototype._parseConfig = function(operationConfig) {
|
||||
this.module = operationConfig.module;
|
||||
this.description = operationConfig.description;
|
||||
this.inputType = Dish.typeEnum(operationConfig.inputType);
|
||||
this.outputType = Dish.typeEnum(operationConfig.outputType);
|
||||
this.run = operationConfig.run;
|
||||
this.highlight = operationConfig.highlight;
|
||||
this.highlightReverse = operationConfig.highlightReverse;
|
||||
this.flowControl = operationConfig.flowControl;
|
||||
this.run = OpModules[this.module][this.name];
|
||||
|
||||
for (let a = 0; a < operationConfig.args.length; a++) {
|
||||
const ingredientConfig = operationConfig.args[a];
|
||||
const ingredient = new Ingredient(ingredientConfig);
|
||||
this.addIngredient(ingredient);
|
||||
}
|
||||
|
||||
if (this.highlight === "func") {
|
||||
this.highlight = OpModules[this.module][`${this.name}-highlight`];
|
||||
}
|
||||
|
||||
if (this.highlightReverse === "func") {
|
||||
this.highlightReverse = OpModules[this.module][`${this.name}-highlightReverse`];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import Operation from "./Operation.js";
|
||||
import OperationConfig from "./config/OperationConfig.js";
|
||||
|
||||
|
||||
/**
|
||||
|
@ -30,8 +29,7 @@ const Recipe = function(recipeConfig) {
|
|||
Recipe.prototype._parseConfig = function(recipeConfig) {
|
||||
for (let c = 0; c < recipeConfig.length; c++) {
|
||||
const operationName = recipeConfig[c].op;
|
||||
const operationConfig = OperationConfig[operationName];
|
||||
const operation = new Operation(operationName, operationConfig);
|
||||
const operation = new Operation(operationName);
|
||||
operation.setIngValues(recipeConfig[c].args);
|
||||
operation.setBreakpoint(recipeConfig[c].breakpoint);
|
||||
operation.setDisabled(recipeConfig[c].disabled);
|
||||
|
@ -147,7 +145,7 @@ Recipe.prototype.lastOpIndex = function(startIndex) {
|
|||
*/
|
||||
Recipe.prototype.execute = async function(dish, startFrom) {
|
||||
startFrom = startFrom || 0;
|
||||
let op, input, output, numJumps = 0;
|
||||
let op, input, output, numJumps = 0, numRegisters = 0;
|
||||
|
||||
for (let i = startFrom; i < this.opList.length; i++) {
|
||||
op = this.opList[i];
|
||||
|
@ -164,15 +162,17 @@ Recipe.prototype.execute = async function(dish, startFrom) {
|
|||
if (op.isFlowControl()) {
|
||||
// Package up the current state
|
||||
let state = {
|
||||
"progress" : i,
|
||||
"dish" : dish,
|
||||
"opList" : this.opList,
|
||||
"numJumps" : numJumps
|
||||
"progress": i,
|
||||
"dish": dish,
|
||||
"opList": this.opList,
|
||||
"numJumps": numJumps,
|
||||
"numRegisters": numRegisters
|
||||
};
|
||||
|
||||
state = await op.run(state);
|
||||
i = state.progress;
|
||||
numJumps = state.numJumps;
|
||||
numRegisters = state.numRegisters;
|
||||
} else {
|
||||
output = await op.run(input, op.getIngValues());
|
||||
dish.set(output, op.outputType);
|
||||
|
@ -217,4 +217,37 @@ Recipe.prototype.fromString = function(recipeStr) {
|
|||
this._parseConfig(recipeConfig);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Generates a list of all the highlight functions assigned to operations in the recipe, if the
|
||||
* entire recipe supports highlighting.
|
||||
*
|
||||
* @returns {Object[]} highlights
|
||||
* @returns {function} highlights[].f
|
||||
* @returns {function} highlights[].b
|
||||
* @returns {Object[]} highlights[].args
|
||||
*/
|
||||
Recipe.prototype.generateHighlightList = function() {
|
||||
const highlights = [];
|
||||
|
||||
for (let i = 0; i < this.opList.length; i++) {
|
||||
let op = this.opList[i];
|
||||
if (op.isDisabled()) continue;
|
||||
|
||||
// If any breakpoints are set, do not attempt to highlight
|
||||
if (op.isBreakpoint()) return false;
|
||||
|
||||
// If any of the operations do not support highlighting, fail immediately.
|
||||
if (op.highlight === false || op.highlight === undefined) return false;
|
||||
|
||||
highlights.push({
|
||||
f: op.highlight,
|
||||
b: op.highlightReverse,
|
||||
args: op.getIngValues()
|
||||
});
|
||||
}
|
||||
|
||||
return highlights;
|
||||
};
|
||||
|
||||
export default Recipe;
|
||||
|
|
|
@ -23,6 +23,16 @@ const Utils = {
|
|||
* Utils.chr(97);
|
||||
*/
|
||||
chr: function(o) {
|
||||
// Detect astral symbols
|
||||
// Thanks to @mathiasbynens for this solution
|
||||
// https://mathiasbynens.be/notes/javascript-unicode
|
||||
if (o > 0xffff) {
|
||||
o -= 0x10000;
|
||||
const high = String.fromCharCode(o >>> 10 & 0x3ff | 0xd800);
|
||||
o = 0xdc00 | o & 0x3ff;
|
||||
return high + String.fromCharCode(o);
|
||||
}
|
||||
|
||||
return String.fromCharCode(o);
|
||||
},
|
||||
|
||||
|
@ -38,6 +48,18 @@ const Utils = {
|
|||
* Utils.ord('a');
|
||||
*/
|
||||
ord: function(c) {
|
||||
// Detect astral symbols
|
||||
// Thanks to @mathiasbynens for this solution
|
||||
// https://mathiasbynens.be/notes/javascript-unicode
|
||||
if (c.length === 2) {
|
||||
const high = c.charCodeAt(0);
|
||||
const low = c.charCodeAt(1);
|
||||
if (high >= 0xd800 && high < 0xdc00 &&
|
||||
low >= 0xdc00 && low < 0xe000) {
|
||||
return (high - 0xd800) * 0x400 + low - 0xdc00 + 0x10000;
|
||||
}
|
||||
}
|
||||
|
||||
return c.charCodeAt(0);
|
||||
},
|
||||
|
||||
|
@ -212,11 +234,11 @@ const Utils = {
|
|||
* @returns {string}
|
||||
*/
|
||||
printable: function(str, preserveWs) {
|
||||
if (typeof window !== "undefined" && window.app && !window.app.options.treatAsUtf8) {
|
||||
if (ENVIRONMENT_IS_WEB() && window.app && !window.app.options.treatAsUtf8) {
|
||||
str = Utils.byteArrayToChars(Utils.strToByteArray(str));
|
||||
}
|
||||
|
||||
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-\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\x0D\u2028\u2029]/g;
|
||||
|
||||
str = str.replace(re, ".");
|
||||
|
@ -259,6 +281,22 @@ const Utils = {
|
|||
},
|
||||
|
||||
|
||||
/**
|
||||
* Escape a string containing regex control characters so that it can be safely
|
||||
* used in a regex without causing unintended behaviours.
|
||||
*
|
||||
* @param {string} str
|
||||
* @returns {string}
|
||||
*
|
||||
* @example
|
||||
* // returns "\[example\]"
|
||||
* Utils.escapeRegex("[example]");
|
||||
*/
|
||||
escapeRegex: function(str) {
|
||||
return str.replace(/([.*+?^=!:${}()|[\]/\\])/g, "\\$1");
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Expand an alphabet range string into a list of the characters in that range.
|
||||
*
|
||||
|
@ -408,15 +446,19 @@ const Utils = {
|
|||
let wordArray = CryptoJS.enc.Utf8.parse(str),
|
||||
byteArray = Utils.wordArrayToByteArray(wordArray);
|
||||
|
||||
if (typeof window !== "undefined" && str.length !== wordArray.sigBytes) {
|
||||
window.app.options.attemptHighlight = false;
|
||||
if (str.length !== wordArray.sigBytes) {
|
||||
if (ENVIRONMENT_IS_WORKER()) {
|
||||
self.setOption("attemptHighlight", false);
|
||||
} else if (ENVIRONMENT_IS_WEB()) {
|
||||
window.app.options.attemptHighlight = false;
|
||||
}
|
||||
}
|
||||
return byteArray;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Converts a string to a charcode array
|
||||
* Converts a string to a unicode charcode array
|
||||
*
|
||||
* @param {string} str
|
||||
* @returns {byteArray}
|
||||
|
@ -429,12 +471,23 @@ const Utils = {
|
|||
* Utils.strToCharcode("你好");
|
||||
*/
|
||||
strToCharcode: function(str) {
|
||||
const byteArray = new Array(str.length);
|
||||
let i = str.length;
|
||||
while (i--) {
|
||||
byteArray[i] = str.charCodeAt(i);
|
||||
const charcode = [];
|
||||
|
||||
for (let i = 0; i < str.length; i++) {
|
||||
let ord = str.charCodeAt(i);
|
||||
|
||||
// Detect and merge astral symbols
|
||||
if (i < str.length - 1 && ord >= 0xd800 && ord < 0xdc00) {
|
||||
const low = str[i + 1].charCodeAt(0);
|
||||
if (low >= 0xdc00 && low < 0xe000) {
|
||||
ord = Utils.ord(str[i] + str[++i]);
|
||||
}
|
||||
}
|
||||
|
||||
charcode.push(ord);
|
||||
}
|
||||
return byteArray;
|
||||
|
||||
return charcode;
|
||||
},
|
||||
|
||||
|
||||
|
@ -461,8 +514,13 @@ const Utils = {
|
|||
let wordArray = new CryptoJS.lib.WordArray.init(words, byteArray.length),
|
||||
str = CryptoJS.enc.Utf8.stringify(wordArray);
|
||||
|
||||
if (typeof window !== "undefined" && str.length !== wordArray.sigBytes)
|
||||
window.app.options.attemptHighlight = false;
|
||||
if (str.length !== wordArray.sigBytes) {
|
||||
if (ENVIRONMENT_IS_WORKER()) {
|
||||
self.setOption("attemptHighlight", false);
|
||||
} else if (ENVIRONMENT_IS_WEB()) {
|
||||
window.app.options.attemptHighlight = false;
|
||||
}
|
||||
}
|
||||
return str;
|
||||
} catch (err) {
|
||||
// If it fails, treat it as ANSI
|
||||
|
@ -605,7 +663,7 @@ const Utils = {
|
|||
i = 0;
|
||||
|
||||
if (removeNonAlphChars) {
|
||||
const re = new RegExp("[^" + alphabet.replace(/[\[\]\\\-^$]/g, "\\$&") + "]", "g");
|
||||
const re = new RegExp("[^" + alphabet.replace(/[[\]\\\-^$]/g, "\\$&") + "]", "g");
|
||||
data = data.replace(re, "");
|
||||
}
|
||||
|
||||
|
@ -797,7 +855,7 @@ const Utils = {
|
|||
if (removeScriptAndStyle) {
|
||||
htmlStr = htmlStr.replace(/<(script|style)[^>]*>.*<\/(script|style)>/gmi, "");
|
||||
}
|
||||
return htmlStr.replace(/<[^>\n]+>/g, "");
|
||||
return htmlStr.replace(/<[^>]+>/g, "");
|
||||
},
|
||||
|
||||
|
||||
|
@ -823,7 +881,7 @@ const Utils = {
|
|||
"`": "`"
|
||||
};
|
||||
|
||||
return str.replace(/[&<>"'\/`]/g, function (match) {
|
||||
return str.replace(/[&<>"'/`]/g, function (match) {
|
||||
return HTML_CHARS[match];
|
||||
});
|
||||
},
|
||||
|
@ -856,6 +914,139 @@ const Utils = {
|
|||
},
|
||||
|
||||
|
||||
/**
|
||||
* Encodes a URI fragment (#) or query (?) using a minimal amount of percent-encoding.
|
||||
*
|
||||
* RFC 3986 defines legal characters for the fragment and query parts of a URL to be as follows:
|
||||
*
|
||||
* fragment = *( pchar / "/" / "?" )
|
||||
* query = *( pchar / "/" / "?" )
|
||||
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
|
||||
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
|
||||
* pct-encoded = "%" HEXDIG HEXDIG
|
||||
* sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
|
||||
* / "*" / "+" / "," / ";" / "="
|
||||
*
|
||||
* Meaning that the list of characters that need not be percent-encoded are alphanumeric plus:
|
||||
* -._~!$&'()*+,;=:@/?
|
||||
*
|
||||
* & and = are still escaped as they are used to serialise the key-value pairs in CyberChef
|
||||
* fragments. + is also escaped so as to prevent it being decoded to a space.
|
||||
*
|
||||
* @param {string} str
|
||||
* @returns {string}
|
||||
*/
|
||||
encodeURIFragment: function(str) {
|
||||
const LEGAL_CHARS = {
|
||||
"%2D": "-",
|
||||
"%2E": ".",
|
||||
"%5F": "_",
|
||||
"%7E": "~",
|
||||
"%21": "!",
|
||||
"%24": "$",
|
||||
//"%26": "&",
|
||||
"%27": "'",
|
||||
"%28": "(",
|
||||
"%29": ")",
|
||||
"%2A": "*",
|
||||
//"%2B": "+",
|
||||
"%2C": ",",
|
||||
"%3B": ";",
|
||||
//"%3D": "=",
|
||||
"%3A": ":",
|
||||
"%40": "@",
|
||||
"%2F": "/",
|
||||
"%3F": "?"
|
||||
};
|
||||
str = encodeURIComponent(str);
|
||||
|
||||
return str.replace(/%[0-9A-F]{2}/g, function (match) {
|
||||
return LEGAL_CHARS[match] || match;
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Generates a "pretty" recipe format from a recipeConfig object.
|
||||
*
|
||||
* "Pretty" CyberChef recipe formats are designed to be included in the fragment (#) or query (?)
|
||||
* parts of the URL. They can also be loaded into CyberChef through the 'Load' interface. In order
|
||||
* to make this format as readable as possible, various special characters are used unescaped. This
|
||||
* reduces the amount of percent-encoding included in the URL which is typically difficult to read,
|
||||
* as well as substantially increasing the overall length. These characteristics can be quite
|
||||
* offputting for users.
|
||||
*
|
||||
* @param {Object[]} recipeConfig
|
||||
* @param {boolean} newline - whether to add a newline after each operation
|
||||
* @returns {string}
|
||||
*/
|
||||
generatePrettyRecipe: function(recipeConfig, newline) {
|
||||
let prettyConfig = "",
|
||||
name = "",
|
||||
args = "",
|
||||
disabled = "",
|
||||
bp = "";
|
||||
|
||||
recipeConfig.forEach(op => {
|
||||
name = op.op.replace(/ /g, "_");
|
||||
args = JSON.stringify(op.args)
|
||||
.slice(1, -1) // Remove [ and ] as they are implied
|
||||
// We now need to switch double-quoted (") strings to single-quotes (') as these do not
|
||||
// need to be percent-encoded.
|
||||
.replace(/'/g, "\\'") // Escape single quotes
|
||||
.replace(/\\"/g, '"') // Unescape double quotes
|
||||
.replace(/(^|,|{|:)"/g, "$1'") // Replace opening " with '
|
||||
.replace(/"(,|:|}|$)/g, "'$1"); // Replace closing " with '
|
||||
|
||||
disabled = op.disabled ? "/disabled": "";
|
||||
bp = op.breakpoint ? "/breakpoint" : "";
|
||||
prettyConfig += `${name}(${args}${disabled}${bp})`;
|
||||
if (newline) prettyConfig += "\n";
|
||||
});
|
||||
return prettyConfig;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Converts a recipe string to the JSON representation of the recipe.
|
||||
* Accepts either stringified JSON or bespoke "pretty" recipe format.
|
||||
*
|
||||
* @param {string} recipe
|
||||
* @returns {Object[]}
|
||||
*/
|
||||
parseRecipeConfig: function(recipe) {
|
||||
recipe = recipe.trim();
|
||||
if (recipe.length === 0) return [];
|
||||
if (recipe[0] === "[") return JSON.parse(recipe);
|
||||
|
||||
// Parse bespoke recipe format
|
||||
recipe = recipe.replace(/\n/g, "");
|
||||
let m,
|
||||
recipeRegex = /([^(]+)\(((?:'[^'\\]*(?:\\.[^'\\]*)*'|[^)/])*)(\/[^)]+)?\)/g,
|
||||
recipeConfig = [],
|
||||
args;
|
||||
|
||||
while ((m = recipeRegex.exec(recipe))) {
|
||||
// Translate strings in args back to double-quotes
|
||||
args = m[2]
|
||||
.replace(/"/g, '\\"') // Escape double quotes
|
||||
.replace(/(^|,|{|:)'/g, '$1"') // Replace opening ' with "
|
||||
.replace(/([^\\])'(,|:|}|$)/g, '$1"$2') // Replace closing ' with "
|
||||
.replace(/\\'/g, "'"); // Unescape single quotes
|
||||
args = "[" + args + "]";
|
||||
|
||||
let op = {
|
||||
op: m[1].replace(/_/g, " "),
|
||||
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;
|
||||
recipeConfig.push(op);
|
||||
}
|
||||
return recipeConfig;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Expresses a number of milliseconds in a human readable format.
|
||||
*
|
||||
|
@ -914,17 +1105,20 @@ const Utils = {
|
|||
* @param {Object[]} files
|
||||
* @returns {html}
|
||||
*/
|
||||
displayFilesAsHTML: function(files){
|
||||
displayFilesAsHTML: function(files) {
|
||||
/* <NL> and <SP> used to denote newlines and spaces in HTML markup.
|
||||
* If a non-html operation is used, all markup will be removed but these
|
||||
* whitespace chars will remain for formatting purposes.
|
||||
*/
|
||||
|
||||
const formatDirectory = function(file) {
|
||||
const html = "<div class='panel panel-default'>" +
|
||||
"<div class='panel-heading' role='tab'>" +
|
||||
"<h4 class='panel-title'>" +
|
||||
file.fileName +
|
||||
// The following line is for formatting when HTML is stripped
|
||||
"<span style='display: none'>\n0 bytes\n</span>" +
|
||||
"</h4>" +
|
||||
"</div>" +
|
||||
"</div>";
|
||||
const html = `<div class='panel panel-default' style='white-space: normal;'>
|
||||
<div class='panel-heading' role='tab'>
|
||||
<h4 class='panel-title'>
|
||||
<NL>${Utils.escapeHtml(file.fileName)}
|
||||
</h4>
|
||||
</div>
|
||||
</div>`;
|
||||
return html;
|
||||
};
|
||||
|
||||
|
@ -935,45 +1129,52 @@ const Utils = {
|
|||
);
|
||||
const blobUrl = URL.createObjectURL(blob);
|
||||
|
||||
const downloadAnchorElem = "<a href='" + blobUrl + "' " +
|
||||
"title='Download " + Utils.escapeHtml(file.fileName) + "' " +
|
||||
"download='" + Utils.escapeHtml(file.fileName) + "'>\u21B4</a>";
|
||||
const viewFileElem = `<a href='#collapse${i}'
|
||||
class='collapsed'
|
||||
data-toggle='collapse'
|
||||
aria-expanded='true'
|
||||
aria-controls='collapse${i}'
|
||||
title="Show/hide contents of '${Utils.escapeHtml(file.fileName)}'">👁️</a>`;
|
||||
|
||||
const expandFileContentsElem = "<a href='#collapse" + i + "' " +
|
||||
"class='collapsed' " +
|
||||
"data-toggle='collapse' " +
|
||||
"aria-expanded='true' " +
|
||||
"aria-controls='collapse" + i + "' " +
|
||||
"title=\"Show/hide contents of '" + Utils.escapeHtml(file.fileName) + "'\">🔍</a>";
|
||||
const downloadFileElem = `<a href='${blobUrl}'
|
||||
title='Download ${Utils.escapeHtml(file.fileName)}'
|
||||
download='${Utils.escapeHtml(file.fileName)}'>💾</a>`;
|
||||
|
||||
const html = "<div class='panel panel-default'>" +
|
||||
"<div class='panel-heading' role='tab' id='heading" + i + "'>" +
|
||||
"<h4 class='panel-title'>" +
|
||||
"<div>" +
|
||||
Utils.escapeHtml(file.fileName) +
|
||||
" " + expandFileContentsElem +
|
||||
" " + downloadAnchorElem +
|
||||
"<span class='pull-right'>" +
|
||||
// These are for formatting when stripping HTML
|
||||
"<span style='display: none'>\n</span>" +
|
||||
file.size.toLocaleString() + " bytes" +
|
||||
"<span style='display: none'>\n</span>" +
|
||||
"</span>" +
|
||||
"</div>" +
|
||||
"</h4>" +
|
||||
"</div>" +
|
||||
"<div id='collapse" + i + "' class='panel-collapse collapse' " +
|
||||
"role='tabpanel' aria-labelledby='heading" + i + "'>" +
|
||||
"<div class='panel-body'>" +
|
||||
"<pre><code>" + Utils.escapeHtml(file.contents) + "</pre></code></div>" +
|
||||
"</div>" +
|
||||
"</div>";
|
||||
const hexFileData = Utils.toHexFast(new Uint8Array(file.bytes));
|
||||
|
||||
const switchToInputElem = `<a href='#switchFileToInput${i}'
|
||||
class='file-switch'
|
||||
title='Move file to input as hex'
|
||||
fileValue='${hexFileData}'>⇧</a>`;
|
||||
|
||||
const html = `<div class='panel panel-default' style='white-space: normal;'>
|
||||
<div class='panel-heading' role='tab' id='heading${i}'>
|
||||
<h4 class='panel-title'>
|
||||
<div>
|
||||
${Utils.escapeHtml(file.fileName)}<NL>
|
||||
${viewFileElem}<SP>
|
||||
${downloadFileElem}<SP>
|
||||
${switchToInputElem}<SP>
|
||||
<span class='pull-right'>
|
||||
<NL>${file.size.toLocaleString()} bytes
|
||||
</span>
|
||||
</div>
|
||||
</h4>
|
||||
</div>
|
||||
<div id='collapse${i}' class='panel-collapse collapse'
|
||||
role='tabpanel' aria-labelledby='heading${i}'>
|
||||
<div class='panel-body'>
|
||||
<NL><NL><pre><code>${Utils.escapeHtml(file.contents)}</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>`;
|
||||
return html;
|
||||
};
|
||||
|
||||
let html = "<div style='padding: 5px;'>" +
|
||||
files.length +
|
||||
" file(s) found</div>\n";
|
||||
let html = `<div style='padding: 5px; white-space: normal;'>
|
||||
${files.length} file(s) found<NL>
|
||||
</div>`;
|
||||
|
||||
files.forEach(function(file, i) {
|
||||
if (typeof file.contents !== "undefined") {
|
||||
html += formatFile(file, i);
|
||||
|
@ -981,14 +1182,53 @@ const Utils = {
|
|||
html += formatDirectory(file);
|
||||
}
|
||||
});
|
||||
return html;
|
||||
|
||||
return html.replace(/(?:(<pre>(?:\n|.)*<\/pre>)|\s{2,})/g, "$1") // Remove whitespace from markup
|
||||
.replace(/<NL>/g, "\n") // Replace <NP> with newlines
|
||||
.replace(/<SP>/g, " "); // Replace <SP> with spaces
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Parses URI parameters into a JSON object.
|
||||
*
|
||||
* @param {string} paramStr - The serialised query or hash section of a URI
|
||||
* @returns {object}
|
||||
*
|
||||
* @example
|
||||
* // returns {a: 'abc', b: '123'}
|
||||
* Utils.parseURIParams("?a=abc&b=123")
|
||||
* Utils.parseURIParams("#a=abc&b=123")
|
||||
*/
|
||||
parseURIParams: function(paramStr) {
|
||||
if (paramStr === "") return {};
|
||||
|
||||
// Cut off ? or # and split on &
|
||||
if (paramStr[0] === "?" ||
|
||||
paramStr[0] === "#") {
|
||||
paramStr = paramStr.substr(1);
|
||||
}
|
||||
|
||||
const params = paramStr.split("&");
|
||||
const result = {};
|
||||
|
||||
for (let i = 0; i < params.length; i++) {
|
||||
const param = params[i].split("=");
|
||||
if (param.length !== 2) {
|
||||
result[params[i]] = true;
|
||||
} else {
|
||||
result[param[0]] = decodeURIComponent(param[1].replace(/\+/g, " "));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Actual modulo function, since % is actually the remainder function in JS.
|
||||
*
|
||||
* @author Matt C [matt@artemisbot.pw]
|
||||
* @author Matt C [matt@artemisbot.uk]
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
* @returns {number}
|
||||
|
@ -1001,7 +1241,7 @@ const Utils = {
|
|||
/**
|
||||
* Finds the greatest common divisor of two numbers.
|
||||
*
|
||||
* @author Matt C [matt@artemisbot.pw]
|
||||
* @author Matt C [matt@artemisbot.uk]
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
* @returns {number}
|
||||
|
@ -1017,7 +1257,7 @@ const Utils = {
|
|||
/**
|
||||
* Finds the modular inverse of two values.
|
||||
*
|
||||
* @author Matt C [matt@artemisbot.pw]
|
||||
* @author Matt C [matt@artemisbot.uk]
|
||||
* @param {number} x
|
||||
* @param {number} y
|
||||
* @returns {number}
|
||||
|
@ -1066,7 +1306,8 @@ const Utils = {
|
|||
"Forward slash": /\//g,
|
||||
"Backslash": /\\/g,
|
||||
"0x": /0x/g,
|
||||
"\\x": /\\x/g
|
||||
"\\x": /\\x/g,
|
||||
"None": /\s+/g // Included here to remove whitespace when there shouldn't be any
|
||||
},
|
||||
|
||||
|
||||
|
|
|
@ -49,6 +49,8 @@ const Categories = [
|
|||
"From Base58",
|
||||
"To Base",
|
||||
"From Base",
|
||||
"To BCD",
|
||||
"From BCD",
|
||||
"To HTML Entity",
|
||||
"From HTML Entity",
|
||||
"URL Encode",
|
||||
|
@ -92,6 +94,8 @@ const Categories = [
|
|||
"Vigenère Decode",
|
||||
"To Morse Code",
|
||||
"From Morse Code",
|
||||
"Bifid Cipher Encode",
|
||||
"Bifid Cipher Decode",
|
||||
"Affine Cipher Encode",
|
||||
"Affine Cipher Decode",
|
||||
"Atbash Cipher",
|
||||
|
@ -121,6 +125,8 @@ const Categories = [
|
|||
"AND",
|
||||
"ADD",
|
||||
"SUB",
|
||||
"Bit shift left",
|
||||
"Bit shift right",
|
||||
"Rotate left",
|
||||
"Rotate right",
|
||||
"ROT13",
|
||||
|
@ -173,7 +179,6 @@ const Categories = [
|
|||
"Tail",
|
||||
"Count occurrences",
|
||||
"Expand alphabet range",
|
||||
"Parse escaped string",
|
||||
"Drop bytes",
|
||||
"Take bytes",
|
||||
"Pad lines",
|
||||
|
@ -188,6 +193,8 @@ const Categories = [
|
|||
"Parse UNIX file permissions",
|
||||
"Swap endianness",
|
||||
"Parse colour code",
|
||||
"Escape string",
|
||||
"Unescape string",
|
||||
]
|
||||
},
|
||||
{
|
||||
|
@ -215,6 +222,7 @@ const Categories = [
|
|||
"Extract dates",
|
||||
"Regular expression",
|
||||
"XPath expression",
|
||||
"JPath expression",
|
||||
"CSS selector",
|
||||
"Extract EXIF",
|
||||
]
|
||||
|
@ -243,20 +251,24 @@ const Categories = [
|
|||
"MD2",
|
||||
"MD4",
|
||||
"MD5",
|
||||
"MD6",
|
||||
"SHA0",
|
||||
"SHA1",
|
||||
"SHA224",
|
||||
"SHA256",
|
||||
"SHA384",
|
||||
"SHA512",
|
||||
"SHA2",
|
||||
"SHA3",
|
||||
"RIPEMD-160",
|
||||
"Keccak",
|
||||
"Shake",
|
||||
"RIPEMD",
|
||||
"HAS-160",
|
||||
"Whirlpool",
|
||||
"Snefru",
|
||||
"HMAC",
|
||||
"Fletcher-8 Checksum",
|
||||
"Fletcher-16 Checksum",
|
||||
"Fletcher-32 Checksum",
|
||||
"Fletcher-64 Checksum",
|
||||
"Adler-32 Checksum",
|
||||
"CRC-16 Checksum",
|
||||
"CRC-32 Checksum",
|
||||
"TCP/IP Checksum",
|
||||
]
|
||||
|
@ -278,7 +290,9 @@ const Categories = [
|
|||
"CSS Beautify",
|
||||
"CSS Minify",
|
||||
"XPath expression",
|
||||
"JPath expression",
|
||||
"CSS selector",
|
||||
"Microsoft Script Decoder",
|
||||
"Strip HTML tags",
|
||||
"Diff",
|
||||
"To Snake case",
|
||||
|
@ -293,7 +307,10 @@ const Categories = [
|
|||
"Frequency distribution",
|
||||
"Detect File Type",
|
||||
"Scan for Embedded Files",
|
||||
"Disassemble x86",
|
||||
"Generate UUID",
|
||||
"Generate TOTP",
|
||||
"Generate HOTP",
|
||||
"Render Image",
|
||||
"Remove EXIF",
|
||||
"Extract EXIF",
|
||||
|
@ -305,6 +322,7 @@ const Categories = [
|
|||
ops: [
|
||||
"Fork",
|
||||
"Merge",
|
||||
"Register",
|
||||
"Jump",
|
||||
"Conditional Jump",
|
||||
"Return",
|
||||
|
|
22
src/core/config/modules/CharEnc.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
import CharEnc from "../../operations/CharEnc.js";
|
||||
|
||||
|
||||
/**
|
||||
* CharEnc module.
|
||||
*
|
||||
* Libraries:
|
||||
* - cptable
|
||||
* - CryptoJS
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
let OpModules = typeof self === "undefined" ? {} : self.OpModules || {};
|
||||
|
||||
OpModules.CharEnc = {
|
||||
"Encode text": CharEnc.runEncode,
|
||||
"Decode text": CharEnc.runDecode,
|
||||
};
|
||||
|
||||
export default OpModules;
|
42
src/core/config/modules/Ciphers.js
Normal file
|
@ -0,0 +1,42 @@
|
|||
import Cipher from "../../operations/Cipher.js";
|
||||
|
||||
|
||||
/**
|
||||
* Ciphers module.
|
||||
*
|
||||
* Libraries:
|
||||
* - CryptoJS
|
||||
* - Blowfish
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
let OpModules = typeof self === "undefined" ? {} : self.OpModules || {};
|
||||
|
||||
OpModules.Ciphers = {
|
||||
"AES Encrypt": Cipher.runAesEnc,
|
||||
"AES Decrypt": Cipher.runAesDec,
|
||||
"Blowfish Encrypt": Cipher.runBlowfishEnc,
|
||||
"Blowfish Decrypt": Cipher.runBlowfishDec,
|
||||
"DES Encrypt": Cipher.runDesEnc,
|
||||
"DES Decrypt": Cipher.runDesDec,
|
||||
"Triple DES Encrypt": Cipher.runTripleDesEnc,
|
||||
"Triple DES Decrypt": Cipher.runTripleDesDec,
|
||||
"Rabbit Encrypt": Cipher.runRabbitEnc,
|
||||
"Rabbit Decrypt": Cipher.runRabbitDec,
|
||||
"Derive PBKDF2 key": Cipher.runPbkdf2,
|
||||
"Derive EVP key": Cipher.runEvpkdf,
|
||||
"RC4": Cipher.runRc4,
|
||||
"RC4 Drop": Cipher.runRc4drop,
|
||||
"Vigenère Encode": Cipher.runVigenereEnc,
|
||||
"Vigenère Decode": Cipher.runVigenereDec,
|
||||
"Bifid Cipher Encode": Cipher.runBifidEnc,
|
||||
"Bifid Cipher Decode": Cipher.runBifidDec,
|
||||
"Affine Cipher Encode": Cipher.runAffineEnc,
|
||||
"Affine Cipher Decode": Cipher.runAffineDec,
|
||||
"Atbash Cipher": Cipher.runAtbash,
|
||||
"Substitute": Cipher.runSubstitute,
|
||||
};
|
||||
|
||||
export default OpModules;
|
44
src/core/config/modules/Code.js
Normal file
|
@ -0,0 +1,44 @@
|
|||
import JS from "../../operations/JS.js";
|
||||
import Code from "../../operations/Code.js";
|
||||
|
||||
|
||||
/**
|
||||
* Code module.
|
||||
*
|
||||
* Libraries:
|
||||
* - lodash
|
||||
* - vkbeautify
|
||||
* - xmldom
|
||||
* - xpath
|
||||
* - jpath
|
||||
* - googlecodeprettify
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
let OpModules = typeof self === "undefined" ? {} : self.OpModules || {};
|
||||
|
||||
OpModules.Code = {
|
||||
"JavaScript Parser": JS.runParse,
|
||||
"JavaScript Beautify": JS.runBeautify,
|
||||
"JavaScript Minify": JS.runMinify,
|
||||
"Syntax highlighter": Code.runSyntaxHighlight,
|
||||
"Generic Code Beautify": Code.runGenericBeautify,
|
||||
"JSON Beautify": Code.runJsonBeautify,
|
||||
"JSON Minify": Code.runJsonMinify,
|
||||
"XML Beautify": Code.runXmlBeautify,
|
||||
"XML Minify": Code.runXmlMinify,
|
||||
"SQL Beautify": Code.runSqlBeautify,
|
||||
"SQL Minify": Code.runSqlMinify,
|
||||
"CSS Beautify": Code.runCssBeautify,
|
||||
"CSS Minify": Code.runCssMinify,
|
||||
"XPath expression": Code.runXpath,
|
||||
"CSS selector": Code.runCSSQuery,
|
||||
"To Snake case": Code.runToSnakeCase,
|
||||
"To Camel case": Code.runToCamelCase,
|
||||
"To Kebab case": Code.runToKebabCase,
|
||||
"JPath expression": Code.runJpath,
|
||||
};
|
||||
|
||||
export default OpModules;
|
32
src/core/config/modules/Compression.js
Normal file
|
@ -0,0 +1,32 @@
|
|||
import Compress from "../../operations/Compress.js";
|
||||
|
||||
|
||||
/**
|
||||
* Compression module.
|
||||
*
|
||||
* Libraries:
|
||||
* - zlib.js
|
||||
* - bzip2.js
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
let OpModules = typeof self === "undefined" ? {} : self.OpModules || {};
|
||||
|
||||
OpModules.Compression = {
|
||||
"Raw Deflate": Compress.runRawDeflate,
|
||||
"Raw Inflate": Compress.runRawInflate,
|
||||
"Zlib Deflate": Compress.runZlibDeflate,
|
||||
"Zlib Inflate": Compress.runZlibInflate,
|
||||
"Gzip": Compress.runGzip,
|
||||
"Gunzip": Compress.runGunzip,
|
||||
"Zip": Compress.runPkzip,
|
||||
"Unzip": Compress.runPkunzip,
|
||||
"Bzip2 Decompress": Compress.runBzip2Decompress,
|
||||
"Tar": Compress.runTar,
|
||||
"Untar": Compress.runUntar,
|
||||
|
||||
};
|
||||
|
||||
export default OpModules;
|
188
src/core/config/modules/Default.js
Normal file
|
@ -0,0 +1,188 @@
|
|||
import FlowControl from "../../FlowControl.js";
|
||||
import Base from "../../operations/Base.js";
|
||||
import Base58 from "../../operations/Base58.js";
|
||||
import Base64 from "../../operations/Base64.js";
|
||||
import BCD from "../../operations/BCD.js";
|
||||
import BitwiseOp from "../../operations/BitwiseOp.js";
|
||||
import ByteRepr from "../../operations/ByteRepr.js";
|
||||
import Convert from "../../operations/Convert.js";
|
||||
import DateTime from "../../operations/DateTime.js";
|
||||
import Endian from "../../operations/Endian.js";
|
||||
import Entropy from "../../operations/Entropy.js";
|
||||
import Extract from "../../operations/Extract.js";
|
||||
import FileType from "../../operations/FileType.js";
|
||||
import Hexdump from "../../operations/Hexdump.js";
|
||||
import HTML from "../../operations/HTML.js";
|
||||
import MAC from "../../operations/MAC.js";
|
||||
import MorseCode from "../../operations/MorseCode.js";
|
||||
import MS from "../../operations/MS.js";
|
||||
import NetBIOS from "../../operations/NetBIOS.js";
|
||||
import Numberwang from "../../operations/Numberwang.js";
|
||||
import OS from "../../operations/OS.js";
|
||||
import OTP from "../../operations/OTP.js";
|
||||
import QuotedPrintable from "../../operations/QuotedPrintable.js";
|
||||
import Rotate from "../../operations/Rotate.js";
|
||||
import SeqUtils from "../../operations/SeqUtils.js";
|
||||
import StrUtils from "../../operations/StrUtils.js";
|
||||
import Tidy from "../../operations/Tidy.js";
|
||||
import Unicode from "../../operations/Unicode.js";
|
||||
import UUID from "../../operations/UUID.js";
|
||||
|
||||
|
||||
/**
|
||||
* Default module.
|
||||
*
|
||||
* The Default module is for operations that are expected to be very commonly used or
|
||||
* do not require any libraries. This module is loaded into the app at compile time.
|
||||
*
|
||||
* Libraries:
|
||||
* - Utils.js
|
||||
* - CryptoJS
|
||||
* - otp
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
let OpModules = typeof self === "undefined" ? {} : self.OpModules || {};
|
||||
|
||||
OpModules.Default = {
|
||||
"To Hexdump": Hexdump.runTo,
|
||||
"From Hexdump": Hexdump.runFrom,
|
||||
"To Hex": ByteRepr.runToHex,
|
||||
"From Hex": ByteRepr.runFromHex,
|
||||
"To Octal": ByteRepr.runToOct,
|
||||
"From Octal": ByteRepr.runFromOct,
|
||||
"To Charcode": ByteRepr.runToCharcode,
|
||||
"From Charcode": ByteRepr.runFromCharcode,
|
||||
"To Decimal": ByteRepr.runToDecimal,
|
||||
"From Decimal": ByteRepr.runFromDecimal,
|
||||
"To Binary": ByteRepr.runToBinary,
|
||||
"From Binary": ByteRepr.runFromBinary,
|
||||
"To Hex Content": ByteRepr.runToHexContent,
|
||||
"From Hex Content": ByteRepr.runFromHexContent,
|
||||
"To Base64": Base64.runTo,
|
||||
"From Base64": Base64.runFrom,
|
||||
"Show Base64 offsets": Base64.runOffsets,
|
||||
"To Base32": Base64.runTo32,
|
||||
"From Base32": Base64.runFrom32,
|
||||
"To Base58": Base58.runTo,
|
||||
"From Base58": Base58.runFrom,
|
||||
"To Base": Base.runTo,
|
||||
"From Base": Base.runFrom,
|
||||
"To BCD": BCD.runToBCD,
|
||||
"From BCD": BCD.runFromBCD,
|
||||
"To HTML Entity": HTML.runToEntity,
|
||||
"From HTML Entity": HTML.runFromEntity,
|
||||
"Strip HTML tags": HTML.runStripTags,
|
||||
"Parse colour code": HTML.runParseColourCode,
|
||||
"Unescape Unicode Characters": Unicode.runUnescape,
|
||||
"To Quoted Printable": QuotedPrintable.runTo,
|
||||
"From Quoted Printable": QuotedPrintable.runFrom,
|
||||
"Swap endianness": Endian.runSwapEndianness,
|
||||
"ROT13": Rotate.runRot13,
|
||||
"ROT47": Rotate.runRot47,
|
||||
"Rotate left": Rotate.runRotl,
|
||||
"Rotate right": Rotate.runRotr,
|
||||
"Bit shift left": BitwiseOp.runBitShiftLeft,
|
||||
"Bit shift right": BitwiseOp.runBitShiftRight,
|
||||
"XOR": BitwiseOp.runXor,
|
||||
"XOR Brute Force": BitwiseOp.runXorBrute,
|
||||
"OR": BitwiseOp.runXor,
|
||||
"NOT": BitwiseOp.runNot,
|
||||
"AND": BitwiseOp.runAnd,
|
||||
"ADD": BitwiseOp.runAdd,
|
||||
"SUB": BitwiseOp.runSub,
|
||||
"To Morse Code": MorseCode.runTo,
|
||||
"From Morse Code": MorseCode.runFrom,
|
||||
"Format MAC addresses": MAC.runFormat,
|
||||
"Encode NetBIOS Name": NetBIOS.runEncodeName,
|
||||
"Decode NetBIOS Name": NetBIOS.runDecodeName,
|
||||
"Regular expression": StrUtils.runRegex,
|
||||
"Offset checker": StrUtils.runOffsetChecker,
|
||||
"To Upper case": StrUtils.runUpper,
|
||||
"To Lower case": StrUtils.runLower,
|
||||
"Find / Replace": StrUtils.runFindReplace,
|
||||
"Split": StrUtils.runSplit,
|
||||
"Filter": StrUtils.runFilter,
|
||||
"Escape string": StrUtils.runEscape,
|
||||
"Unescape string": StrUtils.runUnescape,
|
||||
"Head": StrUtils.runHead,
|
||||
"Tail": StrUtils.runTail,
|
||||
"Remove whitespace": Tidy.runRemoveWhitespace,
|
||||
"Remove null bytes": Tidy.runRemoveNulls,
|
||||
"Drop bytes": Tidy.runDropBytes,
|
||||
"Take bytes": Tidy.runTakeBytes,
|
||||
"Pad lines": Tidy.runPad,
|
||||
"Reverse": SeqUtils.runReverse,
|
||||
"Sort": SeqUtils.runSort,
|
||||
"Unique": SeqUtils.runUnique,
|
||||
"Count occurrences": SeqUtils.runCount,
|
||||
"Add line numbers": SeqUtils.runAddLineNumbers,
|
||||
"Remove line numbers": SeqUtils.runRemoveLineNumbers,
|
||||
"Expand alphabet range": SeqUtils.runExpandAlphRange,
|
||||
"Convert distance": Convert.runDistance,
|
||||
"Convert area": Convert.runArea,
|
||||
"Convert mass": Convert.runMass,
|
||||
"Convert speed": Convert.runSpeed,
|
||||
"Convert data units": Convert.runDataSize,
|
||||
"Parse UNIX file permissions": OS.runParseUnixPerms,
|
||||
"Parse DateTime": DateTime.runParse,
|
||||
"Translate DateTime Format": DateTime.runTranslateFormat,
|
||||
"From UNIX Timestamp": DateTime.runFromUnixTimestamp,
|
||||
"To UNIX Timestamp": DateTime.runToUnixTimestamp,
|
||||
"Strings": Extract.runStrings,
|
||||
"Extract IP addresses": Extract.runIp,
|
||||
"Extract email addresses": Extract.runEmail,
|
||||
"Extract MAC addresses": Extract.runMac,
|
||||
"Extract URLs": Extract.runUrls,
|
||||
"Extract domains": Extract.runDomains,
|
||||
"Extract file paths": Extract.runFilePaths,
|
||||
"Extract dates": Extract.runDates,
|
||||
"Microsoft Script Decoder": MS.runDecodeScript,
|
||||
"Entropy": Entropy.runEntropy,
|
||||
"Frequency distribution": Entropy.runFreqDistrib,
|
||||
"Detect File Type": FileType.runDetect,
|
||||
"Scan for Embedded Files": FileType.runScanForEmbeddedFiles,
|
||||
"Generate UUID": UUID.runGenerateV4,
|
||||
"Numberwang": Numberwang.run,
|
||||
"Generate TOTP": OTP.runTOTP,
|
||||
"Generate HOTP": OTP.runHOTP,
|
||||
"Fork": FlowControl.runFork,
|
||||
"Merge": FlowControl.runMerge,
|
||||
"Register": FlowControl.runRegister,
|
||||
"Jump": FlowControl.runJump,
|
||||
"Conditional Jump": FlowControl.runCondJump,
|
||||
"Return": FlowControl.runReturn,
|
||||
"Comment": FlowControl.runComment,
|
||||
|
||||
|
||||
/*
|
||||
Highlighting functions.
|
||||
|
||||
This is a temporary solution as highlighting should be entirely
|
||||
overhauled at some point.
|
||||
*/
|
||||
"From Base64-highlight": Base64.highlightFrom,
|
||||
"From Base64-highlightReverse": Base64.highlightTo,
|
||||
"To Base64-highlight": Base64.highlightTo,
|
||||
"To Base64-highlightReverse": Base64.highlightFrom,
|
||||
"From Hex-highlight": ByteRepr.highlightFrom,
|
||||
"From Hex-highlightReverse": ByteRepr.highlightTo,
|
||||
"To Hex-highlight": ByteRepr.highlightTo,
|
||||
"To Hex-highlightReverse": ByteRepr.highlightFrom,
|
||||
"From Charcode-highlight": ByteRepr.highlightFrom,
|
||||
"From Charcode-highlightReverse": ByteRepr.highlightTo,
|
||||
"To Charcode-highlight": ByteRepr.highlightTo,
|
||||
"To Charcode-highlightReverse": ByteRepr.highlightFrom,
|
||||
"From Binary-highlight": ByteRepr.highlightFromBinary,
|
||||
"From Binary-highlightReverse": ByteRepr.highlightToBinary,
|
||||
"To Binary-highlight": ByteRepr.highlightToBinary,
|
||||
"To Binary-highlightReverse": ByteRepr.highlightFromBinary,
|
||||
"From Hexdump-highlight": Hexdump.highlightFrom,
|
||||
"From Hexdump-highlightReverse": Hexdump.highlightTo,
|
||||
"To Hexdump-highlight": Hexdump.highlightTo,
|
||||
"To Hexdump-highlightReverse": Hexdump.highlightFrom,
|
||||
};
|
||||
|
||||
export default OpModules;
|
20
src/core/config/modules/Diff.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
import Diff from "../../operations/Diff.js";
|
||||
|
||||
|
||||
/**
|
||||
* Diff module.
|
||||
*
|
||||
* Libraries:
|
||||
* - JsDIff
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
let OpModules = typeof self === "undefined" ? {} : self.OpModules || {};
|
||||
|
||||
OpModules.Diff = {
|
||||
"Diff": Diff.runDiff,
|
||||
};
|
||||
|
||||
export default OpModules;
|
21
src/core/config/modules/Encodings.js
Normal file
|
@ -0,0 +1,21 @@
|
|||
import Punycode from "../../operations/Punycode.js";
|
||||
|
||||
|
||||
/**
|
||||
* Encodings module.
|
||||
*
|
||||
* Libraries:
|
||||
* - punycode
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
let OpModules = typeof self === "undefined" ? {} : self.OpModules || {};
|
||||
|
||||
OpModules.Encodings = {
|
||||
"To Punycode": Punycode.runToAscii,
|
||||
"From Punycode": Punycode.runToUnicode,
|
||||
};
|
||||
|
||||
export default OpModules;
|
22
src/core/config/modules/HTTP.js
Normal file
|
@ -0,0 +1,22 @@
|
|||
import HTTP from "../../operations/HTTP.js";
|
||||
|
||||
|
||||
/**
|
||||
* HTTP module.
|
||||
*
|
||||
* Libraries:
|
||||
* - UAS_parser
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
let OpModules = typeof self === "undefined" ? {} : self.OpModules || {};
|
||||
|
||||
OpModules.HTTP = {
|
||||
"HTTP request": HTTP.runHTTPRequest,
|
||||
"Strip HTTP headers": HTTP.runStripHeaders,
|
||||
"Parse User Agent": HTTP.runParseUserAgent,
|
||||
};
|
||||
|
||||
export default OpModules;
|
48
src/core/config/modules/Hashing.js
Normal file
|
@ -0,0 +1,48 @@
|
|||
import Checksum from "../../operations/Checksum.js";
|
||||
import Hash from "../../operations/Hash.js";
|
||||
|
||||
|
||||
/**
|
||||
* Hashing module.
|
||||
*
|
||||
* Libraries:
|
||||
* - CryptoApi
|
||||
* - node-md6
|
||||
* - js-sha3
|
||||
* - ./Checksum.js
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
let OpModules = typeof self === "undefined" ? {} : self.OpModules || {};
|
||||
|
||||
OpModules.Hashing = {
|
||||
"Analyse hash": Hash.runAnalyse,
|
||||
"Generate all hashes": Hash.runAll,
|
||||
"MD2": Hash.runMD2,
|
||||
"MD4": Hash.runMD4,
|
||||
"MD5": Hash.runMD5,
|
||||
"MD6": Hash.runMD6,
|
||||
"SHA0": Hash.runSHA0,
|
||||
"SHA1": Hash.runSHA1,
|
||||
"SHA2": Hash.runSHA2,
|
||||
"SHA3": Hash.runSHA3,
|
||||
"Keccak": Hash.runKeccak,
|
||||
"Shake": Hash.runShake,
|
||||
"RIPEMD": Hash.runRIPEMD,
|
||||
"HAS-160": Hash.runHAS,
|
||||
"Whirlpool": Hash.runWhirlpool,
|
||||
"Snefru": Hash.runSnefru,
|
||||
"HMAC": Hash.runHMAC,
|
||||
"Fletcher-8 Checksum": Checksum.runFletcher8,
|
||||
"Fletcher-16 Checksum": Checksum.runFletcher16,
|
||||
"Fletcher-32 Checksum": Checksum.runFletcher32,
|
||||
"Fletcher-64 Checksum": Checksum.runFletcher64,
|
||||
"Adler-32 Checksum": Checksum.runAdler32,
|
||||
"CRC-16 Checksum": Checksum.runCRC16,
|
||||
"CRC-32 Checksum": Checksum.runCRC32,
|
||||
"TCP/IP Checksum": Checksum.runTCPIP,
|
||||
};
|
||||
|
||||
export default OpModules;
|
25
src/core/config/modules/Image.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
import Image from "../../operations/Image.js";
|
||||
|
||||
|
||||
/**
|
||||
* Image module.
|
||||
*
|
||||
* Libraries:
|
||||
* - exif-parser
|
||||
* - remove-exif
|
||||
* - ./FileType.js
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
let OpModules = typeof self === "undefined" ? {} : self.OpModules || {};
|
||||
|
||||
OpModules.Image = {
|
||||
"Extract EXIF": Image.runExtractEXIF,
|
||||
"Remove EXIF": Image.runRemoveEXIF,
|
||||
"Render Image": Image.runRenderImage,
|
||||
|
||||
};
|
||||
|
||||
export default OpModules;
|
28
src/core/config/modules/JSBN.js
Normal file
|
@ -0,0 +1,28 @@
|
|||
import IP from "../../operations/IP.js";
|
||||
import Filetime from "../../operations/Filetime.js";
|
||||
|
||||
|
||||
/**
|
||||
* JSBN module.
|
||||
*
|
||||
* Libraries:
|
||||
* - jsbn
|
||||
* - ./Checksum.js
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
let OpModules = typeof self === "undefined" ? {} : self.OpModules || {};
|
||||
|
||||
OpModules.JSBN = {
|
||||
"Parse IP range": IP.runParseIpRange,
|
||||
"Parse IPv6 address": IP.runParseIPv6,
|
||||
"Parse IPv4 header": IP.runParseIPv4Header,
|
||||
"Change IP format": IP.runChangeIpFormat,
|
||||
"Group IP addresses": IP.runGroupIps,
|
||||
"Windows Filetime to UNIX Timestamp": Filetime.runFromFiletimeToUnix,
|
||||
"UNIX Timestamp to Windows Filetime": Filetime.runToFiletimeFromUnix,
|
||||
};
|
||||
|
||||
export default OpModules;
|
41
src/core/config/modules/OpModules.js
Normal file
|
@ -0,0 +1,41 @@
|
|||
/**
|
||||
* Imports all modules for builds which do not load modules separately.
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import OpModules from "./Default.js";
|
||||
import CharEncModule from "./CharEnc.js";
|
||||
import CipherModule from "./Ciphers.js";
|
||||
import CodeModule from "./Code.js";
|
||||
import CompressionModule from "./Compression.js";
|
||||
import DiffModule from "./Diff.js";
|
||||
import EncodingModule from "./Encodings.js";
|
||||
import HashingModule from "./Hashing.js";
|
||||
import HTTPModule from "./HTTP.js";
|
||||
import ImageModule from "./Image.js";
|
||||
import JSBNModule from "./JSBN.js";
|
||||
import PublicKeyModule from "./PublicKey.js";
|
||||
import ShellcodeModule from "./Shellcode.js";
|
||||
import URLModule from "./URL.js";
|
||||
|
||||
Object.assign(
|
||||
OpModules,
|
||||
CharEncModule,
|
||||
CipherModule,
|
||||
CodeModule,
|
||||
CompressionModule,
|
||||
DiffModule,
|
||||
EncodingModule,
|
||||
HashingModule,
|
||||
HTTPModule,
|
||||
ImageModule,
|
||||
JSBNModule,
|
||||
PublicKeyModule,
|
||||
ShellcodeModule,
|
||||
URLModule
|
||||
);
|
||||
|
||||
export default OpModules;
|
25
src/core/config/modules/PublicKey.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
import PublicKey from "../../operations/PublicKey.js";
|
||||
|
||||
|
||||
/**
|
||||
* PublicKey module.
|
||||
*
|
||||
* Libraries:
|
||||
* - jsrsasign
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
let OpModules = typeof self === "undefined" ? {} : self.OpModules || {};
|
||||
|
||||
OpModules.PublicKey = {
|
||||
"Parse X.509 certificate": PublicKey.runParseX509,
|
||||
"Parse ASN.1 hex string": PublicKey.runParseAsn1HexString,
|
||||
"PEM to Hex": PublicKey.runPemToHex,
|
||||
"Hex to PEM": PublicKey.runHexToPem,
|
||||
"Hex to Object Identifier": PublicKey.runHexToObjectIdentifier,
|
||||
"Object Identifier to Hex": PublicKey.runObjectIdentifierToHex,
|
||||
};
|
||||
|
||||
export default OpModules;
|
20
src/core/config/modules/Shellcode.js
Normal file
|
@ -0,0 +1,20 @@
|
|||
import Shellcode from "../../operations/Shellcode.js";
|
||||
|
||||
|
||||
/**
|
||||
* Shellcode module.
|
||||
*
|
||||
* Libraries:
|
||||
* - DisassembleX86-64.js
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
let OpModules = typeof self === "undefined" ? {} : self.OpModules || {};
|
||||
|
||||
OpModules.Shellcode = {
|
||||
"Disassemble x86": Shellcode.runDisassemble,
|
||||
};
|
||||
|
||||
export default OpModules;
|
23
src/core/config/modules/URL.js
Normal file
|
@ -0,0 +1,23 @@
|
|||
import URL_ from "../../operations/URL.js";
|
||||
|
||||
|
||||
/**
|
||||
* URL module.
|
||||
*
|
||||
* Libraries:
|
||||
* - Utils.js
|
||||
* - url
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
let OpModules = typeof self === "undefined" ? {} : self.OpModules || {};
|
||||
|
||||
OpModules.URL = {
|
||||
"URL Encode": URL_.runTo,
|
||||
"URL Decode": URL_.runFrom,
|
||||
"Parse URI": URL_.runParse,
|
||||
};
|
||||
|
||||
export default OpModules;
|
5722
src/core/lib/DisassembleX86-64.js
Normal file
214
src/core/operations/BCD.js
Executable file
|
@ -0,0 +1,214 @@
|
|||
import Utils from "../Utils.js";
|
||||
|
||||
|
||||
/**
|
||||
* Binary-Coded Decimal operations.
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*
|
||||
* @namespace
|
||||
*/
|
||||
const BCD = {
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
ENCODING_SCHEME: [
|
||||
"8 4 2 1",
|
||||
"7 4 2 1",
|
||||
"4 2 2 1",
|
||||
"2 4 2 1",
|
||||
"8 4 -2 -1",
|
||||
"Excess-3",
|
||||
"IBM 8 4 2 1",
|
||||
],
|
||||
|
||||
/**
|
||||
* Lookup table for the binary value of each digit representation.
|
||||
*
|
||||
* I wrote a very nice algorithm to generate 8 4 2 1 encoding programatically,
|
||||
* but unfortunately it's much easier (if less elegant) to use lookup tables
|
||||
* when supporting multiple encoding schemes.
|
||||
*
|
||||
* "Practicality beats purity" - PEP 20
|
||||
*
|
||||
* In some schemes it is possible to represent the same value in multiple ways.
|
||||
* For instance, in 4 2 2 1 encoding, 0100 and 0010 both represent 2. Support
|
||||
* has not yet been added for this.
|
||||
*
|
||||
* @constant
|
||||
*/
|
||||
ENCODING_LOOKUP: {
|
||||
"8 4 2 1": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
||||
"7 4 2 1": [0, 1, 2, 3, 4, 5, 6, 8, 9, 10],
|
||||
"4 2 2 1": [0, 1, 4, 5, 8, 9, 12, 13, 14, 15],
|
||||
"2 4 2 1": [0, 1, 2, 3, 4, 11, 12, 13, 14, 15],
|
||||
"8 4 -2 -1": [0, 7, 6, 5, 4, 11, 10, 9, 8, 15],
|
||||
"Excess-3": [3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
|
||||
"IBM 8 4 2 1": [10, 1, 2, 3, 4, 5, 6, 7, 8, 9],
|
||||
},
|
||||
|
||||
/**
|
||||
* @default
|
||||
* @constant
|
||||
*/
|
||||
FORMAT: ["Nibbles", "Bytes", "Raw"],
|
||||
|
||||
|
||||
/**
|
||||
* To BCD operation.
|
||||
*
|
||||
* @param {number} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
runToBCD: function(input, args) {
|
||||
if (isNaN(input))
|
||||
return "Invalid input";
|
||||
if (Math.floor(input) !== input)
|
||||
return "Fractional values are not supported by BCD";
|
||||
|
||||
const encoding = BCD.ENCODING_LOOKUP[args[0]],
|
||||
packed = args[1],
|
||||
signed = args[2],
|
||||
outputFormat = args[3];
|
||||
|
||||
// Split input number up into separate digits
|
||||
const digits = input.toString().split("");
|
||||
|
||||
if (digits[0] === "-" || digits[0] === "+") {
|
||||
digits.shift();
|
||||
}
|
||||
|
||||
let nibbles = [];
|
||||
|
||||
digits.forEach(d => {
|
||||
const n = parseInt(d, 10);
|
||||
nibbles.push(encoding[n]);
|
||||
});
|
||||
|
||||
if (signed) {
|
||||
if (packed && digits.length % 2 === 0) {
|
||||
// If there are an even number of digits, we add a leading 0 so
|
||||
// that the sign nibble doesn't sit in its own byte, leading to
|
||||
// ambiguity around whether the number ends with a 0 or not.
|
||||
nibbles.unshift(encoding[0]);
|
||||
}
|
||||
|
||||
nibbles.push(input > 0 ? 12 : 13);
|
||||
// 12 ("C") for + (credit)
|
||||
// 13 ("D") for - (debit)
|
||||
}
|
||||
|
||||
let bytes = [];
|
||||
|
||||
if (packed) {
|
||||
let encoded = 0,
|
||||
little = false;
|
||||
|
||||
nibbles.forEach(n => {
|
||||
encoded ^= little ? n : (n << 4);
|
||||
if (little) {
|
||||
bytes.push(encoded);
|
||||
encoded = 0;
|
||||
}
|
||||
little = !little;
|
||||
});
|
||||
|
||||
if (little) bytes.push(encoded);
|
||||
} else {
|
||||
bytes = nibbles;
|
||||
|
||||
// Add null high nibbles
|
||||
nibbles = nibbles.map(n => {
|
||||
return [0, n];
|
||||
}).reduce((a, b) => {
|
||||
return a.concat(b);
|
||||
});
|
||||
}
|
||||
|
||||
// Output
|
||||
switch (outputFormat) {
|
||||
case "Nibbles":
|
||||
return nibbles.map(n => {
|
||||
return Utils.padLeft(n.toString(2), 4);
|
||||
}).join(" ");
|
||||
case "Bytes":
|
||||
return bytes.map(b => {
|
||||
return Utils.padLeft(b.toString(2), 8);
|
||||
}).join(" ");
|
||||
case "Raw":
|
||||
default:
|
||||
return Utils.byteArrayToChars(bytes);
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* From BCD operation.
|
||||
*
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {number}
|
||||
*/
|
||||
runFromBCD: function(input, args) {
|
||||
const encoding = BCD.ENCODING_LOOKUP[args[0]],
|
||||
packed = args[1],
|
||||
signed = args[2],
|
||||
inputFormat = args[3];
|
||||
|
||||
let nibbles = [],
|
||||
output = "",
|
||||
byteArray;
|
||||
|
||||
// Normalise the input
|
||||
switch (inputFormat) {
|
||||
case "Nibbles":
|
||||
case "Bytes":
|
||||
input = input.replace(/\s/g, "");
|
||||
for (let i = 0; i < input.length; i += 4) {
|
||||
nibbles.push(parseInt(input.substr(i, 4), 2));
|
||||
}
|
||||
break;
|
||||
case "Raw":
|
||||
default:
|
||||
byteArray = Utils.strToByteArray(input);
|
||||
byteArray.forEach(b => {
|
||||
nibbles.push(b >>> 4);
|
||||
nibbles.push(b & 15);
|
||||
});
|
||||
break;
|
||||
}
|
||||
|
||||
if (!packed) {
|
||||
// Discard each high nibble
|
||||
for (let i = 0; i < nibbles.length; i++) {
|
||||
nibbles.splice(i, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (signed) {
|
||||
const sign = nibbles.pop();
|
||||
if (sign === 13 ||
|
||||
sign === 11) {
|
||||
// Negative
|
||||
output += "-";
|
||||
}
|
||||
}
|
||||
|
||||
nibbles.forEach(n => {
|
||||
if (isNaN(n)) throw "Invalid input";
|
||||
let val = encoding.indexOf(n);
|
||||
if (val < 0) throw `Value ${Utils.bin(n, 4)} not in encoding scheme`;
|
||||
output += val.toString();
|
||||
});
|
||||
|
||||
return parseInt(output, 10);
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
export default BCD;
|
|
@ -221,15 +221,15 @@ const Base64 = {
|
|||
offset0 = "<span data-toggle='tooltip' data-placement='top' title='" +
|
||||
Utils.escapeHtml(Utils.fromBase64(staticSection, alphabet).slice(0, -2)) + "'>" +
|
||||
staticSection + "</span>" +
|
||||
"<span class='hlgreen'>" + offset0.substr(offset0.length - 3, 1) + "</span>" +
|
||||
"<span class='hlred'>" + offset0.substr(offset0.length - 2) + "</span>";
|
||||
"<span class='hl5'>" + offset0.substr(offset0.length - 3, 1) + "</span>" +
|
||||
"<span class='hl3'>" + offset0.substr(offset0.length - 2) + "</span>";
|
||||
} else if (len0 % 4 === 3) {
|
||||
staticSection = offset0.slice(0, -2);
|
||||
offset0 = "<span data-toggle='tooltip' data-placement='top' title='" +
|
||||
Utils.escapeHtml(Utils.fromBase64(staticSection, alphabet).slice(0, -1)) + "'>" +
|
||||
staticSection + "</span>" +
|
||||
"<span class='hlgreen'>" + offset0.substr(offset0.length - 2, 1) + "</span>" +
|
||||
"<span class='hlred'>" + offset0.substr(offset0.length - 1) + "</span>";
|
||||
"<span class='hl5'>" + offset0.substr(offset0.length - 2, 1) + "</span>" +
|
||||
"<span class='hl3'>" + offset0.substr(offset0.length - 1) + "</span>";
|
||||
} else {
|
||||
staticSection = offset0;
|
||||
offset0 = "<span data-toggle='tooltip' data-placement='top' title='" +
|
||||
|
@ -243,23 +243,23 @@ const Base64 = {
|
|||
|
||||
|
||||
// Highlight offset 1
|
||||
padding = "<span class='hlred'>" + offset1.substr(0, 1) + "</span>" +
|
||||
"<span class='hlgreen'>" + offset1.substr(1, 1) + "</span>";
|
||||
padding = "<span class='hl3'>" + offset1.substr(0, 1) + "</span>" +
|
||||
"<span class='hl5'>" + offset1.substr(1, 1) + "</span>";
|
||||
offset1 = offset1.substr(2);
|
||||
if (len1 % 4 === 2) {
|
||||
staticSection = offset1.slice(0, -3);
|
||||
offset1 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
|
||||
Utils.escapeHtml(Utils.fromBase64("AA" + staticSection, alphabet).slice(1, -2)) + "'>" +
|
||||
staticSection + "</span>" +
|
||||
"<span class='hlgreen'>" + offset1.substr(offset1.length - 3, 1) + "</span>" +
|
||||
"<span class='hlred'>" + offset1.substr(offset1.length - 2) + "</span>";
|
||||
"<span class='hl5'>" + offset1.substr(offset1.length - 3, 1) + "</span>" +
|
||||
"<span class='hl3'>" + offset1.substr(offset1.length - 2) + "</span>";
|
||||
} else if (len1 % 4 === 3) {
|
||||
staticSection = offset1.slice(0, -2);
|
||||
offset1 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
|
||||
Utils.escapeHtml(Utils.fromBase64("AA" + staticSection, alphabet).slice(1, -1)) + "'>" +
|
||||
staticSection + "</span>" +
|
||||
"<span class='hlgreen'>" + offset1.substr(offset1.length - 2, 1) + "</span>" +
|
||||
"<span class='hlred'>" + offset1.substr(offset1.length - 1) + "</span>";
|
||||
"<span class='hl5'>" + offset1.substr(offset1.length - 2, 1) + "</span>" +
|
||||
"<span class='hl3'>" + offset1.substr(offset1.length - 1) + "</span>";
|
||||
} else {
|
||||
staticSection = offset1;
|
||||
offset1 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
|
||||
|
@ -272,23 +272,23 @@ const Base64 = {
|
|||
}
|
||||
|
||||
// Highlight offset 2
|
||||
padding = "<span class='hlred'>" + offset2.substr(0, 2) + "</span>" +
|
||||
"<span class='hlgreen'>" + offset2.substr(2, 1) + "</span>";
|
||||
padding = "<span class='hl3'>" + offset2.substr(0, 2) + "</span>" +
|
||||
"<span class='hl5'>" + offset2.substr(2, 1) + "</span>";
|
||||
offset2 = offset2.substr(3);
|
||||
if (len2 % 4 === 2) {
|
||||
staticSection = offset2.slice(0, -3);
|
||||
offset2 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
|
||||
Utils.escapeHtml(Utils.fromBase64("AAA" + staticSection, alphabet).slice(2, -2)) + "'>" +
|
||||
staticSection + "</span>" +
|
||||
"<span class='hlgreen'>" + offset2.substr(offset2.length - 3, 1) + "</span>" +
|
||||
"<span class='hlred'>" + offset2.substr(offset2.length - 2) + "</span>";
|
||||
"<span class='hl5'>" + offset2.substr(offset2.length - 3, 1) + "</span>" +
|
||||
"<span class='hl3'>" + offset2.substr(offset2.length - 2) + "</span>";
|
||||
} else if (len2 % 4 === 3) {
|
||||
staticSection = offset2.slice(0, -2);
|
||||
offset2 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
|
||||
Utils.escapeHtml(Utils.fromBase64("AAA" + staticSection, alphabet).slice(2, -2)) + "'>" +
|
||||
staticSection + "</span>" +
|
||||
"<span class='hlgreen'>" + offset2.substr(offset2.length - 2, 1) + "</span>" +
|
||||
"<span class='hlred'>" + offset2.substr(offset2.length - 1) + "</span>";
|
||||
"<span class='hl5'>" + offset2.substr(offset2.length - 2, 1) + "</span>" +
|
||||
"<span class='hl3'>" + offset2.substr(offset2.length - 1) + "</span>";
|
||||
} else {
|
||||
staticSection = offset2;
|
||||
offset2 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
|
||||
|
@ -300,8 +300,8 @@ const Base64 = {
|
|||
offset2 = staticSection;
|
||||
}
|
||||
|
||||
return (showVariable ? "Characters highlighted in <span class='hlgreen'>green</span> could change if the input is surrounded by more data." +
|
||||
"\nCharacters highlighted in <span class='hlred'>red</span> are for padding purposes only." +
|
||||
return (showVariable ? "Characters highlighted in <span class='hl5'>green</span> could change if the input is surrounded by more data." +
|
||||
"\nCharacters highlighted in <span class='hl3'>red</span> are for padding purposes only." +
|
||||
"\nUnhighlighted characters are <span data-toggle='tooltip' data-placement='top' title='Tooltip on left'>static</span>." +
|
||||
"\nHover over the static sections to see what they decode to on their own.\n" +
|
||||
"\nOffset 0: " + offset0 +
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import Utils from "../Utils.js";
|
||||
import CryptoJS from "crypto-js";
|
||||
|
||||
|
||||
/**
|
||||
|
@ -36,7 +35,9 @@ const BitwiseOp = {
|
|||
o = input[i];
|
||||
x = nullPreserving && (o === 0 || o === k) ? o : func(o, k);
|
||||
result.push(x);
|
||||
if (scheme !== "Standard" && !(nullPreserving && (o === 0 || o === k))) {
|
||||
if (scheme &&
|
||||
scheme !== "Standard" &&
|
||||
!(nullPreserving && (o === 0 || o === k))) {
|
||||
switch (scheme) {
|
||||
case "Input differential":
|
||||
key[i % key.length] = x;
|
||||
|
@ -90,7 +91,7 @@ const BitwiseOp = {
|
|||
* @constant
|
||||
* @default
|
||||
*/
|
||||
XOR_BRUTE_KEY_LENGTH: ["1", "2"],
|
||||
XOR_BRUTE_KEY_LENGTH: 1,
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
|
@ -120,39 +121,62 @@ const BitwiseOp = {
|
|||
* @returns {string}
|
||||
*/
|
||||
runXorBrute: function (input, args) {
|
||||
let keyLength = parseInt(args[0], 10),
|
||||
const keyLength = args[0],
|
||||
sampleLength = args[1],
|
||||
sampleOffset = args[2],
|
||||
nullPreserving = args[3],
|
||||
differential = args[4],
|
||||
crib = args[5],
|
||||
printKey = args[6],
|
||||
outputHex = args[7],
|
||||
regex;
|
||||
scheme = args[3],
|
||||
nullPreserving = args[4],
|
||||
printKey = args[5],
|
||||
outputHex = args[6],
|
||||
crib = args[7].toLowerCase();
|
||||
|
||||
let output = "",
|
||||
let output = [],
|
||||
result,
|
||||
resultUtf8;
|
||||
resultUtf8,
|
||||
record = "";
|
||||
|
||||
input = input.slice(sampleOffset, sampleOffset + sampleLength);
|
||||
|
||||
if (crib !== "") {
|
||||
regex = new RegExp(crib, "im");
|
||||
}
|
||||
if (ENVIRONMENT_IS_WORKER())
|
||||
self.sendStatusMessage("Calculating " + Math.pow(256, keyLength) + " values...");
|
||||
|
||||
/**
|
||||
* Converts an integer to an array of bytes expressing that number.
|
||||
*
|
||||
* @param {number} int
|
||||
* @param {number} len - Length of the resulting array
|
||||
* @returns {array}
|
||||
*/
|
||||
const intToByteArray = (int, len) => {
|
||||
let res = Array(len).fill(0);
|
||||
for (let i = len - 1; i >= 0; i--) {
|
||||
res[i] = int & 0xff;
|
||||
int = int >>> 8;
|
||||
}
|
||||
return res;
|
||||
};
|
||||
|
||||
for (let key = 1, l = Math.pow(256, keyLength); key < l; key++) {
|
||||
result = BitwiseOp._bitOp(input, Utils.hexToByteArray(key.toString(16)), BitwiseOp._xor, nullPreserving, differential);
|
||||
if (key % 10000 === 0 && ENVIRONMENT_IS_WORKER()) {
|
||||
self.sendStatusMessage("Calculating " + l + " values... " + Math.floor(key / l * 100) + "%");
|
||||
}
|
||||
|
||||
result = BitwiseOp._bitOp(input, intToByteArray(key, keyLength), BitwiseOp._xor, nullPreserving, scheme);
|
||||
resultUtf8 = Utils.byteArrayToUtf8(result);
|
||||
if (crib !== "" && resultUtf8.search(regex) === -1) continue;
|
||||
if (printKey) output += "Key = " + Utils.hex(key, (2*keyLength)) + ": ";
|
||||
if (outputHex)
|
||||
output += Utils.byteArrayToHex(result) + "\n";
|
||||
else
|
||||
output += Utils.printable(resultUtf8, false) + "\n";
|
||||
if (printKey) output += "\n";
|
||||
record = "";
|
||||
|
||||
if (crib && resultUtf8.toLowerCase().indexOf(crib) < 0) continue;
|
||||
if (printKey) record += "Key = " + Utils.hex(key, (2*keyLength)) + ": ";
|
||||
if (outputHex) {
|
||||
record += Utils.toHex(result);
|
||||
} else {
|
||||
record += Utils.printable(resultUtf8, false);
|
||||
}
|
||||
|
||||
output.push(record);
|
||||
}
|
||||
return output;
|
||||
|
||||
return output.join("\n");
|
||||
},
|
||||
|
||||
|
||||
|
@ -228,6 +252,46 @@ const BitwiseOp = {
|
|||
},
|
||||
|
||||
|
||||
/**
|
||||
* Bit shift left operation.
|
||||
*
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
runBitShiftLeft: function(input, args) {
|
||||
const amount = args[0];
|
||||
|
||||
return input.map(b => {
|
||||
return (b << amount) & 0xff;
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
BIT_SHIFT_TYPE: ["Logical shift", "Arithmetic shift"],
|
||||
|
||||
/**
|
||||
* Bit shift right operation.
|
||||
*
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
runBitShiftRight: function(input, args) {
|
||||
const amount = args[0],
|
||||
type = args[1],
|
||||
mask = type === "Logical shift" ? 0 : 0x80;
|
||||
|
||||
return input.map(b => {
|
||||
return (b >>> amount) ^ (b & mask);
|
||||
});
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* XOR bitwise calculation.
|
||||
*
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
/* globals app */
|
||||
import Utils from "../Utils.js";
|
||||
|
||||
|
||||
|
@ -100,7 +99,7 @@ const ByteRepr = {
|
|||
/**
|
||||
* To Octal operation.
|
||||
*
|
||||
* @author Matt C [matt@artemisbot.pw]
|
||||
* @author Matt C [matt@artemisbot.uk]
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
|
@ -114,7 +113,7 @@ const ByteRepr = {
|
|||
/**
|
||||
* From Octal operation.
|
||||
*
|
||||
* @author Matt C [matt@artemisbot.pw]
|
||||
* @author Matt C [matt@artemisbot.uk]
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
|
@ -150,8 +149,9 @@ const ByteRepr = {
|
|||
throw "Error: Base argument must be between 2 and 36";
|
||||
}
|
||||
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
ordinal = Utils.ord(input[i]);
|
||||
const charcode = Utils.strToCharcode(input);
|
||||
for (let i = 0; i < charcode.length; i++) {
|
||||
ordinal = charcode[i];
|
||||
|
||||
if (base === 16) {
|
||||
if (ordinal < 256) padding = 2;
|
||||
|
@ -160,11 +160,11 @@ const ByteRepr = {
|
|||
else if (ordinal < 4294967296) padding = 8;
|
||||
else padding = 2;
|
||||
|
||||
if (padding > 2 && app) app.options.attemptHighlight = false;
|
||||
if (padding > 2 && ENVIRONMENT_IS_WORKER()) self.setOption("attemptHighlight", false);
|
||||
|
||||
output += Utils.hex(ordinal, padding) + delim;
|
||||
} else {
|
||||
if (app) app.options.attemptHighlight = false;
|
||||
if (ENVIRONMENT_IS_WORKER()) self.setOption("attemptHighlight", false);
|
||||
output += ordinal.toString(base) + delim;
|
||||
}
|
||||
}
|
||||
|
@ -190,9 +190,7 @@ const ByteRepr = {
|
|||
throw "Error: Base argument must be between 2 and 36";
|
||||
}
|
||||
|
||||
if (base !== 16 && app) {
|
||||
app.options.attemptHighlight = false;
|
||||
}
|
||||
if (base !== 16 && ENVIRONMENT_IS_WORKER()) self.setOption("attemptHighlight", false);
|
||||
|
||||
// Split into groups of 2 if the whole string is concatenated and
|
||||
// too long to be a single character
|
||||
|
@ -237,7 +235,7 @@ const ByteRepr = {
|
|||
|
||||
|
||||
/**
|
||||
* Highlight to hex
|
||||
* Highlight from hex
|
||||
*
|
||||
* @param {Object[]} pos
|
||||
* @param {number} pos[].start
|
||||
|
@ -329,10 +327,8 @@ const ByteRepr = {
|
|||
* @returns {byteArray}
|
||||
*/
|
||||
runFromBinary: function(input, args) {
|
||||
if (args[0] !== "None") {
|
||||
const delimRegex = Utils.regexRep[args[0] || "Space"];
|
||||
input = input.replace(delimRegex, "");
|
||||
}
|
||||
const delimRegex = Utils.regexRep[args[0] || "Space"];
|
||||
input = input.replace(delimRegex, "");
|
||||
|
||||
const output = [];
|
||||
const byteLen = 8;
|
||||
|
|
|
@ -1,6 +1,4 @@
|
|||
import cptable from "../lib/js-codepage/cptable.js";
|
||||
import Utils from "../Utils.js";
|
||||
import CryptoJS from "crypto-js";
|
||||
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import * as CRC from "js-crc";
|
||||
import Utils from "../Utils.js";
|
||||
|
||||
|
||||
|
@ -119,19 +120,24 @@ const Checksum = {
|
|||
/**
|
||||
* CRC-32 Checksum operation.
|
||||
*
|
||||
* @param {byteArray} input
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
runCRC32: function(input, args) {
|
||||
let crcTable = global.crcTable || (global.crcTable = Checksum._genCRCTable()),
|
||||
crc = 0 ^ (-1);
|
||||
return CRC.crc32(input);
|
||||
},
|
||||
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
crc = (crc >>> 8) ^ crcTable[(crc ^ input[i]) & 0xff];
|
||||
}
|
||||
|
||||
return Utils.hex((crc ^ (-1)) >>> 0);
|
||||
/**
|
||||
* CRC-16 Checksum operation.
|
||||
*
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
runCRC16: function(input, args) {
|
||||
return CRC.crc16(input);
|
||||
},
|
||||
|
||||
|
||||
|
@ -168,28 +174,6 @@ const Checksum = {
|
|||
return Utils.hex(0xffff - csum);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Generates a CRC table for use with CRC checksums.
|
||||
*
|
||||
* @private
|
||||
* @returns {array}
|
||||
*/
|
||||
_genCRCTable: function() {
|
||||
let c,
|
||||
crcTable = [];
|
||||
|
||||
for (let n = 0; n < 256; n++) {
|
||||
c = n;
|
||||
for (let k = 0; k < 8; k++) {
|
||||
c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));
|
||||
}
|
||||
crcTable[n] = c;
|
||||
}
|
||||
|
||||
return crcTable;
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
export default Checksum;
|
||||
|
|
|
@ -407,7 +407,7 @@ const Cipher = {
|
|||
/**
|
||||
* Vigenère Encode operation.
|
||||
*
|
||||
* @author Matt C [matt@artemisbot.pw]
|
||||
* @author Matt C [matt@artemisbot.uk]
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
|
@ -454,7 +454,7 @@ const Cipher = {
|
|||
/**
|
||||
* Vigenère Decode operation.
|
||||
*
|
||||
* @author Matt C [matt@artemisbot.pw]
|
||||
* @author Matt C [matt@artemisbot.uk]
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
|
@ -508,7 +508,7 @@ const Cipher = {
|
|||
/**
|
||||
* Affine Cipher Encode operation.
|
||||
*
|
||||
* @author Matt C [matt@artemisbot.pw]
|
||||
* @author Matt C [matt@artemisbot.uk]
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
|
@ -540,9 +540,9 @@ const Cipher = {
|
|||
|
||||
|
||||
/**
|
||||
* Affine Cipher Encode operation.
|
||||
* Affine Cipher Decode operation.
|
||||
*
|
||||
* @author Matt C [matt@artemisbot.pw]
|
||||
* @author Matt C [matt@artemisbot.uk]
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
|
@ -584,7 +584,7 @@ const Cipher = {
|
|||
/**
|
||||
* Atbash Cipher Encode operation.
|
||||
*
|
||||
* @author Matt C [matt@artemisbot.pw]
|
||||
* @author Matt C [matt@artemisbot.uk]
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
|
@ -594,6 +594,159 @@ const Cipher = {
|
|||
},
|
||||
|
||||
|
||||
/**
|
||||
* Generates a polybius square for the given keyword
|
||||
*
|
||||
* @private
|
||||
* @author Matt C [matt@artemisbot.uk]
|
||||
* @param {string} keyword - Must be upper case
|
||||
* @returns {string}
|
||||
*/
|
||||
_genPolybiusSquare: function (keyword) {
|
||||
const alpha = "ABCDEFGHIKLMNOPQRSTUVWXYZ";
|
||||
const polArray = `${keyword}${alpha}`.split("").unique();
|
||||
let polybius = [];
|
||||
|
||||
for (let i = 0; i < 5; i++) {
|
||||
polybius[i] = polArray.slice(i*5, i*5 + 5);
|
||||
}
|
||||
|
||||
return polybius;
|
||||
},
|
||||
|
||||
/**
|
||||
* Bifid Cipher Encode operation
|
||||
*
|
||||
* @author Matt C [matt@artemisbot.uk]
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
runBifidEnc: function (input, args) {
|
||||
const keywordStr = args[0].toUpperCase().replace("J", "I"),
|
||||
keyword = keywordStr.split("").unique(),
|
||||
alpha = "ABCDEFGHIKLMNOPQRSTUVWXYZ";
|
||||
|
||||
let output = "",
|
||||
xCo = [],
|
||||
yCo = [],
|
||||
structure = [],
|
||||
count = 0;
|
||||
|
||||
if (keyword.length > 25)
|
||||
return "The alphabet keyword must be less than 25 characters.";
|
||||
|
||||
if (!/^[a-zA-Z]+$/.test(keywordStr) && keyword.length > 0)
|
||||
return "The key must consist only of letters";
|
||||
|
||||
const polybius = Cipher._genPolybiusSquare(keywordStr);
|
||||
|
||||
input.replace("J", "I").split("").forEach(letter => {
|
||||
let alpInd = alpha.split("").indexOf(letter.toLocaleUpperCase()) >= 0,
|
||||
polInd;
|
||||
|
||||
if (alpInd) {
|
||||
for (let i = 0; i < 5; i++) {
|
||||
polInd = polybius[i].indexOf(letter.toLocaleUpperCase());
|
||||
if (polInd >= 0) {
|
||||
xCo.push(polInd);
|
||||
yCo.push(i);
|
||||
}
|
||||
}
|
||||
|
||||
if (alpha.split("").indexOf(letter) >= 0) {
|
||||
structure.push(true);
|
||||
} else if (alpInd) {
|
||||
structure.push(false);
|
||||
}
|
||||
} else {
|
||||
structure.push(letter);
|
||||
}
|
||||
});
|
||||
|
||||
const trans = `${yCo.join("")}${xCo.join("")}`;
|
||||
|
||||
structure.forEach(pos => {
|
||||
if (typeof pos === "boolean") {
|
||||
let coords = trans.substr(2*count, 2).split("");
|
||||
|
||||
output += pos ?
|
||||
polybius[coords[0]][coords[1]] :
|
||||
polybius[coords[0]][coords[1]].toLocaleLowerCase();
|
||||
count++;
|
||||
} else {
|
||||
output += pos;
|
||||
}
|
||||
});
|
||||
|
||||
return output;
|
||||
},
|
||||
|
||||
/**
|
||||
* Bifid Cipher Decode operation
|
||||
*
|
||||
* @author Matt C [matt@artemisbot.uk]
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
runBifidDec: function (input, args) {
|
||||
const keywordStr = args[0].toUpperCase().replace("J", "I"),
|
||||
keyword = keywordStr.split("").unique(),
|
||||
alpha = "ABCDEFGHIKLMNOPQRSTUVWXYZ";
|
||||
|
||||
let output = "",
|
||||
structure = [],
|
||||
count = 0,
|
||||
trans = "";
|
||||
|
||||
if (keyword.length > 25)
|
||||
return "The alphabet keyword must be less than 25 characters.";
|
||||
|
||||
if (!/^[a-zA-Z]+$/.test(keywordStr) && keyword.length > 0)
|
||||
return "The key must consist only of letters";
|
||||
|
||||
const polybius = Cipher._genPolybiusSquare(keywordStr);
|
||||
|
||||
input.replace("J", "I").split("").forEach((letter) => {
|
||||
let alpInd = alpha.split("").indexOf(letter.toLocaleUpperCase()) >= 0,
|
||||
polInd;
|
||||
|
||||
if (alpInd) {
|
||||
for (let i = 0; i < 5; i++) {
|
||||
polInd = polybius[i].indexOf(letter.toLocaleUpperCase());
|
||||
if (polInd >= 0) {
|
||||
trans += `${i}${polInd}`;
|
||||
}
|
||||
}
|
||||
|
||||
if (alpha.split("").indexOf(letter) >= 0) {
|
||||
structure.push(true);
|
||||
} else if (alpInd) {
|
||||
structure.push(false);
|
||||
}
|
||||
} else {
|
||||
structure.push(letter);
|
||||
}
|
||||
});
|
||||
|
||||
structure.forEach(pos => {
|
||||
if (typeof pos === "boolean") {
|
||||
let coords = [trans[count], trans[count+trans.length/2]];
|
||||
|
||||
output += pos ?
|
||||
polybius[coords[0]][coords[1]] :
|
||||
polybius[coords[0]][coords[1]].toLocaleLowerCase();
|
||||
count++;
|
||||
} else {
|
||||
output += pos;
|
||||
}
|
||||
});
|
||||
|
||||
return output;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
|
@ -608,23 +761,23 @@ const Cipher = {
|
|||
/**
|
||||
* Substitute operation.
|
||||
*
|
||||
* @param {byteArray} input
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
* @returns {string}
|
||||
*/
|
||||
runSubstitute: function (input, args) {
|
||||
let plaintext = Utils.strToByteArray(Utils.expandAlphRange(args[0]).join()),
|
||||
ciphertext = Utils.strToByteArray(Utils.expandAlphRange(args[1]).join()),
|
||||
output = [],
|
||||
let plaintext = Utils.expandAlphRange(args[0]).join(""),
|
||||
ciphertext = Utils.expandAlphRange(args[1]).join(""),
|
||||
output = "",
|
||||
index = -1;
|
||||
|
||||
if (plaintext.length !== ciphertext.length) {
|
||||
output = Utils.strToByteArray("Warning: Plaintext and Ciphertext lengths differ\n\n");
|
||||
output = "Warning: Plaintext and Ciphertext lengths differ\n\n";
|
||||
}
|
||||
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
index = plaintext.indexOf(input[i]);
|
||||
output.push(index > -1 && index < ciphertext.length ? ciphertext[index] : input[i]);
|
||||
output += index > -1 && index < ciphertext.length ? ciphertext[index] : input[i];
|
||||
}
|
||||
|
||||
return output;
|
||||
|
|
|
@ -4,6 +4,7 @@ import Utils from "../Utils.js";
|
|||
import vkbeautify from "vkbeautify";
|
||||
import {DOMParser as dom} from "xmldom";
|
||||
import xpath from "xpath";
|
||||
import jpath from "jsonpath";
|
||||
import prettyPrintOne from "imports-loader?window=>global!exports-loader?prettyPrintOne!google-code-prettify/bin/prettify.min.js";
|
||||
|
||||
|
||||
|
@ -228,19 +229,19 @@ const Code = {
|
|||
}
|
||||
|
||||
code = code
|
||||
// Create newlines after ;
|
||||
.replace(/;/g, ";\n")
|
||||
// Create newlines after { and around }
|
||||
.replace(/{/g, "{\n")
|
||||
.replace(/}/g, "\n}\n")
|
||||
// Remove carriage returns
|
||||
.replace(/\r/g, "")
|
||||
// Remove all indentation
|
||||
.replace(/^\s+/g, "")
|
||||
.replace(/\n\s+/g, "\n")
|
||||
// Remove trailing spaces
|
||||
.replace(/\s*$/g, "")
|
||||
.replace(/\n{/g, "{");
|
||||
// Create newlines after ;
|
||||
.replace(/;/g, ";\n")
|
||||
// Create newlines after { and around }
|
||||
.replace(/{/g, "{\n")
|
||||
.replace(/}/g, "\n}\n")
|
||||
// Remove carriage returns
|
||||
.replace(/\r/g, "")
|
||||
// Remove all indentation
|
||||
.replace(/^\s+/g, "")
|
||||
.replace(/\n\s+/g, "\n")
|
||||
// Remove trailing spaces
|
||||
.replace(/\s*$/g, "")
|
||||
.replace(/\n{/g, "{");
|
||||
|
||||
// Indent
|
||||
let i = 0,
|
||||
|
@ -265,27 +266,27 @@ const Code = {
|
|||
}
|
||||
|
||||
code = code
|
||||
// Add strategic spaces
|
||||
.replace(/\s*([!<>=+-/*]?)=\s*/g, " $1= ")
|
||||
.replace(/\s*<([=]?)\s*/g, " <$1 ")
|
||||
.replace(/\s*>([=]?)\s*/g, " >$1 ")
|
||||
.replace(/([^+])\+([^+=])/g, "$1 + $2")
|
||||
.replace(/([^-])-([^-=])/g, "$1 - $2")
|
||||
.replace(/([^*])\*([^*=])/g, "$1 * $2")
|
||||
.replace(/([^/])\/([^/=])/g, "$1 / $2")
|
||||
.replace(/\s*,\s*/g, ", ")
|
||||
.replace(/\s*{/g, " {")
|
||||
.replace(/}\n/g, "}\n\n")
|
||||
// Hacky horribleness
|
||||
.replace(/(if|for|while|with|elif|elseif)\s*\(([^\n]*)\)\s*\n([^{])/gim, "$1 ($2)\n $3")
|
||||
.replace(/(if|for|while|with|elif|elseif)\s*\(([^\n]*)\)([^{])/gim, "$1 ($2) $3")
|
||||
.replace(/else\s*\n([^{])/gim, "else\n $1")
|
||||
.replace(/else\s+([^{])/gim, "else $1")
|
||||
// Remove strategic spaces
|
||||
.replace(/\s+;/g, ";")
|
||||
.replace(/\{\s+\}/g, "{}")
|
||||
.replace(/\[\s+\]/g, "[]")
|
||||
.replace(/}\s*(else|catch|except|finally|elif|elseif|else if)/gi, "} $1");
|
||||
// Add strategic spaces
|
||||
.replace(/\s*([!<>=+-/*]?)=\s*/g, " $1= ")
|
||||
.replace(/\s*<([=]?)\s*/g, " <$1 ")
|
||||
.replace(/\s*>([=]?)\s*/g, " >$1 ")
|
||||
.replace(/([^+])\+([^+=])/g, "$1 + $2")
|
||||
.replace(/([^-])-([^-=])/g, "$1 - $2")
|
||||
.replace(/([^*])\*([^*=])/g, "$1 * $2")
|
||||
.replace(/([^/])\/([^/=])/g, "$1 / $2")
|
||||
.replace(/\s*,\s*/g, ", ")
|
||||
.replace(/\s*{/g, " {")
|
||||
.replace(/}\n/g, "}\n\n")
|
||||
// Hacky horribleness
|
||||
.replace(/(if|for|while|with|elif|elseif)\s*\(([^\n]*)\)\s*\n([^{])/gim, "$1 ($2)\n $3")
|
||||
.replace(/(if|for|while|with|elif|elseif)\s*\(([^\n]*)\)([^{])/gim, "$1 ($2) $3")
|
||||
.replace(/else\s*\n([^{])/gim, "else\n $1")
|
||||
.replace(/else\s+([^{])/gim, "else $1")
|
||||
// Remove strategic spaces
|
||||
.replace(/\s+;/g, ";")
|
||||
.replace(/\{\s+\}/g, "{}")
|
||||
.replace(/\[\s+\]/g, "[]")
|
||||
.replace(/}\s*(else|catch|except|finally|elif|elseif|else if)/gi, "} $1");
|
||||
|
||||
// Replace preserved tokens
|
||||
const ptokens = /###preservedToken(\d+)###/g;
|
||||
|
@ -329,7 +330,7 @@ const Code = {
|
|||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
runXpath:function(input, args) {
|
||||
runXpath: function(input, args) {
|
||||
let query = args[0],
|
||||
delimiter = args[1];
|
||||
|
||||
|
@ -355,6 +356,48 @@ const Code = {
|
|||
},
|
||||
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
JPATH_INITIAL: "",
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
JPATH_DELIMITER: "\\n",
|
||||
|
||||
/**
|
||||
* JPath expression operation.
|
||||
*
|
||||
* @author Matt C (matt@artemisbot.uk)
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
runJpath: function(input, args) {
|
||||
let query = args[0],
|
||||
delimiter = args[1],
|
||||
results,
|
||||
obj;
|
||||
|
||||
try {
|
||||
obj = JSON.parse(input);
|
||||
} catch (err) {
|
||||
return "Invalid input JSON: " + err.message;
|
||||
}
|
||||
|
||||
try {
|
||||
results = jpath.query(obj, query);
|
||||
} catch (err) {
|
||||
return "Invalid JPath expression: " + err.message;
|
||||
}
|
||||
|
||||
return results.map(result => JSON.stringify(result)).join(delimiter);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
|
|
|
@ -10,12 +10,12 @@ import pako from "pako/index.js";
|
|||
const Zlib = {
|
||||
RawDeflate: rawdeflate.Zlib.RawDeflate,
|
||||
RawInflate: rawinflate.Zlib.RawInflate,
|
||||
Deflate: zlibAndGzip.Zlib.Deflate,
|
||||
Inflate: zlibAndGzip.Zlib.Inflate,
|
||||
Gzip: zlibAndGzip.Zlib.Gzip,
|
||||
Gunzip: zlibAndGzip.Zlib.Gunzip,
|
||||
Zip: zip.Zlib.Zip,
|
||||
Unzip: unzip.Zlib.Unzip,
|
||||
Deflate: zlibAndGzip.Zlib.Deflate,
|
||||
Inflate: zlibAndGzip.Zlib.Inflate,
|
||||
Gzip: zlibAndGzip.Zlib.Gzip,
|
||||
Gunzip: zlibAndGzip.Zlib.Gunzip,
|
||||
Zip: zip.Zlib.Zip,
|
||||
Unzip: unzip.Zlib.Unzip,
|
||||
};
|
||||
|
||||
|
||||
|
@ -55,9 +55,9 @@ const Compress = {
|
|||
* @default
|
||||
*/
|
||||
RAW_COMPRESSION_TYPE_LOOKUP: {
|
||||
"Fixed Huffman Coding" : Zlib.RawDeflate.CompressionType.FIXED,
|
||||
"Dynamic Huffman Coding" : Zlib.RawDeflate.CompressionType.DYNAMIC,
|
||||
"None (Store)" : Zlib.RawDeflate.CompressionType.NONE,
|
||||
"Fixed Huffman Coding": Zlib.RawDeflate.CompressionType.FIXED,
|
||||
"Dynamic Huffman Coding": Zlib.RawDeflate.CompressionType.DYNAMIC,
|
||||
"None (Store)": Zlib.RawDeflate.CompressionType.NONE,
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -100,8 +100,8 @@ const Compress = {
|
|||
* @default
|
||||
*/
|
||||
RAW_BUFFER_TYPE_LOOKUP: {
|
||||
"Adaptive" : Zlib.RawInflate.BufferType.ADAPTIVE,
|
||||
"Block" : Zlib.RawInflate.BufferType.BLOCK,
|
||||
"Adaptive": Zlib.RawInflate.BufferType.ADAPTIVE,
|
||||
"Block": Zlib.RawInflate.BufferType.BLOCK,
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -151,9 +151,9 @@ const Compress = {
|
|||
* @default
|
||||
*/
|
||||
ZLIB_COMPRESSION_TYPE_LOOKUP: {
|
||||
"Fixed Huffman Coding" : Zlib.Deflate.CompressionType.FIXED,
|
||||
"Dynamic Huffman Coding" : Zlib.Deflate.CompressionType.DYNAMIC,
|
||||
"None (Store)" : Zlib.Deflate.CompressionType.NONE,
|
||||
"Fixed Huffman Coding": Zlib.Deflate.CompressionType.FIXED,
|
||||
"Dynamic Huffman Coding": Zlib.Deflate.CompressionType.DYNAMIC,
|
||||
"None (Store)": Zlib.Deflate.CompressionType.NONE,
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -176,8 +176,8 @@ const Compress = {
|
|||
* @default
|
||||
*/
|
||||
ZLIB_BUFFER_TYPE_LOOKUP: {
|
||||
"Adaptive" : Zlib.Inflate.BufferType.ADAPTIVE,
|
||||
"Block" : Zlib.Inflate.BufferType.BLOCK,
|
||||
"Adaptive": Zlib.Inflate.BufferType.ADAPTIVE,
|
||||
"Block": Zlib.Inflate.BufferType.BLOCK,
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -286,17 +286,17 @@ const Compress = {
|
|||
* @default
|
||||
*/
|
||||
ZIP_COMPRESSION_METHOD_LOOKUP: {
|
||||
"Deflate" : Zlib.Zip.CompressionMethod.DEFLATE,
|
||||
"None (Store)" : Zlib.Zip.CompressionMethod.STORE
|
||||
"Deflate": Zlib.Zip.CompressionMethod.DEFLATE,
|
||||
"None (Store)": Zlib.Zip.CompressionMethod.STORE
|
||||
},
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
ZIP_OS_LOOKUP: {
|
||||
"MSDOS" : Zlib.Zip.OperatingSystem.MSDOS,
|
||||
"Unix" : Zlib.Zip.OperatingSystem.UNIX,
|
||||
"Macintosh" : Zlib.Zip.OperatingSystem.MACINTOSH
|
||||
"MSDOS": Zlib.Zip.OperatingSystem.MSDOS,
|
||||
"Unix": Zlib.Zip.OperatingSystem.UNIX,
|
||||
"Macintosh": Zlib.Zip.OperatingSystem.MACINTOSH
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -25,36 +25,36 @@ const Convert = {
|
|||
* @default
|
||||
*/
|
||||
DISTANCE_FACTOR: { // Multiples of a metre
|
||||
"Nanometres (nm)" : 1e-9,
|
||||
"Micrometres (µm)" : 1e-6,
|
||||
"Millimetres (mm)" : 1e-3,
|
||||
"Centimetres (cm)" : 1e-2,
|
||||
"Metres (m)" : 1,
|
||||
"Kilometers (km)" : 1e3,
|
||||
"Nanometres (nm)": 1e-9,
|
||||
"Micrometres (µm)": 1e-6,
|
||||
"Millimetres (mm)": 1e-3,
|
||||
"Centimetres (cm)": 1e-2,
|
||||
"Metres (m)": 1,
|
||||
"Kilometers (km)": 1e3,
|
||||
|
||||
"Thou (th)" : 0.0000254,
|
||||
"Inches (in)" : 0.0254,
|
||||
"Feet (ft)" : 0.3048,
|
||||
"Yards (yd)" : 0.9144,
|
||||
"Chains (ch)" : 20.1168,
|
||||
"Furlongs (fur)" : 201.168,
|
||||
"Miles (mi)" : 1609.344,
|
||||
"Leagues (lea)" : 4828.032,
|
||||
"Thou (th)": 0.0000254,
|
||||
"Inches (in)": 0.0254,
|
||||
"Feet (ft)": 0.3048,
|
||||
"Yards (yd)": 0.9144,
|
||||
"Chains (ch)": 20.1168,
|
||||
"Furlongs (fur)": 201.168,
|
||||
"Miles (mi)": 1609.344,
|
||||
"Leagues (lea)": 4828.032,
|
||||
|
||||
"Fathoms (ftm)" : 1.853184,
|
||||
"Cables" : 185.3184,
|
||||
"Nautical miles" : 1853.184,
|
||||
"Fathoms (ftm)": 1.853184,
|
||||
"Cables": 185.3184,
|
||||
"Nautical miles": 1853.184,
|
||||
|
||||
"Cars (4m)" : 4,
|
||||
"Buses (8.4m)" : 8.4,
|
||||
"Cars (4m)": 4,
|
||||
"Buses (8.4m)": 8.4,
|
||||
"American football fields (91m)": 91,
|
||||
"Football pitches (105m)": 105,
|
||||
|
||||
"Earth-to-Moons" : 380000000,
|
||||
"Earth's equators" : 40075016.686,
|
||||
"Earth-to-Moons": 380000000,
|
||||
"Earth's equators": 40075016.686,
|
||||
"Astronomical units (au)": 149597870700,
|
||||
"Light-years (ly)" : 9460730472580800,
|
||||
"Parsecs (pc)" : 3.0856776e16
|
||||
"Light-years (ly)": 9460730472580800,
|
||||
"Parsecs (pc)": 3.0856776e16
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -90,52 +90,52 @@ const Convert = {
|
|||
* @default
|
||||
*/
|
||||
DATA_FACTOR: { // Multiples of a bit
|
||||
"Bits (b)" : 1,
|
||||
"Nibbles" : 4,
|
||||
"Octets" : 8,
|
||||
"Bytes (B)" : 8,
|
||||
"Bits (b)": 1,
|
||||
"Nibbles": 4,
|
||||
"Octets": 8,
|
||||
"Bytes (B)": 8,
|
||||
|
||||
// Binary bits (2^n)
|
||||
"Kibibits (Kib)" : 1024,
|
||||
"Mebibits (Mib)" : 1048576,
|
||||
"Gibibits (Gib)" : 1073741824,
|
||||
"Tebibits (Tib)" : 1099511627776,
|
||||
"Pebibits (Pib)" : 1125899906842624,
|
||||
"Exbibits (Eib)" : 1152921504606846976,
|
||||
"Zebibits (Zib)" : 1180591620717411303424,
|
||||
"Yobibits (Yib)" : 1208925819614629174706176,
|
||||
"Kibibits (Kib)": 1024,
|
||||
"Mebibits (Mib)": 1048576,
|
||||
"Gibibits (Gib)": 1073741824,
|
||||
"Tebibits (Tib)": 1099511627776,
|
||||
"Pebibits (Pib)": 1125899906842624,
|
||||
"Exbibits (Eib)": 1152921504606846976,
|
||||
"Zebibits (Zib)": 1180591620717411303424,
|
||||
"Yobibits (Yib)": 1208925819614629174706176,
|
||||
|
||||
// Decimal bits (10^n)
|
||||
"Decabits" : 10,
|
||||
"Hectobits" : 100,
|
||||
"Kilobits (Kb)" : 1e3,
|
||||
"Megabits (Mb)" : 1e6,
|
||||
"Gigabits (Gb)" : 1e9,
|
||||
"Terabits (Tb)" : 1e12,
|
||||
"Petabits (Pb)" : 1e15,
|
||||
"Exabits (Eb)" : 1e18,
|
||||
"Zettabits (Zb)" : 1e21,
|
||||
"Yottabits (Yb)" : 1e24,
|
||||
"Decabits": 10,
|
||||
"Hectobits": 100,
|
||||
"Kilobits (Kb)": 1e3,
|
||||
"Megabits (Mb)": 1e6,
|
||||
"Gigabits (Gb)": 1e9,
|
||||
"Terabits (Tb)": 1e12,
|
||||
"Petabits (Pb)": 1e15,
|
||||
"Exabits (Eb)": 1e18,
|
||||
"Zettabits (Zb)": 1e21,
|
||||
"Yottabits (Yb)": 1e24,
|
||||
|
||||
// Binary bytes (8 x 2^n)
|
||||
"Kibibytes (KiB)" : 8192,
|
||||
"Mebibytes (MiB)" : 8388608,
|
||||
"Gibibytes (GiB)" : 8589934592,
|
||||
"Tebibytes (TiB)" : 8796093022208,
|
||||
"Pebibytes (PiB)" : 9007199254740992,
|
||||
"Exbibytes (EiB)" : 9223372036854775808,
|
||||
"Zebibytes (ZiB)" : 9444732965739290427392,
|
||||
"Yobibytes (YiB)" : 9671406556917033397649408,
|
||||
"Kibibytes (KiB)": 8192,
|
||||
"Mebibytes (MiB)": 8388608,
|
||||
"Gibibytes (GiB)": 8589934592,
|
||||
"Tebibytes (TiB)": 8796093022208,
|
||||
"Pebibytes (PiB)": 9007199254740992,
|
||||
"Exbibytes (EiB)": 9223372036854775808,
|
||||
"Zebibytes (ZiB)": 9444732965739290427392,
|
||||
"Yobibytes (YiB)": 9671406556917033397649408,
|
||||
|
||||
// Decimal bytes (8 x 10^n)
|
||||
"Kilobytes (KB)" : 8e3,
|
||||
"Megabytes (MB)" : 8e6,
|
||||
"Gigabytes (GB)" : 8e9,
|
||||
"Terabytes (TB)" : 8e12,
|
||||
"Petabytes (PB)" : 8e15,
|
||||
"Exabytes (EB)" : 8e18,
|
||||
"Zettabytes (ZB)" : 8e21,
|
||||
"Yottabytes (YB)" : 8e24,
|
||||
"Kilobytes (KB)": 8e3,
|
||||
"Megabytes (MB)": 8e6,
|
||||
"Gigabytes (GB)": 8e9,
|
||||
"Terabytes (TB)": 8e12,
|
||||
"Petabytes (PB)": 8e15,
|
||||
"Exabytes (EB)": 8e18,
|
||||
"Zettabytes (ZB)": 8e21,
|
||||
"Yottabytes (YB)": 8e24,
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -171,51 +171,51 @@ const Convert = {
|
|||
*/
|
||||
AREA_FACTOR: { // Multiples of a square metre
|
||||
// Metric
|
||||
"Square metre (sq m)" : 1,
|
||||
"Square kilometre (sq km)" : 1e6,
|
||||
"Square metre (sq m)": 1,
|
||||
"Square kilometre (sq km)": 1e6,
|
||||
|
||||
"Centiare (ca)" : 1,
|
||||
"Deciare (da)" : 10,
|
||||
"Are (a)" : 100,
|
||||
"Decare (daa)" : 1e3,
|
||||
"Hectare (ha)" : 1e4,
|
||||
"Centiare (ca)": 1,
|
||||
"Deciare (da)": 10,
|
||||
"Are (a)": 100,
|
||||
"Decare (daa)": 1e3,
|
||||
"Hectare (ha)": 1e4,
|
||||
|
||||
// Imperial
|
||||
"Square inch (sq in)" : 0.00064516,
|
||||
"Square foot (sq ft)" : 0.09290304,
|
||||
"Square yard (sq yd)" : 0.83612736,
|
||||
"Square mile (sq mi)" : 2589988.110336,
|
||||
"Perch (sq per)" : 42.21,
|
||||
"Rood (ro)" : 1011,
|
||||
"International acre (ac)" : 4046.8564224,
|
||||
"Square inch (sq in)": 0.00064516,
|
||||
"Square foot (sq ft)": 0.09290304,
|
||||
"Square yard (sq yd)": 0.83612736,
|
||||
"Square mile (sq mi)": 2589988.110336,
|
||||
"Perch (sq per)": 42.21,
|
||||
"Rood (ro)": 1011,
|
||||
"International acre (ac)": 4046.8564224,
|
||||
|
||||
// US customary units
|
||||
"US survey acre (ac)" : 4046.87261,
|
||||
"US survey square mile (sq mi)" : 2589998.470305239,
|
||||
"US survey township" : 93239944.9309886,
|
||||
"US survey acre (ac)": 4046.87261,
|
||||
"US survey square mile (sq mi)": 2589998.470305239,
|
||||
"US survey township": 93239944.9309886,
|
||||
|
||||
// Nuclear physics
|
||||
"Yoctobarn (yb)" : 1e-52,
|
||||
"Zeptobarn (zb)" : 1e-49,
|
||||
"Attobarn (ab)" : 1e-46,
|
||||
"Femtobarn (fb)" : 1e-43,
|
||||
"Picobarn (pb)" : 1e-40,
|
||||
"Nanobarn (nb)" : 1e-37,
|
||||
"Microbarn (μb)" : 1e-34,
|
||||
"Millibarn (mb)" : 1e-31,
|
||||
"Barn (b)" : 1e-28,
|
||||
"Kilobarn (kb)" : 1e-25,
|
||||
"Megabarn (Mb)" : 1e-22,
|
||||
"Yoctobarn (yb)": 1e-52,
|
||||
"Zeptobarn (zb)": 1e-49,
|
||||
"Attobarn (ab)": 1e-46,
|
||||
"Femtobarn (fb)": 1e-43,
|
||||
"Picobarn (pb)": 1e-40,
|
||||
"Nanobarn (nb)": 1e-37,
|
||||
"Microbarn (μb)": 1e-34,
|
||||
"Millibarn (mb)": 1e-31,
|
||||
"Barn (b)": 1e-28,
|
||||
"Kilobarn (kb)": 1e-25,
|
||||
"Megabarn (Mb)": 1e-22,
|
||||
|
||||
"Planck area" : 2.6e-70,
|
||||
"Shed" : 1e-52,
|
||||
"Outhouse" : 1e-34,
|
||||
"Planck area": 2.6e-70,
|
||||
"Shed": 1e-52,
|
||||
"Outhouse": 1e-34,
|
||||
|
||||
// Comparisons
|
||||
"Washington D.C." : 176119191.502848,
|
||||
"Isle of Wight" : 380000000,
|
||||
"Wales" : 20779000000,
|
||||
"Texas" : 696241000000,
|
||||
"Washington D.C.": 176119191.502848,
|
||||
"Isle of Wight": 380000000,
|
||||
"Wales": 20779000000,
|
||||
"Texas": 696241000000,
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -252,81 +252,81 @@ const Convert = {
|
|||
*/
|
||||
MASS_FACTOR: { // Multiples of a gram
|
||||
// Metric
|
||||
"Yoctogram (yg)" : 1e-24,
|
||||
"Zeptogram (zg)" : 1e-21,
|
||||
"Attogram (ag)" : 1e-18,
|
||||
"Femtogram (fg)" : 1e-15,
|
||||
"Picogram (pg)" : 1e-12,
|
||||
"Nanogram (ng)" : 1e-9,
|
||||
"Microgram (μg)" : 1e-6,
|
||||
"Milligram (mg)" : 1e-3,
|
||||
"Centigram (cg)" : 1e-2,
|
||||
"Decigram (dg)" : 1e-1,
|
||||
"Gram (g)" : 1,
|
||||
"Decagram (dag)" : 10,
|
||||
"Hectogram (hg)" : 100,
|
||||
"Kilogram (kg)" : 1000,
|
||||
"Megagram (Mg)" : 1e6,
|
||||
"Tonne (t)" : 1e6,
|
||||
"Gigagram (Gg)" : 1e9,
|
||||
"Teragram (Tg)" : 1e12,
|
||||
"Petagram (Pg)" : 1e15,
|
||||
"Exagram (Eg)" : 1e18,
|
||||
"Zettagram (Zg)" : 1e21,
|
||||
"Yottagram (Yg)" : 1e24,
|
||||
"Yoctogram (yg)": 1e-24,
|
||||
"Zeptogram (zg)": 1e-21,
|
||||
"Attogram (ag)": 1e-18,
|
||||
"Femtogram (fg)": 1e-15,
|
||||
"Picogram (pg)": 1e-12,
|
||||
"Nanogram (ng)": 1e-9,
|
||||
"Microgram (μg)": 1e-6,
|
||||
"Milligram (mg)": 1e-3,
|
||||
"Centigram (cg)": 1e-2,
|
||||
"Decigram (dg)": 1e-1,
|
||||
"Gram (g)": 1,
|
||||
"Decagram (dag)": 10,
|
||||
"Hectogram (hg)": 100,
|
||||
"Kilogram (kg)": 1000,
|
||||
"Megagram (Mg)": 1e6,
|
||||
"Tonne (t)": 1e6,
|
||||
"Gigagram (Gg)": 1e9,
|
||||
"Teragram (Tg)": 1e12,
|
||||
"Petagram (Pg)": 1e15,
|
||||
"Exagram (Eg)": 1e18,
|
||||
"Zettagram (Zg)": 1e21,
|
||||
"Yottagram (Yg)": 1e24,
|
||||
|
||||
// Imperial Avoirdupois
|
||||
"Grain (gr)" : 64.79891e-3,
|
||||
"Dram (dr)" : 1.7718451953125,
|
||||
"Ounce (oz)" : 28.349523125,
|
||||
"Pound (lb)" : 453.59237,
|
||||
"Nail" : 3175.14659,
|
||||
"Stone (st)" : 6.35029318e3,
|
||||
"Quarter (gr)" : 12700.58636,
|
||||
"Tod" : 12700.58636,
|
||||
"US hundredweight (cwt)" : 45.359237e3,
|
||||
"Imperial hundredweight (cwt)" : 50.80234544e3,
|
||||
"US ton (t)" : 907.18474e3,
|
||||
"Imperial ton (t)" : 1016.0469088e3,
|
||||
"Grain (gr)": 64.79891e-3,
|
||||
"Dram (dr)": 1.7718451953125,
|
||||
"Ounce (oz)": 28.349523125,
|
||||
"Pound (lb)": 453.59237,
|
||||
"Nail": 3175.14659,
|
||||
"Stone (st)": 6.35029318e3,
|
||||
"Quarter (gr)": 12700.58636,
|
||||
"Tod": 12700.58636,
|
||||
"US hundredweight (cwt)": 45.359237e3,
|
||||
"Imperial hundredweight (cwt)": 50.80234544e3,
|
||||
"US ton (t)": 907.18474e3,
|
||||
"Imperial ton (t)": 1016.0469088e3,
|
||||
|
||||
// Imperial Troy
|
||||
"Pennyweight (dwt)" : 1.55517384,
|
||||
"Troy dram (dr t)" : 3.8879346,
|
||||
"Troy ounce (oz t)" : 31.1034768,
|
||||
"Troy pound (lb t)" : 373.2417216,
|
||||
"Mark" : 248.8278144,
|
||||
"Pennyweight (dwt)": 1.55517384,
|
||||
"Troy dram (dr t)": 3.8879346,
|
||||
"Troy ounce (oz t)": 31.1034768,
|
||||
"Troy pound (lb t)": 373.2417216,
|
||||
"Mark": 248.8278144,
|
||||
|
||||
// Archaic
|
||||
"Wey" : 76.5e3,
|
||||
"Wool wey" : 101.7e3,
|
||||
"Suffolk wey" : 161.5e3,
|
||||
"Wool sack" : 153000,
|
||||
"Coal sack" : 50.80234544e3,
|
||||
"Load" : 918000,
|
||||
"Last" : 1836000,
|
||||
"Flax or feather last" : 770e3,
|
||||
"Gunpowder last" : 1090e3,
|
||||
"Picul" : 60.478982e3,
|
||||
"Rice last" : 1200e3,
|
||||
"Wey": 76.5e3,
|
||||
"Wool wey": 101.7e3,
|
||||
"Suffolk wey": 161.5e3,
|
||||
"Wool sack": 153000,
|
||||
"Coal sack": 50.80234544e3,
|
||||
"Load": 918000,
|
||||
"Last": 1836000,
|
||||
"Flax or feather last": 770e3,
|
||||
"Gunpowder last": 1090e3,
|
||||
"Picul": 60.478982e3,
|
||||
"Rice last": 1200e3,
|
||||
|
||||
// Comparisons
|
||||
"Big Ben (14 tonnes)" : 14e6,
|
||||
"Blue whale (180 tonnes)" : 180e6,
|
||||
"International Space Station (417 tonnes)" : 417e6,
|
||||
"Space Shuttle (2,041 tonnes)" : 2041e6,
|
||||
"RMS Titanic (52,000 tonnes)" : 52000e6,
|
||||
"Great Pyramid of Giza (6,000,000 tonnes)" : 6e12,
|
||||
"Earth's oceans (1.4 yottagrams)" : 1.4e24,
|
||||
"Big Ben (14 tonnes)": 14e6,
|
||||
"Blue whale (180 tonnes)": 180e6,
|
||||
"International Space Station (417 tonnes)": 417e6,
|
||||
"Space Shuttle (2,041 tonnes)": 2041e6,
|
||||
"RMS Titanic (52,000 tonnes)": 52000e6,
|
||||
"Great Pyramid of Giza (6,000,000 tonnes)": 6e12,
|
||||
"Earth's oceans (1.4 yottagrams)": 1.4e24,
|
||||
|
||||
// Astronomical
|
||||
"A teaspoon of neutron star (5,500 million tonnes)" : 5.5e15,
|
||||
"Lunar mass (ML)" : 7.342e25,
|
||||
"Earth mass (M⊕)" : 5.97219e27,
|
||||
"Jupiter mass (MJ)" : 1.8981411476999997e30,
|
||||
"Solar mass (M☉)" : 1.98855e33,
|
||||
"Sagittarius A* (7.5 x 10^36 kgs-ish)" : 7.5e39,
|
||||
"Milky Way galaxy (1.2 x 10^42 kgs)" : 1.2e45,
|
||||
"The observable universe (1.45 x 10^53 kgs)" : 1.45e56,
|
||||
"A teaspoon of neutron star (5,500 million tonnes)": 5.5e15,
|
||||
"Lunar mass (ML)": 7.342e25,
|
||||
"Earth mass (M⊕)": 5.97219e27,
|
||||
"Jupiter mass (MJ)": 1.8981411476999997e30,
|
||||
"Solar mass (M☉)": 1.98855e33,
|
||||
"Sagittarius A* (7.5 x 10^36 kgs-ish)": 7.5e39,
|
||||
"Milky Way galaxy (1.2 x 10^42 kgs)": 1.2e45,
|
||||
"The observable universe (1.45 x 10^53 kgs)": 1.45e56,
|
||||
},
|
||||
|
||||
/**
|
||||
|
@ -361,37 +361,37 @@ const Convert = {
|
|||
*/
|
||||
SPEED_FACTOR: { // Multiples of m/s
|
||||
// Metric
|
||||
"Metres per second (m/s)" : 1,
|
||||
"Kilometres per hour (km/h)" : 0.2778,
|
||||
"Metres per second (m/s)": 1,
|
||||
"Kilometres per hour (km/h)": 0.2778,
|
||||
|
||||
// Imperial
|
||||
"Miles per hour (mph)" : 0.44704,
|
||||
"Knots (kn)" : 0.5144,
|
||||
"Miles per hour (mph)": 0.44704,
|
||||
"Knots (kn)": 0.5144,
|
||||
|
||||
// Comparisons
|
||||
"Human hair growth rate" : 4.8e-9,
|
||||
"Bamboo growth rate" : 1.4e-5,
|
||||
"World's fastest snail" : 0.00275,
|
||||
"Usain Bolt's top speed" : 12.42,
|
||||
"Jet airliner cruising speed" : 250,
|
||||
"Concorde" : 603,
|
||||
"SR-71 Blackbird" : 981,
|
||||
"Space Shuttle" : 1400,
|
||||
"International Space Station" : 7700,
|
||||
"Human hair growth rate": 4.8e-9,
|
||||
"Bamboo growth rate": 1.4e-5,
|
||||
"World's fastest snail": 0.00275,
|
||||
"Usain Bolt's top speed": 12.42,
|
||||
"Jet airliner cruising speed": 250,
|
||||
"Concorde": 603,
|
||||
"SR-71 Blackbird": 981,
|
||||
"Space Shuttle": 1400,
|
||||
"International Space Station": 7700,
|
||||
|
||||
// Scientific
|
||||
"Sound in standard atmosphere" : 340.3,
|
||||
"Sound in water" : 1500,
|
||||
"Lunar escape velocity" : 2375,
|
||||
"Earth escape velocity" : 11200,
|
||||
"Earth's solar orbit" : 29800,
|
||||
"Solar system's Milky Way orbit" : 200000,
|
||||
"Milky Way relative to the cosmic microwave background" : 552000,
|
||||
"Solar escape velocity" : 617700,
|
||||
"Neutron star escape velocity (0.3c)" : 100000000,
|
||||
"Light in a diamond (0.4136c)" : 124000000,
|
||||
"Signal in an optical fibre (0.667c)" : 200000000,
|
||||
"Light (c)" : 299792458,
|
||||
"Sound in standard atmosphere": 340.3,
|
||||
"Sound in water": 1500,
|
||||
"Lunar escape velocity": 2375,
|
||||
"Earth escape velocity": 11200,
|
||||
"Earth's solar orbit": 29800,
|
||||
"Solar system's Milky Way orbit": 200000,
|
||||
"Milky Way relative to the cosmic microwave background": 552000,
|
||||
"Solar escape velocity": 617700,
|
||||
"Neutron star escape velocity (0.3c)": 100000000,
|
||||
"Light in a diamond (0.4136c)": 124000000,
|
||||
"Signal in an optical fibre (0.667c)": 200000000,
|
||||
"Light (c)": 299792458,
|
||||
},
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import {BigInteger} from "jsbn";
|
||||
|
||||
/**
|
||||
* Date and time operations.
|
||||
*
|
||||
|
@ -80,58 +78,6 @@ const DateTime = {
|
|||
},
|
||||
|
||||
|
||||
/**
|
||||
* Windows Filetime to Unix Timestamp operation.
|
||||
*
|
||||
* @author bwhitn [brian.m.whitney@outlook.com]
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
runFromFiletimeToUnix: function(input, args) {
|
||||
let units = args[0];
|
||||
input = new BigInteger(input).subtract(new BigInteger("116444736000000000"));
|
||||
if (units === "Seconds (s)"){
|
||||
input = input.divide(new BigInteger("10000000"));
|
||||
} else if (units === "Milliseconds (ms)") {
|
||||
input = input.divide(new BigInteger("10000"));
|
||||
} else if (units === "Microseconds (μs)") {
|
||||
input = input.divide(new BigInteger("10"));
|
||||
} else if (units === "Nanoseconds (ns)") {
|
||||
input = input.multiply(new BigInteger("100"));
|
||||
} else {
|
||||
throw "Unrecognised unit";
|
||||
}
|
||||
return input.toString();
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Unix Timestamp to Windows Filetime operation.
|
||||
*
|
||||
* @author bwhitn [brian.m.whitney@outlook.com]
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
runToFiletimeFromUnix: function(input, args) {
|
||||
let units = args[0];
|
||||
input = new BigInteger(input);
|
||||
if (units === "Seconds (s)"){
|
||||
input = input.multiply(new BigInteger("10000000"));
|
||||
} else if (units === "Milliseconds (ms)") {
|
||||
input = input.multiply(new BigInteger("10000"));
|
||||
} else if (units === "Microseconds (μs)") {
|
||||
input = input.multiply(new BigInteger("10"));
|
||||
} else if (units === "Nanoseconds (ns)") {
|
||||
input = input.divide(new BigInteger("100"));
|
||||
} else {
|
||||
throw "Unrecognised unit";
|
||||
}
|
||||
return input.add(new BigInteger("116444736000000000")).toString();
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
|
@ -246,268 +192,270 @@ const DateTime = {
|
|||
/**
|
||||
* @constant
|
||||
*/
|
||||
FORMAT_EXAMPLES: "Format string tokens:\n\n\
|
||||
<table class='table table-striped table-hover table-condensed table-bordered' style='font-family: sans-serif'>\
|
||||
<thead>\
|
||||
<tr>\
|
||||
<th>Category</th>\
|
||||
<th>Token</th>\
|
||||
<th>Output</th>\
|
||||
</tr>\
|
||||
</thead>\
|
||||
<tbody>\
|
||||
<tr>\
|
||||
<td><b>Month</b></td>\
|
||||
<td>M</td>\
|
||||
<td>1 2 ... 11 12</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td></td>\
|
||||
<td>Mo</td>\
|
||||
<td>1st 2nd ... 11th 12th</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td></td>\
|
||||
<td>MM</td>\
|
||||
<td>01 02 ... 11 12</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td></td>\
|
||||
<td>MMM</td>\
|
||||
<td>Jan Feb ... Nov Dec</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td></td>\
|
||||
<td>MMMM</td>\
|
||||
<td>January February ... November December</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td><b>Quarter</b></td>\
|
||||
<td>Q</td>\
|
||||
<td>1 2 3 4</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td><b>Day of Month</b></td>\
|
||||
<td>D</td>\
|
||||
<td>1 2 ... 30 31</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td></td>\
|
||||
<td>Do</td>\
|
||||
<td>1st 2nd ... 30th 31st</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td></td>\
|
||||
<td>DD</td>\
|
||||
<td>01 02 ... 30 31</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td><b>Day of Year</b></td>\
|
||||
<td>DDD</td>\
|
||||
<td>1 2 ... 364 365</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td></td>\
|
||||
<td>DDDo</td>\
|
||||
<td>1st 2nd ... 364th 365th</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td></td>\
|
||||
<td>DDDD</td>\
|
||||
<td>001 002 ... 364 365</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td><b>Day of Week</b></td>\
|
||||
<td>d</td>\
|
||||
<td>0 1 ... 5 6</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td></td>\
|
||||
<td>do</td>\
|
||||
<td>0th 1st ... 5th 6th</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td></td>\
|
||||
<td>dd</td>\
|
||||
<td>Su Mo ... Fr Sa</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td></td>\
|
||||
<td>ddd</td>\
|
||||
<td>Sun Mon ... Fri Sat</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td></td>\
|
||||
<td>dddd</td>\
|
||||
<td>Sunday Monday ... Friday Saturday</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td><b>Day of Week (Locale)</b></td>\
|
||||
<td>e</td>\
|
||||
<td>0 1 ... 5 6</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td><b>Day of Week (ISO)</b></td>\
|
||||
<td>E</td>\
|
||||
<td>1 2 ... 6 7</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td><b>Week of Year</b></td>\
|
||||
<td>w</td>\
|
||||
<td>1 2 ... 52 53</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td></td>\
|
||||
<td>wo</td>\
|
||||
<td>1st 2nd ... 52nd 53rd</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td></td>\
|
||||
<td>ww</td>\
|
||||
<td>01 02 ... 52 53</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td><b>Week of Year (ISO)</b></td>\
|
||||
<td>W</td>\
|
||||
<td>1 2 ... 52 53</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td></td>\
|
||||
<td>Wo</td>\
|
||||
<td>1st 2nd ... 52nd 53rd</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td></td>\
|
||||
<td>WW</td>\
|
||||
<td>01 02 ... 52 53</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td><b>Year</b></td>\
|
||||
<td>YY</td>\
|
||||
<td>70 71 ... 29 30</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td></td>\
|
||||
<td>YYYY</td>\
|
||||
<td>1970 1971 ... 2029 2030</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td><b>Week Year</b></td>\
|
||||
<td>gg</td>\
|
||||
<td>70 71 ... 29 30</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td></td>\
|
||||
<td>gggg</td>\
|
||||
<td>1970 1971 ... 2029 2030</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td><b>Week Year (ISO)</b></td>\
|
||||
<td>GG</td>\
|
||||
<td>70 71 ... 29 30</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td></td>\
|
||||
<td>GGGG</td>\
|
||||
<td>1970 1971 ... 2029 2030</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td><b>AM/PM</b></td>\
|
||||
<td>A</td>\
|
||||
<td>AM PM</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td></td>\
|
||||
<td>a</td>\
|
||||
<td>am pm</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td><b>Hour</b></td>\
|
||||
<td>H</td>\
|
||||
<td>0 1 ... 22 23</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td></td>\
|
||||
<td>HH</td>\
|
||||
<td>00 01 ... 22 23</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td></td>\
|
||||
<td>h</td>\
|
||||
<td>1 2 ... 11 12</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td></td>\
|
||||
<td>hh</td>\
|
||||
<td>01 02 ... 11 12</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td><b>Minute</b></td>\
|
||||
<td>m</td>\
|
||||
<td>0 1 ... 58 59</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td></td>\
|
||||
<td>mm</td>\
|
||||
<td>00 01 ... 58 59</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td><b>Second</b></td>\
|
||||
<td>s</td>\
|
||||
<td>0 1 ... 58 59</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td></td>\
|
||||
<td>ss</td>\
|
||||
<td>00 01 ... 58 59</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td><b>Fractional Second</b></td>\
|
||||
<td>S</td>\
|
||||
<td>0 1 ... 8 9</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td></td>\
|
||||
<td>SS</td>\
|
||||
<td>00 01 ... 98 99</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td></td>\
|
||||
<td>SSS</td>\
|
||||
<td>000 001 ... 998 999</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td></td>\
|
||||
<td>SSSS ... SSSSSSSSS</td>\
|
||||
<td>000[0..] 001[0..] ... 998[0..] 999[0..]</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td><b>Timezone</b></td>\
|
||||
<td>z or zz</td>\
|
||||
<td>EST CST ... MST PST</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td></td>\
|
||||
<td>Z</td>\
|
||||
<td>-07:00 -06:00 ... +06:00 +07:00</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td></td>\
|
||||
<td>ZZ</td>\
|
||||
<td>-0700 -0600 ... +0600 +0700</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td><b>Unix Timestamp</b></td>\
|
||||
<td>X</td>\
|
||||
<td>1360013296</td>\
|
||||
</tr>\
|
||||
<tr>\
|
||||
<td><b>Unix Millisecond Timestamp</b></td>\
|
||||
<td>x</td>\
|
||||
<td>1360013296123</td>\
|
||||
</tr>\
|
||||
</tbody>\
|
||||
</table>",
|
||||
FORMAT_EXAMPLES: `Format string tokens:
|
||||
|
||||
|
||||
<table class="table table-striped table-hover table-condensed table-bordered" style="font-family: sans-serif">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Category</th>
|
||||
<th>Token</th>
|
||||
<th>Output</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td><b>Month</b></td>
|
||||
<td>M</td>
|
||||
<td>1 2 ... 11 12</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>Mo</td>
|
||||
<td>1st 2nd ... 11th 12th</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>MM</td>
|
||||
<td>01 02 ... 11 12</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>MMM</td>
|
||||
<td>Jan Feb ... Nov Dec</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>MMMM</td>
|
||||
<td>January February ... November December</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Quarter</b></td>
|
||||
<td>Q</td>
|
||||
<td>1 2 3 4</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Day of Month</b></td>
|
||||
<td>D</td>
|
||||
<td>1 2 ... 30 31</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>Do</td>
|
||||
<td>1st 2nd ... 30th 31st</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>DD</td>
|
||||
<td>01 02 ... 30 31</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Day of Year</b></td>
|
||||
<td>DDD</td>
|
||||
<td>1 2 ... 364 365</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>DDDo</td>
|
||||
<td>1st 2nd ... 364th 365th</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>DDDD</td>
|
||||
<td>001 002 ... 364 365</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Day of Week</b></td>
|
||||
<td>d</td>
|
||||
<td>0 1 ... 5 6</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>do</td>
|
||||
<td>0th 1st ... 5th 6th</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>dd</td>
|
||||
<td>Su Mo ... Fr Sa</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>ddd</td>
|
||||
<td>Sun Mon ... Fri Sat</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>dddd</td>
|
||||
<td>Sunday Monday ... Friday Saturday</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Day of Week (Locale)</b></td>
|
||||
<td>e</td>
|
||||
<td>0 1 ... 5 6</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Day of Week (ISO)</b></td>
|
||||
<td>E</td>
|
||||
<td>1 2 ... 6 7</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Week of Year</b></td>
|
||||
<td>w</td>
|
||||
<td>1 2 ... 52 53</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>wo</td>
|
||||
<td>1st 2nd ... 52nd 53rd</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>ww</td>
|
||||
<td>01 02 ... 52 53</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Week of Year (ISO)</b></td>
|
||||
<td>W</td>
|
||||
<td>1 2 ... 52 53</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>Wo</td>
|
||||
<td>1st 2nd ... 52nd 53rd</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>WW</td>
|
||||
<td>01 02 ... 52 53</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Year</b></td>
|
||||
<td>YY</td>
|
||||
<td>70 71 ... 29 30</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>YYYY</td>
|
||||
<td>1970 1971 ... 2029 2030</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Week Year</b></td>
|
||||
<td>gg</td>
|
||||
<td>70 71 ... 29 30</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>gggg</td>
|
||||
<td>1970 1971 ... 2029 2030</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Week Year (ISO)</b></td>
|
||||
<td>GG</td>
|
||||
<td>70 71 ... 29 30</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>GGGG</td>
|
||||
<td>1970 1971 ... 2029 2030</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>AM/PM</b></td>
|
||||
<td>A</td>
|
||||
<td>AM PM</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>a</td>
|
||||
<td>am pm</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Hour</b></td>
|
||||
<td>H</td>
|
||||
<td>0 1 ... 22 23</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>HH</td>
|
||||
<td>00 01 ... 22 23</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>h</td>
|
||||
<td>1 2 ... 11 12</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>hh</td>
|
||||
<td>01 02 ... 11 12</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Minute</b></td>
|
||||
<td>m</td>
|
||||
<td>0 1 ... 58 59</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>mm</td>
|
||||
<td>00 01 ... 58 59</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Second</b></td>
|
||||
<td>s</td>
|
||||
<td>0 1 ... 58 59</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>ss</td>
|
||||
<td>00 01 ... 58 59</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Fractional Second</b></td>
|
||||
<td>S</td>
|
||||
<td>0 1 ... 8 9</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>SS</td>
|
||||
<td>00 01 ... 98 99</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>SSS</td>
|
||||
<td>000 001 ... 998 999</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>SSSS ... SSSSSSSSS</td>
|
||||
<td>000[0..] 001[0..] ... 998[0..] 999[0..]</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Timezone</b></td>
|
||||
<td>z or zz</td>
|
||||
<td>EST CST ... MST PST</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>Z</td>
|
||||
<td>-07:00 -06:00 ... +06:00 +07:00</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>ZZ</td>
|
||||
<td>-0700 -0600 ... +0600 +0700</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Unix Timestamp</b></td>
|
||||
<td>X</td>
|
||||
<td>1360013296</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><b>Unix Millisecond Timestamp</b></td>
|
||||
<td>x</td>
|
||||
<td>1360013296123</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>`,
|
||||
|
||||
};
|
||||
|
||||
|
|
94
src/core/operations/Diff.js
Normal file
|
@ -0,0 +1,94 @@
|
|||
import Utils from "../Utils.js";
|
||||
import * as JsDiff from "diff";
|
||||
|
||||
|
||||
/**
|
||||
* Diff operations.
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*
|
||||
* @namespace
|
||||
*/
|
||||
const Diff = {
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
DIFF_SAMPLE_DELIMITER: "\\n\\n",
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
DIFF_BY: ["Character", "Word", "Line", "Sentence", "CSS", "JSON"],
|
||||
|
||||
/**
|
||||
* Diff operation.
|
||||
*
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {html}
|
||||
*/
|
||||
runDiff: function(input, args) {
|
||||
let sampleDelim = args[0],
|
||||
diffBy = args[1],
|
||||
showAdded = args[2],
|
||||
showRemoved = args[3],
|
||||
ignoreWhitespace = args[4],
|
||||
samples = input.split(sampleDelim),
|
||||
output = "",
|
||||
diff;
|
||||
|
||||
if (!samples || samples.length !== 2) {
|
||||
return "Incorrect number of samples, perhaps you need to modify the sample delimiter or add more samples?";
|
||||
}
|
||||
|
||||
switch (diffBy) {
|
||||
case "Character":
|
||||
diff = JsDiff.diffChars(samples[0], samples[1]);
|
||||
break;
|
||||
case "Word":
|
||||
if (ignoreWhitespace) {
|
||||
diff = JsDiff.diffWords(samples[0], samples[1]);
|
||||
} else {
|
||||
diff = JsDiff.diffWordsWithSpace(samples[0], samples[1]);
|
||||
}
|
||||
break;
|
||||
case "Line":
|
||||
if (ignoreWhitespace) {
|
||||
diff = JsDiff.diffTrimmedLines(samples[0], samples[1]);
|
||||
} else {
|
||||
diff = JsDiff.diffLines(samples[0], samples[1]);
|
||||
}
|
||||
break;
|
||||
case "Sentence":
|
||||
diff = JsDiff.diffSentences(samples[0], samples[1]);
|
||||
break;
|
||||
case "CSS":
|
||||
diff = JsDiff.diffCss(samples[0], samples[1]);
|
||||
break;
|
||||
case "JSON":
|
||||
diff = JsDiff.diffJson(samples[0], samples[1]);
|
||||
break;
|
||||
default:
|
||||
return "Invalid 'Diff by' option.";
|
||||
}
|
||||
|
||||
for (let i = 0; i < diff.length; i++) {
|
||||
if (diff[i].added) {
|
||||
if (showAdded) output += "<span class='hl5'>" + Utils.escapeHtml(diff[i].value) + "</span>";
|
||||
} else if (diff[i].removed) {
|
||||
if (showRemoved) output += "<span class='hl3'>" + Utils.escapeHtml(diff[i].value) + "</span>";
|
||||
} else {
|
||||
output += Utils.escapeHtml(diff[i].value);
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
export default Diff;
|
|
@ -170,9 +170,9 @@ const Extract = {
|
|||
protocol = "[A-Z]+://",
|
||||
hostname = "[-\\w]+(?:\\.\\w[-\\w]*)+",
|
||||
port = ":\\d+",
|
||||
path = "/[^.!,?;\"'<>()\\[\\]{}\\s\\x7F-\\xFF]*";
|
||||
path = "/[^.!,?\"<>\\[\\]{}\\s\\x7F-\\xFF]*";
|
||||
|
||||
path += "(?:[.!,?]+[^.!,?;\"'<>()\\[\\]{}\\s\\x7F-\\xFF]+)*";
|
||||
path += "(?:[.!,?]+[^.!,?\"<>\\[\\]{}\\s\\x7F-\\xFF]+)*";
|
||||
const regex = new RegExp(protocol + hostname + "(?:" + port +
|
||||
")?(?:" + path + ")?", "ig");
|
||||
return Extract._search(input, regex, null, displayTotal);
|
||||
|
@ -187,11 +187,8 @@ const Extract = {
|
|||
* @returns {string}
|
||||
*/
|
||||
runDomains: function(input, args) {
|
||||
let displayTotal = args[0],
|
||||
protocol = "https?://",
|
||||
hostname = "[-\\w\\.]+",
|
||||
tld = "\\.(?:com|net|org|biz|info|co|uk|onion|int|mobi|name|edu|gov|mil|eu|ac|ae|af|de|ca|ch|cn|cy|es|gb|hk|il|in|io|tv|me|nl|no|nz|ro|ru|tr|us|az|ir|kz|uz|pk)+",
|
||||
regex = new RegExp("(?:" + protocol + ")?" + hostname + tld, "ig");
|
||||
const displayTotal = args[0],
|
||||
regex = /\b((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,63}\b/ig;
|
||||
|
||||
return Extract._search(input, regex, null, displayTotal);
|
||||
},
|
||||
|
@ -261,39 +258,6 @@ const Extract = {
|
|||
return Extract._search(input, regex, null, displayTotal);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Extract all identifiers operation.
|
||||
*
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
runAllIdents: function(input, args) {
|
||||
let output = "";
|
||||
output += "IP addresses\n";
|
||||
output += Extract.runIp(input, [true, true, false]);
|
||||
|
||||
output += "\nEmail addresses\n";
|
||||
output += Extract.runEmail(input, []);
|
||||
|
||||
output += "\nMAC addresses\n";
|
||||
output += Extract.runMac(input, []);
|
||||
|
||||
output += "\nURLs\n";
|
||||
output += Extract.runUrls(input, []);
|
||||
|
||||
output += "\nDomain names\n";
|
||||
output += Extract.runDomains(input, []);
|
||||
|
||||
output += "\nFile paths\n";
|
||||
output += Extract.runFilePaths(input, [true, true]);
|
||||
|
||||
output += "\nDates\n";
|
||||
output += Extract.runDates(input, []);
|
||||
return output;
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
export default Extract;
|
||||
|
|
99
src/core/operations/Filetime.js
Normal file
|
@ -0,0 +1,99 @@
|
|||
import {BigInteger} from "jsbn";
|
||||
|
||||
/**
|
||||
* Windows Filetime operations.
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*
|
||||
* @namespace
|
||||
*/
|
||||
const Filetime = {
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
UNITS: ["Seconds (s)", "Milliseconds (ms)", "Microseconds (μs)", "Nanoseconds (ns)"],
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
FILETIME_FORMATS: ["Decimal", "Hex"],
|
||||
|
||||
/**
|
||||
* Windows Filetime to Unix Timestamp operation.
|
||||
*
|
||||
* @author bwhitn [brian.m.whitney@outlook.com]
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
runFromFiletimeToUnix: function(input, args) {
|
||||
let units = args[0],
|
||||
format = args[1];
|
||||
|
||||
if (format === "Hex") {
|
||||
input = new BigInteger(input, 16);
|
||||
} else {
|
||||
input = new BigInteger(input);
|
||||
}
|
||||
|
||||
input = input.subtract(new BigInteger("116444736000000000"));
|
||||
|
||||
if (units === "Seconds (s)"){
|
||||
input = input.divide(new BigInteger("10000000"));
|
||||
} else if (units === "Milliseconds (ms)") {
|
||||
input = input.divide(new BigInteger("10000"));
|
||||
} else if (units === "Microseconds (μs)") {
|
||||
input = input.divide(new BigInteger("10"));
|
||||
} else if (units === "Nanoseconds (ns)") {
|
||||
input = input.multiply(new BigInteger("100"));
|
||||
} else {
|
||||
throw "Unrecognised unit";
|
||||
}
|
||||
|
||||
return input.toString();
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Unix Timestamp to Windows Filetime operation.
|
||||
*
|
||||
* @author bwhitn [brian.m.whitney@outlook.com]
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
runToFiletimeFromUnix: function(input, args) {
|
||||
let units = args[0],
|
||||
format = args[1];
|
||||
|
||||
input = new BigInteger(input);
|
||||
|
||||
if (units === "Seconds (s)"){
|
||||
input = input.multiply(new BigInteger("10000000"));
|
||||
} else if (units === "Milliseconds (ms)") {
|
||||
input = input.multiply(new BigInteger("10000"));
|
||||
} else if (units === "Microseconds (μs)") {
|
||||
input = input.multiply(new BigInteger("10"));
|
||||
} else if (units === "Nanoseconds (ns)") {
|
||||
input = input.divide(new BigInteger("100"));
|
||||
} else {
|
||||
throw "Unrecognised unit";
|
||||
}
|
||||
|
||||
input = input.add(new BigInteger("116444736000000000"));
|
||||
|
||||
if (format === "Hex"){
|
||||
return input.toString(16);
|
||||
} else {
|
||||
return input.toString();
|
||||
}
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
export default Filetime;
|
|
@ -125,30 +125,30 @@ const HTTP = {
|
|||
}
|
||||
|
||||
return fetch(url, config)
|
||||
.then(r => {
|
||||
if (r.status === 0 && r.type === "opaque") {
|
||||
return "Error: Null response. Try setting the connection mode to CORS.";
|
||||
}
|
||||
|
||||
if (showResponseMetadata) {
|
||||
let headers = "";
|
||||
for (let pair of r.headers.entries()) {
|
||||
headers += " " + pair[0] + ": " + pair[1] + "\n";
|
||||
.then(r => {
|
||||
if (r.status === 0 && r.type === "opaque") {
|
||||
return "Error: Null response. Try setting the connection mode to CORS.";
|
||||
}
|
||||
return r.text().then(b => {
|
||||
return "####\n Status: " + r.status + " " + r.statusText +
|
||||
"\n Exposed headers:\n" + headers + "####\n\n" + b;
|
||||
});
|
||||
}
|
||||
return r.text();
|
||||
})
|
||||
.catch(e => {
|
||||
return e.toString() +
|
||||
"\n\nThis error could be caused by one of the following:\n" +
|
||||
" - An invalid URL\n" +
|
||||
" - Making a request to an insecure resource (HTTP) from a secure source (HTTPS)\n" +
|
||||
" - Making a cross-origin request to a server which does not support CORS\n";
|
||||
});
|
||||
|
||||
if (showResponseMetadata) {
|
||||
let headers = "";
|
||||
for (let pair of r.headers.entries()) {
|
||||
headers += " " + pair[0] + ": " + pair[1] + "\n";
|
||||
}
|
||||
return r.text().then(b => {
|
||||
return "####\n Status: " + r.status + " " + r.statusText +
|
||||
"\n Exposed headers:\n" + headers + "####\n\n" + b;
|
||||
});
|
||||
}
|
||||
return r.text();
|
||||
})
|
||||
.catch(e => {
|
||||
return e.toString() +
|
||||
"\n\nThis error could be caused by one of the following:\n" +
|
||||
" - An invalid URL\n" +
|
||||
" - Making a request to an insecure resource (HTTP) from a secure source (HTTPS)\n" +
|
||||
" - Making a cross-origin request to a server which does not support CORS\n";
|
||||
});
|
||||
},
|
||||
|
||||
};
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import Utils from "../Utils.js";
|
||||
import CryptoJS from "crypto-js";
|
||||
import CryptoApi from "crypto-api";
|
||||
import MD6 from "node-md6";
|
||||
import * as SHA3 from "js-sha3";
|
||||
import Checksum from "./Checksum.js";
|
||||
|
||||
|
||||
|
@ -15,6 +16,22 @@ import Checksum from "./Checksum.js";
|
|||
*/
|
||||
const Hash = {
|
||||
|
||||
/**
|
||||
* Generic hash function.
|
||||
*
|
||||
* @param {string} name
|
||||
* @param {string} input
|
||||
* @returns {string}
|
||||
*/
|
||||
runHash: function(name, input) {
|
||||
const hasher = CryptoApi.hasher(name);
|
||||
hasher.state.message = input;
|
||||
hasher.state.length += input.length;
|
||||
hasher.process();
|
||||
return hasher.finalize().stringify("hex");
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* MD2 operation.
|
||||
*
|
||||
|
@ -23,7 +40,7 @@ const Hash = {
|
|||
* @returns {string}
|
||||
*/
|
||||
runMD2: function (input, args) {
|
||||
return Utils.toHexFast(CryptoApi.hash("md2", input, {}));
|
||||
return Hash.runHash("md2", input);
|
||||
},
|
||||
|
||||
|
||||
|
@ -35,7 +52,7 @@ const Hash = {
|
|||
* @returns {string}
|
||||
*/
|
||||
runMD4: function (input, args) {
|
||||
return Utils.toHexFast(CryptoApi.hash("md4", input, {}));
|
||||
return Hash.runHash("md4", input);
|
||||
},
|
||||
|
||||
|
||||
|
@ -47,8 +64,39 @@ const Hash = {
|
|||
* @returns {string}
|
||||
*/
|
||||
runMD5: function (input, args) {
|
||||
input = CryptoJS.enc.Latin1.parse(input); // Cast to WordArray
|
||||
return CryptoJS.MD5(input).toString(CryptoJS.enc.Hex);
|
||||
return Hash.runHash("md5", input);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
MD6_SIZE: 256,
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
MD6_LEVELS: 64,
|
||||
|
||||
/**
|
||||
* MD6 operation.
|
||||
*
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
runMD6: function (input, args) {
|
||||
const size = args[0],
|
||||
levels = args[1],
|
||||
key = args[2];
|
||||
|
||||
if (size < 0 || size > 512)
|
||||
return "Size must be between 0 and 512";
|
||||
if (levels < 0)
|
||||
return "Levels must be greater than 0";
|
||||
|
||||
return MD6.getHashOfText(input, size, key, levels);
|
||||
},
|
||||
|
||||
|
||||
|
@ -60,7 +108,7 @@ const Hash = {
|
|||
* @returns {string}
|
||||
*/
|
||||
runSHA0: function (input, args) {
|
||||
return Utils.toHexFast(CryptoApi.hash("sha0", input, {}));
|
||||
return Hash.runHash("sha0", input);
|
||||
},
|
||||
|
||||
|
||||
|
@ -72,60 +120,7 @@ const Hash = {
|
|||
* @returns {string}
|
||||
*/
|
||||
runSHA1: function (input, args) {
|
||||
input = CryptoJS.enc.Latin1.parse(input);
|
||||
return CryptoJS.SHA1(input).toString(CryptoJS.enc.Hex);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* SHA224 operation.
|
||||
*
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
runSHA224: function (input, args) {
|
||||
input = CryptoJS.enc.Latin1.parse(input);
|
||||
return CryptoJS.SHA224(input).toString(CryptoJS.enc.Hex);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* SHA256 operation.
|
||||
*
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
runSHA256: function (input, args) {
|
||||
input = CryptoJS.enc.Latin1.parse(input);
|
||||
return CryptoJS.SHA256(input).toString(CryptoJS.enc.Hex);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* SHA384 operation.
|
||||
*
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
runSHA384: function (input, args) {
|
||||
input = CryptoJS.enc.Latin1.parse(input);
|
||||
return CryptoJS.SHA384(input).toString(CryptoJS.enc.Hex);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* SHA512 operation.
|
||||
*
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
runSHA512: function (input, args) {
|
||||
input = CryptoJS.enc.Latin1.parse(input);
|
||||
return CryptoJS.SHA512(input).toString(CryptoJS.enc.Hex);
|
||||
return Hash.runHash("sha1", input);
|
||||
},
|
||||
|
||||
|
||||
|
@ -133,7 +128,26 @@ const Hash = {
|
|||
* @constant
|
||||
* @default
|
||||
*/
|
||||
SHA3_LENGTH: ["512", "384", "256", "224"],
|
||||
SHA2_SIZE: ["512", "256", "384", "224", "512/256", "512/224"],
|
||||
|
||||
/**
|
||||
* SHA2 operation.
|
||||
*
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
runSHA2: function (input, args) {
|
||||
const size = args[0];
|
||||
return Hash.runHash("sha" + size, input);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
SHA3_SIZE: ["512", "384", "256", "224"],
|
||||
|
||||
/**
|
||||
* SHA3 operation.
|
||||
|
@ -143,25 +157,27 @@ const Hash = {
|
|||
* @returns {string}
|
||||
*/
|
||||
runSHA3: function (input, args) {
|
||||
input = CryptoJS.enc.Latin1.parse(input);
|
||||
let sha3Length = args[0],
|
||||
options = {
|
||||
outputLength: parseInt(sha3Length, 10)
|
||||
};
|
||||
return CryptoJS.SHA3(input, options).toString(CryptoJS.enc.Hex);
|
||||
},
|
||||
const size = parseInt(args[0], 10);
|
||||
let algo;
|
||||
|
||||
switch (size) {
|
||||
case 224:
|
||||
algo = SHA3.sha3_224;
|
||||
break;
|
||||
case 384:
|
||||
algo = SHA3.sha3_384;
|
||||
break;
|
||||
case 256:
|
||||
algo = SHA3.sha3_256;
|
||||
break;
|
||||
case 512:
|
||||
algo = SHA3.sha3_512;
|
||||
break;
|
||||
default:
|
||||
return "Invalid size";
|
||||
}
|
||||
|
||||
/**
|
||||
* RIPEMD-160 operation.
|
||||
*
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
runRIPEMD160: function (input, args) {
|
||||
input = CryptoJS.enc.Latin1.parse(input);
|
||||
return CryptoJS.RIPEMD160(input).toString(CryptoJS.enc.Hex);
|
||||
return algo(input);
|
||||
},
|
||||
|
||||
|
||||
|
@ -169,7 +185,181 @@ const Hash = {
|
|||
* @constant
|
||||
* @default
|
||||
*/
|
||||
HMAC_FUNCTIONS: ["MD5", "SHA1", "SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "RIPEMD-160"],
|
||||
KECCAK_SIZE: ["512", "384", "256", "224"],
|
||||
|
||||
/**
|
||||
* Keccak operation.
|
||||
*
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
runKeccak: function (input, args) {
|
||||
const size = parseInt(args[0], 10);
|
||||
let algo;
|
||||
|
||||
switch (size) {
|
||||
case 224:
|
||||
algo = SHA3.keccak224;
|
||||
break;
|
||||
case 384:
|
||||
algo = SHA3.keccak384;
|
||||
break;
|
||||
case 256:
|
||||
algo = SHA3.keccak256;
|
||||
break;
|
||||
case 512:
|
||||
algo = SHA3.keccak512;
|
||||
break;
|
||||
default:
|
||||
return "Invalid size";
|
||||
}
|
||||
|
||||
return algo(input);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
SHAKE_CAPACITY: ["256", "128"],
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
SHAKE_SIZE: 512,
|
||||
|
||||
/**
|
||||
* Shake operation.
|
||||
*
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
runShake: function (input, args) {
|
||||
const capacity = parseInt(args[0], 10),
|
||||
size = args[1];
|
||||
let algo;
|
||||
|
||||
if (size < 0)
|
||||
return "Size must be greater than 0";
|
||||
|
||||
switch (capacity) {
|
||||
case 128:
|
||||
algo = SHA3.shake128;
|
||||
break;
|
||||
case 256:
|
||||
algo = SHA3.shake256;
|
||||
break;
|
||||
default:
|
||||
return "Invalid size";
|
||||
}
|
||||
|
||||
return algo(input, size);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
RIPEMD_SIZE: ["320", "256", "160", "128"],
|
||||
|
||||
/**
|
||||
* RIPEMD operation.
|
||||
*
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
runRIPEMD: function (input, args) {
|
||||
const size = args[0];
|
||||
return Hash.runHash("ripemd" + size, input);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* HAS-160 operation.
|
||||
*
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
runHAS: function (input, args) {
|
||||
return Hash.runHash("has160", input);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
WHIRLPOOL_VARIANT: ["Whirlpool", "Whirlpool-T", "Whirlpool-0"],
|
||||
|
||||
/**
|
||||
* Whirlpool operation.
|
||||
*
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
runWhirlpool: function (input, args) {
|
||||
const variant = args[0].toLowerCase();
|
||||
return Hash.runHash(variant, input);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
SNEFRU_ROUNDS: ["8", "4", "2"],
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
SNEFRU_SIZE: ["256", "128"],
|
||||
|
||||
/**
|
||||
* Snefru operation.
|
||||
*
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
runSnefru: function (input, args) {
|
||||
const rounds = args[0],
|
||||
size = args[1];
|
||||
return Hash.runHash(`snefru-${rounds}-${size}`, input);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
HMAC_FUNCTIONS: [
|
||||
"MD2",
|
||||
"MD4",
|
||||
"MD5",
|
||||
"SHA0",
|
||||
"SHA1",
|
||||
"SHA224",
|
||||
"SHA256",
|
||||
"SHA384",
|
||||
"SHA512",
|
||||
"SHA512/224",
|
||||
"SHA512/256",
|
||||
"RIPEMD128",
|
||||
"RIPEMD160",
|
||||
"RIPEMD256",
|
||||
"RIPEMD320",
|
||||
"HAS160",
|
||||
"Whirlpool",
|
||||
"Whirlpool-0",
|
||||
"Whirlpool-T"
|
||||
],
|
||||
|
||||
/**
|
||||
* HMAC operation.
|
||||
|
@ -179,19 +369,12 @@ const Hash = {
|
|||
* @returns {string}
|
||||
*/
|
||||
runHMAC: function (input, args) {
|
||||
const hashFunc = args[1];
|
||||
input = CryptoJS.enc.Latin1.parse(input);
|
||||
const execute = {
|
||||
"MD5": CryptoJS.HmacMD5(input, args[0]),
|
||||
"SHA1": CryptoJS.HmacSHA1(input, args[0]),
|
||||
"SHA224": CryptoJS.HmacSHA224(input, args[0]),
|
||||
"SHA256": CryptoJS.HmacSHA256(input, args[0]),
|
||||
"SHA384": CryptoJS.HmacSHA384(input, args[0]),
|
||||
"SHA512": CryptoJS.HmacSHA512(input, args[0]),
|
||||
"SHA3": CryptoJS.HmacSHA3(input, args[0]),
|
||||
"RIPEMD-160": CryptoJS.HmacRIPEMD160(input, args[0]),
|
||||
};
|
||||
return execute[hashFunc].toString(CryptoJS.enc.Hex);
|
||||
const password = args[0],
|
||||
hashFunc = args[1].toLowerCase(),
|
||||
hmac = CryptoApi.mac("hmac", password, hashFunc, {});
|
||||
|
||||
hmac.update(input);
|
||||
return hmac.finalize().stringify("hex");
|
||||
},
|
||||
|
||||
|
||||
|
@ -207,24 +390,39 @@ const Hash = {
|
|||
output = "MD2: " + Hash.runMD2(input, []) +
|
||||
"\nMD4: " + Hash.runMD4(input, []) +
|
||||
"\nMD5: " + Hash.runMD5(input, []) +
|
||||
"\nMD6: " + Hash.runMD6(input, []) +
|
||||
"\nSHA0: " + Hash.runSHA0(input, []) +
|
||||
"\nSHA1: " + Hash.runSHA1(input, []) +
|
||||
"\nSHA2 224: " + Hash.runSHA224(input, []) +
|
||||
"\nSHA2 256: " + Hash.runSHA256(input, []) +
|
||||
"\nSHA2 384: " + Hash.runSHA384(input, []) +
|
||||
"\nSHA2 512: " + Hash.runSHA512(input, []) +
|
||||
"\nSHA2 224: " + Hash.runSHA2(input, ["224"]) +
|
||||
"\nSHA2 256: " + Hash.runSHA2(input, ["256"]) +
|
||||
"\nSHA2 384: " + Hash.runSHA2(input, ["384"]) +
|
||||
"\nSHA2 512: " + Hash.runSHA2(input, ["512"]) +
|
||||
"\nSHA3 224: " + Hash.runSHA3(input, ["224"]) +
|
||||
"\nSHA3 256: " + Hash.runSHA3(input, ["256"]) +
|
||||
"\nSHA3 384: " + Hash.runSHA3(input, ["384"]) +
|
||||
"\nSHA3 512: " + Hash.runSHA3(input, ["512"]) +
|
||||
"\nRIPEMD-160: " + Hash.runRIPEMD160(input, []) +
|
||||
"\nKeccak 224: " + Hash.runKeccak(input, ["224"]) +
|
||||
"\nKeccak 256: " + Hash.runKeccak(input, ["256"]) +
|
||||
"\nKeccak 384: " + Hash.runKeccak(input, ["384"]) +
|
||||
"\nKeccak 512: " + Hash.runKeccak(input, ["512"]) +
|
||||
"\nShake 128: " + Hash.runShake(input, ["128", 256]) +
|
||||
"\nShake 256: " + Hash.runShake(input, ["256", 512]) +
|
||||
"\nRIPEMD-128: " + Hash.runRIPEMD(input, ["128"]) +
|
||||
"\nRIPEMD-160: " + Hash.runRIPEMD(input, ["160"]) +
|
||||
"\nRIPEMD-256: " + Hash.runRIPEMD(input, ["256"]) +
|
||||
"\nRIPEMD-320: " + Hash.runRIPEMD(input, ["320"]) +
|
||||
"\nHAS-160: " + Hash.runHAS(input, []) +
|
||||
"\nWhirlpool-0: " + Hash.runWhirlpool(input, ["Whirlpool-0"]) +
|
||||
"\nWhirlpool-T: " + Hash.runWhirlpool(input, ["Whirlpool-T"]) +
|
||||
"\nWhirlpool: " + Hash.runWhirlpool(input, ["Whirlpool"]) +
|
||||
"\n\nChecksums:" +
|
||||
"\nFletcher-8: " + Checksum.runFletcher8(byteArray, []) +
|
||||
"\nFletcher-16: " + Checksum.runFletcher16(byteArray, []) +
|
||||
"\nFletcher-32: " + Checksum.runFletcher32(byteArray, []) +
|
||||
"\nFletcher-64: " + Checksum.runFletcher64(byteArray, []) +
|
||||
"\nAdler-32: " + Checksum.runAdler32(byteArray, []) +
|
||||
"\nCRC-32: " + Checksum.runCRC32(byteArray, []);
|
||||
"\nCRC-16: " + Checksum.runCRC16(input, []) +
|
||||
"\nCRC-32: " + Checksum.runCRC32(input, []);
|
||||
|
||||
return output;
|
||||
},
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
/* globals app */
|
||||
import Utils from "../Utils.js";
|
||||
|
||||
|
||||
|
@ -92,7 +91,7 @@ const Hexdump = {
|
|||
const w = (width - 13) / 4;
|
||||
// w should be the specified width of the hexdump and therefore a round number
|
||||
if (Math.floor(w) !== w || input.indexOf("\r") !== -1 || output.indexOf(13) !== -1) {
|
||||
if (app) app.options.attemptHighlight = false;
|
||||
if (ENVIRONMENT_IS_WORKER()) self.setOption("attemptHighlight", false);
|
||||
}
|
||||
return output;
|
||||
},
|
||||
|
|
|
@ -283,7 +283,7 @@ const IP = {
|
|||
baIp.push(decimal & 255);
|
||||
break;
|
||||
case "Hex":
|
||||
baIp = Utils.hexToByteArray(lines[i]);
|
||||
baIp = Utils.fromHex(lines[i]);
|
||||
break;
|
||||
default:
|
||||
throw "Unsupported input IP format";
|
||||
|
@ -516,7 +516,7 @@ const IP = {
|
|||
"<tr><td>Destination IP address</td><td>" + IP._ipv4ToStr(dstIP) + "</td></tr>";
|
||||
|
||||
if (ihl > 5) {
|
||||
output += "<tr><td>Options</td><td>" + Utils.byteArrayToHex(options) + "</td></tr>";
|
||||
output += "<tr><td>Options</td><td>" + Utils.toHex(options) + "</td></tr>";
|
||||
}
|
||||
|
||||
return output + "</table>";
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import esprima from "esprima";
|
||||
import * as esprima from "esprima";
|
||||
import escodegen from "escodegen";
|
||||
import esmangle from "esmangle";
|
||||
|
||||
|
@ -62,7 +62,7 @@ const JS = {
|
|||
tolerant: parseTolerant
|
||||
};
|
||||
|
||||
result = esprima.parse(input, options);
|
||||
result = esprima.parseScript(input, options);
|
||||
return JSON.stringify(result, null, 2);
|
||||
},
|
||||
|
||||
|
@ -104,7 +104,7 @@ const JS = {
|
|||
AST;
|
||||
|
||||
try {
|
||||
AST = esprima.parse(input, {
|
||||
AST = esprima.parseScript(input, {
|
||||
range: true,
|
||||
tokens: true,
|
||||
comment: true
|
||||
|
@ -142,7 +142,7 @@ const JS = {
|
|||
*/
|
||||
runMinify: function(input, args) {
|
||||
let result = "",
|
||||
AST = esprima.parse(input),
|
||||
AST = esprima.parseScript(input),
|
||||
optimisedAST = esmangle.optimize(AST, null),
|
||||
mangledAST = esmangle.mangle(optimisedAST);
|
||||
|
||||
|
|
213
src/core/operations/MS.js
Normal file
|
@ -0,0 +1,213 @@
|
|||
/**
|
||||
* Microsoft operations.
|
||||
*
|
||||
* @author bmwhitn [brian.m.whitney@outlook.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*
|
||||
* @namespace
|
||||
*/
|
||||
const MS = {
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
D_DECODE: [
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"\x57\x6E\x7B",
|
||||
"\x4A\x4C\x41",
|
||||
"\x0B\x0B\x0B",
|
||||
"\x0C\x0C\x0C",
|
||||
"\x4A\x4C\x41",
|
||||
"\x0E\x0E\x0E",
|
||||
"\x0F\x0F\x0F",
|
||||
"\x10\x10\x10",
|
||||
"\x11\x11\x11",
|
||||
"\x12\x12\x12",
|
||||
"\x13\x13\x13",
|
||||
"\x14\x14\x14",
|
||||
"\x15\x15\x15",
|
||||
"\x16\x16\x16",
|
||||
"\x17\x17\x17",
|
||||
"\x18\x18\x18",
|
||||
"\x19\x19\x19",
|
||||
"\x1A\x1A\x1A",
|
||||
"\x1B\x1B\x1B",
|
||||
"\x1C\x1C\x1C",
|
||||
"\x1D\x1D\x1D",
|
||||
"\x1E\x1E\x1E",
|
||||
"\x1F\x1F\x1F",
|
||||
"\x2E\x2D\x32",
|
||||
"\x47\x75\x30",
|
||||
"\x7A\x52\x21",
|
||||
"\x56\x60\x29",
|
||||
"\x42\x71\x5B",
|
||||
"\x6A\x5E\x38",
|
||||
"\x2F\x49\x33",
|
||||
"\x26\x5C\x3D",
|
||||
"\x49\x62\x58",
|
||||
"\x41\x7D\x3A",
|
||||
"\x34\x29\x35",
|
||||
"\x32\x36\x65",
|
||||
"\x5B\x20\x39",
|
||||
"\x76\x7C\x5C",
|
||||
"\x72\x7A\x56",
|
||||
"\x43\x7F\x73",
|
||||
"\x38\x6B\x66",
|
||||
"\x39\x63\x4E",
|
||||
"\x70\x33\x45",
|
||||
"\x45\x2B\x6B",
|
||||
"\x68\x68\x62",
|
||||
"\x71\x51\x59",
|
||||
"\x4F\x66\x78",
|
||||
"\x09\x76\x5E",
|
||||
"\x62\x31\x7D",
|
||||
"\x44\x64\x4A",
|
||||
"\x23\x54\x6D",
|
||||
"\x75\x43\x71",
|
||||
"\x4A\x4C\x41",
|
||||
"\x7E\x3A\x60",
|
||||
"\x4A\x4C\x41",
|
||||
"\x5E\x7E\x53",
|
||||
"\x40\x4C\x40",
|
||||
"\x77\x45\x42",
|
||||
"\x4A\x2C\x27",
|
||||
"\x61\x2A\x48",
|
||||
"\x5D\x74\x72",
|
||||
"\x22\x27\x75",
|
||||
"\x4B\x37\x31",
|
||||
"\x6F\x44\x37",
|
||||
"\x4E\x79\x4D",
|
||||
"\x3B\x59\x52",
|
||||
"\x4C\x2F\x22",
|
||||
"\x50\x6F\x54",
|
||||
"\x67\x26\x6A",
|
||||
"\x2A\x72\x47",
|
||||
"\x7D\x6A\x64",
|
||||
"\x74\x39\x2D",
|
||||
"\x54\x7B\x20",
|
||||
"\x2B\x3F\x7F",
|
||||
"\x2D\x38\x2E",
|
||||
"\x2C\x77\x4C",
|
||||
"\x30\x67\x5D",
|
||||
"\x6E\x53\x7E",
|
||||
"\x6B\x47\x6C",
|
||||
"\x66\x34\x6F",
|
||||
"\x35\x78\x79",
|
||||
"\x25\x5D\x74",
|
||||
"\x21\x30\x43",
|
||||
"\x64\x23\x26",
|
||||
"\x4D\x5A\x76",
|
||||
"\x52\x5B\x25",
|
||||
"\x63\x6C\x24",
|
||||
"\x3F\x48\x2B",
|
||||
"\x7B\x55\x28",
|
||||
"\x78\x70\x23",
|
||||
"\x29\x69\x41",
|
||||
"\x28\x2E\x34",
|
||||
"\x73\x4C\x09",
|
||||
"\x59\x21\x2A",
|
||||
"\x33\x24\x44",
|
||||
"\x7F\x4E\x3F",
|
||||
"\x6D\x50\x77",
|
||||
"\x55\x09\x3B",
|
||||
"\x53\x56\x55",
|
||||
"\x7C\x73\x69",
|
||||
"\x3A\x35\x61",
|
||||
"\x5F\x61\x63",
|
||||
"\x65\x4B\x50",
|
||||
"\x46\x58\x67",
|
||||
"\x58\x3B\x51",
|
||||
"\x31\x57\x49",
|
||||
"\x69\x22\x4F",
|
||||
"\x6C\x6D\x46",
|
||||
"\x5A\x4D\x68",
|
||||
"\x48\x25\x7C",
|
||||
"\x27\x28\x36",
|
||||
"\x5C\x46\x70",
|
||||
"\x3D\x4A\x6E",
|
||||
"\x24\x32\x7A",
|
||||
"\x79\x41\x2F",
|
||||
"\x37\x3D\x5F",
|
||||
"\x60\x5F\x4B",
|
||||
"\x51\x4F\x5A",
|
||||
"\x20\x42\x2C",
|
||||
"\x36\x65\x57"
|
||||
],
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
D_COMBINATION: [
|
||||
0, 1, 2, 0, 1, 2, 1, 2, 2, 1, 2, 1, 0, 2, 1, 2, 0, 2, 1, 2, 0, 0, 1, 2, 2, 1, 0, 2, 1, 2, 2, 1,
|
||||
0, 0, 2, 1, 2, 1, 2, 0, 2, 0, 0, 1, 2, 0, 2, 1, 0, 2, 1, 2, 0, 0, 1, 2, 2, 0, 0, 1, 2, 0, 2, 1
|
||||
],
|
||||
|
||||
|
||||
/**
|
||||
* Decodes Microsoft Encoded Script files that can be read and executed by cscript.exe/wscript.exe.
|
||||
* This is a conversion of a Python script that was originally created by Didier Stevens
|
||||
* (https://DidierStevens.com).
|
||||
*
|
||||
* @private
|
||||
* @param {string} data
|
||||
* @returns {string}
|
||||
*/
|
||||
_decode: function (data) {
|
||||
let result = [];
|
||||
let index = -1;
|
||||
data = data.replace(/@&/g, String.fromCharCode(10))
|
||||
.replace(/@#/g, String.fromCharCode(13))
|
||||
.replace(/@\*/g, ">")
|
||||
.replace(/@!/g, "<")
|
||||
.replace(/@\$/g, "@");
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
let byte = data.charCodeAt(i);
|
||||
let char = data.charAt(i);
|
||||
if (byte < 128) {
|
||||
index++;
|
||||
}
|
||||
|
||||
if ((byte === 9 || byte > 31 && byte < 128) &&
|
||||
byte !== 60 &&
|
||||
byte !== 62 &&
|
||||
byte !== 64) {
|
||||
char = MS.D_DECODE[byte].charAt(MS.D_COMBINATION[index % 64]);
|
||||
}
|
||||
result.push(char);
|
||||
}
|
||||
return result.join("");
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Microsoft Script Decoder operation.
|
||||
*
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
runDecodeScript: function (input, args) {
|
||||
let matcher = /#@~\^.{6}==(.+).{6}==\^#~@/;
|
||||
let encodedData = matcher.exec(input);
|
||||
if (encodedData){
|
||||
return MS._decode(encodedData[1]);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
export default MS;
|
|
@ -18,25 +18,25 @@ const OS = {
|
|||
*/
|
||||
runParseUnixPerms: function(input, args) {
|
||||
let perms = {
|
||||
d : false, // directory
|
||||
sl : false, // symbolic link
|
||||
np : false, // named pipe
|
||||
s : false, // socket
|
||||
cd : false, // character device
|
||||
bd : false, // block device
|
||||
dr : false, // door
|
||||
sb : false, // sticky bit
|
||||
su : false, // setuid
|
||||
sg : false, // setgid
|
||||
ru : false, // read user
|
||||
wu : false, // write user
|
||||
eu : false, // execute user
|
||||
rg : false, // read group
|
||||
wg : false, // write group
|
||||
eg : false, // execute group
|
||||
ro : false, // read other
|
||||
wo : false, // write other
|
||||
eo : false // execute other
|
||||
d: false, // directory
|
||||
sl: false, // symbolic link
|
||||
np: false, // named pipe
|
||||
s: false, // socket
|
||||
cd: false, // character device
|
||||
bd: false, // block device
|
||||
dr: false, // door
|
||||
sb: false, // sticky bit
|
||||
su: false, // setuid
|
||||
sg: false, // setgid
|
||||
ru: false, // read user
|
||||
wu: false, // write user
|
||||
eu: false, // execute user
|
||||
rg: false, // read group
|
||||
wg: false, // write group
|
||||
eg: false, // execute group
|
||||
ro: false, // read other
|
||||
wo: false, // write other
|
||||
eo: false // execute other
|
||||
},
|
||||
d = 0,
|
||||
u = 0,
|
||||
|
|
55
src/core/operations/OTP.js
Executable file
|
@ -0,0 +1,55 @@
|
|||
import otp from "otp";
|
||||
import Base64 from "./Base64.js";
|
||||
|
||||
/**
|
||||
* One-Time Password operations.
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*
|
||||
* @namespace
|
||||
*/
|
||||
const OTP = {
|
||||
|
||||
/**
|
||||
* Generate TOTP operation.
|
||||
*
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
runTOTP: function(input, args) {
|
||||
const otpObj = otp({
|
||||
name: args[0],
|
||||
keySize: args[1],
|
||||
codeLength: args[2],
|
||||
secret: Base64.runTo32(input, []),
|
||||
epoch: args[3],
|
||||
timeSlice: args[4]
|
||||
});
|
||||
return `URI: ${otpObj.totpURL}\n\nPassword: ${otpObj.totp()}`;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Generate HOTP operation.
|
||||
*
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
runHOTP: function(input, args) {
|
||||
const otpObj = otp({
|
||||
name: args[0],
|
||||
keySize: args[1],
|
||||
codeLength: args[2],
|
||||
secret: Base64.runTo32(input, []),
|
||||
});
|
||||
const counter = args[3];
|
||||
return `URI: ${otpObj.hotpURL}\n\nPassword: ${otpObj.hotp(counter)}`;
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
export default OTP;
|
|
@ -27,52 +27,47 @@ const PublicKey = {
|
|||
* @returns {string}
|
||||
*/
|
||||
runParseX509: function (input, args) {
|
||||
let cert = new r.X509(),
|
||||
inputFormat = args[0];
|
||||
|
||||
if (!input.length) {
|
||||
return "No input";
|
||||
}
|
||||
|
||||
let cert = new r.X509(),
|
||||
inputFormat = args[0];
|
||||
|
||||
switch (inputFormat) {
|
||||
case "DER Hex":
|
||||
input = input.replace(/\s/g, "");
|
||||
cert.hex = input;
|
||||
cert.pem = r.KJUR.asn1.ASN1Util.getPEMStringFromHex(input, "CERTIFICATE");
|
||||
cert.readCertHex(input);
|
||||
break;
|
||||
case "PEM":
|
||||
cert.hex = r.X509.pemToHex(input);
|
||||
cert.pem = input;
|
||||
cert.readCertPEM(input);
|
||||
break;
|
||||
case "Base64":
|
||||
cert.hex = Utils.toHex(Utils.fromBase64(input, null, "byteArray"), "");
|
||||
cert.pem = r.KJUR.asn1.ASN1Util.getPEMStringFromHex(cert.hex, "CERTIFICATE");
|
||||
cert.readCertHex(Utils.toHex(Utils.fromBase64(input, null, "byteArray"), ""));
|
||||
break;
|
||||
case "Raw":
|
||||
cert.hex = Utils.toHex(Utils.strToByteArray(input), "");
|
||||
cert.pem = r.KJUR.asn1.ASN1Util.getPEMStringFromHex(cert.hex, "CERTIFICATE");
|
||||
cert.readCertHex(Utils.toHex(Utils.strToByteArray(input), ""));
|
||||
break;
|
||||
default:
|
||||
throw "Undefined input format";
|
||||
}
|
||||
|
||||
let version = r.ASN1HEX.getDecendantHexVByNthList(cert.hex, 0, [0, 0, 0]),
|
||||
sn = cert.getSerialNumberHex(),
|
||||
algorithm = r.KJUR.asn1.x509.OID.oid2name(r.KJUR.asn1.ASN1Util.oidHexToInt(r.ASN1HEX.getDecendantHexVByNthList(cert.hex, 0, [0, 2, 0]))),
|
||||
let sn = cert.getSerialNumberHex(),
|
||||
issuer = cert.getIssuerString(),
|
||||
notBefore = cert.getNotBefore(),
|
||||
notAfter = cert.getNotAfter(),
|
||||
subject = cert.getSubjectString(),
|
||||
pkAlgorithm = r.KJUR.asn1.x509.OID.oid2name(r.KJUR.asn1.ASN1Util.oidHexToInt(r.ASN1HEX.getDecendantHexVByNthList(cert.hex, 0, [0, 6, 0, 0]))),
|
||||
pk = r.X509.getPublicKeyFromCertPEM(cert.pem),
|
||||
pk = cert.getPublicKey(),
|
||||
pkFields = [],
|
||||
pkStr = "",
|
||||
certSigAlg = r.KJUR.asn1.x509.OID.oid2name(r.KJUR.asn1.ASN1Util.oidHexToInt(r.ASN1HEX.getDecendantHexVByNthList(cert.hex, 0, [1, 0]))),
|
||||
certSig = r.ASN1HEX.getDecendantHexVByNthList(cert.hex, 0, [2]).substr(2),
|
||||
sig = cert.getSignatureValueHex(),
|
||||
sigStr = "",
|
||||
extensions = r.ASN1HEX.dump(r.ASN1HEX.getDecendantHexVByNthList(cert.hex, 0, [0, 7]));
|
||||
extensions = cert.getInfo().split("X509v3 Extensions:\n")[1].split("signature")[0];
|
||||
|
||||
// Public Key fields
|
||||
pkFields.push({
|
||||
key: "Algorithm",
|
||||
value: pk.type
|
||||
});
|
||||
|
||||
if (pk.type === "EC") { // ECDSA
|
||||
pkFields.push({
|
||||
key: "Curve Name",
|
||||
|
@ -123,21 +118,6 @@ const PublicKey = {
|
|||
});
|
||||
}
|
||||
|
||||
// Signature fields
|
||||
let breakoutSig = false;
|
||||
try {
|
||||
breakoutSig = r.ASN1HEX.dump(certSig).indexOf("SEQUENCE") === 0;
|
||||
} catch (err) {
|
||||
// Error processing signature, output without further breakout
|
||||
}
|
||||
|
||||
if (breakoutSig) { // DSA or ECDSA
|
||||
sigStr = " r: " + PublicKey._formatByteStr(r.ASN1HEX.getDecendantHexVByNthList(certSig, 0, [0]), 16, 18) + "\n" +
|
||||
" s: " + PublicKey._formatByteStr(r.ASN1HEX.getDecendantHexVByNthList(certSig, 0, [1]), 16, 18) + "\n";
|
||||
} else { // RSA or unknown
|
||||
sigStr = " Signature: " + PublicKey._formatByteStr(certSig, 16, 18) + "\n";
|
||||
}
|
||||
|
||||
// Format Public Key fields
|
||||
for (let i = 0; i < pkFields.length; i++) {
|
||||
pkStr += " " + pkFields[i].key + ":" +
|
||||
|
@ -148,31 +128,45 @@ const PublicKey = {
|
|||
);
|
||||
}
|
||||
|
||||
// Signature fields
|
||||
let breakoutSig = false;
|
||||
try {
|
||||
breakoutSig = r.ASN1HEX.dump(sig).indexOf("SEQUENCE") === 0;
|
||||
} catch (err) {
|
||||
// Error processing signature, output without further breakout
|
||||
}
|
||||
|
||||
if (breakoutSig) { // DSA or ECDSA
|
||||
sigStr = " r: " + PublicKey._formatByteStr(r.ASN1HEX.getV(sig, 4), 16, 18) + "\n" +
|
||||
" s: " + PublicKey._formatByteStr(r.ASN1HEX.getV(sig, 48), 16, 18);
|
||||
} else { // RSA or unknown
|
||||
sigStr = " Signature: " + PublicKey._formatByteStr(sig, 16, 18);
|
||||
}
|
||||
|
||||
|
||||
let issuerStr = PublicKey._formatDnStr(issuer, 2),
|
||||
nbDate = PublicKey._formatDate(notBefore),
|
||||
naDate = PublicKey._formatDate(notAfter),
|
||||
nbDate = PublicKey._formatDate(cert.getNotBefore()),
|
||||
naDate = PublicKey._formatDate(cert.getNotAfter()),
|
||||
subjectStr = PublicKey._formatDnStr(subject, 2);
|
||||
|
||||
const output = "Version: " + (parseInt(version, 16) + 1) + " (0x" + version + ")\n" +
|
||||
"Serial number: " + new r.BigInteger(sn, 16).toString() + " (0x" + sn + ")\n" +
|
||||
"Algorithm ID: " + algorithm + "\n" +
|
||||
"Validity\n" +
|
||||
" Not Before: " + nbDate + " (dd-mm-yy hh:mm:ss) (" + notBefore + ")\n" +
|
||||
" Not After: " + naDate + " (dd-mm-yy hh:mm:ss) (" + notAfter + ")\n" +
|
||||
"Issuer\n" +
|
||||
issuerStr +
|
||||
"Subject\n" +
|
||||
subjectStr +
|
||||
"Public Key\n" +
|
||||
" Algorithm: " + pkAlgorithm + "\n" +
|
||||
pkStr +
|
||||
"Certificate Signature\n" +
|
||||
" Algorithm: " + certSigAlg + "\n" +
|
||||
sigStr +
|
||||
"\nExtensions (parsed ASN.1)\n" +
|
||||
extensions;
|
||||
return `Version: ${cert.version} (0x${Utils.hex(cert.version - 1)})
|
||||
Serial number: ${new r.BigInteger(sn, 16).toString()} (0x${sn})
|
||||
Algorithm ID: ${cert.getSignatureAlgorithmField()}
|
||||
Validity
|
||||
Not Before: ${nbDate} (dd-mm-yy hh:mm:ss) (${cert.getNotBefore()})
|
||||
Not After: ${naDate} (dd-mm-yy hh:mm:ss) (${cert.getNotAfter()})
|
||||
Issuer
|
||||
${issuerStr}
|
||||
Subject
|
||||
${subjectStr}
|
||||
Public Key
|
||||
${pkStr.slice(0, -1)}
|
||||
Certificate Signature
|
||||
Algorithm: ${cert.getSignatureAlgorithmName()}
|
||||
${sigStr}
|
||||
|
||||
return output;
|
||||
Extensions
|
||||
${extensions}`;
|
||||
},
|
||||
|
||||
|
||||
|
@ -192,7 +186,9 @@ const PublicKey = {
|
|||
// Add footer so that the KEYUTIL function works
|
||||
input = input + "-----END CERTIFICATE-----";
|
||||
}
|
||||
return r.KEYUTIL.getHexFromPEM(input);
|
||||
let cert = new r.X509();
|
||||
cert.readCertPEM(input);
|
||||
return cert.hex;
|
||||
},
|
||||
|
||||
|
||||
|
@ -270,7 +266,7 @@ const PublicKey = {
|
|||
*/
|
||||
_formatDnStr: function(dnStr, indent) {
|
||||
let output = "",
|
||||
fields = dnStr.split(",/|"),
|
||||
fields = dnStr.substr(1).replace(/([^\\])\//g, "$1$1/").split(/[^\\]\//),
|
||||
maxKeyLen = 0,
|
||||
key,
|
||||
value,
|
||||
|
@ -295,7 +291,7 @@ const PublicKey = {
|
|||
output += Utils.padLeft(str, indent + str.length, " ");
|
||||
}
|
||||
|
||||
return output;
|
||||
return output.slice(0, -1);
|
||||
},
|
||||
|
||||
|
||||
|
@ -345,720 +341,3 @@ const PublicKey = {
|
|||
};
|
||||
|
||||
export default PublicKey;
|
||||
|
||||
|
||||
/**
|
||||
* Overwrite X509.hex2dn function so as to join RDNs with a string which can be split on without
|
||||
* causing problems later (I hope).
|
||||
*
|
||||
* @param {string} hDN - Hex DN string
|
||||
* @returns {string}
|
||||
*/
|
||||
r.X509.hex2dn = function(hDN) {
|
||||
let s = "";
|
||||
const a = r.ASN1HEX.getPosArrayOfChildren_AtObj(hDN, 0);
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
const hRDN = r.ASN1HEX.getHexOfTLV_AtObj(hDN, a[i]);
|
||||
s = s + ",/|" + r.X509.hex2rdn(hRDN);
|
||||
}
|
||||
return s;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Overwrite DN attribute lookup in jsrasign library with a much more complete version from
|
||||
* https://github.com/nfephp-org/nfephp/blob/master/libs/Common/Certificate/Oids.php
|
||||
*
|
||||
* Various duplicates commented out.
|
||||
*
|
||||
* @constant
|
||||
*/
|
||||
r.X509.DN_ATTRHEX = {
|
||||
"0603550403" : "commonName",
|
||||
"0603550404" : "surname",
|
||||
"0603550406" : "countryName",
|
||||
"0603550407" : "localityName",
|
||||
"0603550408" : "stateOrProvinceName",
|
||||
"0603550409" : "streetAddress",
|
||||
"060355040a" : "organizationName",
|
||||
"060355040b" : "organizationalUnitName",
|
||||
"060355040c" : "title",
|
||||
"0603550414" : "telephoneNumber",
|
||||
"060355042a" : "givenName",
|
||||
// "0603551d0e" : "id-ce-subjectKeyIdentifier",
|
||||
// "0603551d0f" : "id-ce-keyUsage",
|
||||
// "0603551d11" : "id-ce-subjectAltName",
|
||||
// "0603551d13" : "id-ce-basicConstraints",
|
||||
// "0603551d14" : "id-ce-cRLNumber",
|
||||
// "0603551d1f" : "id-ce-CRLDistributionPoints",
|
||||
// "0603551d20" : "id-ce-certificatePolicies",
|
||||
// "0603551d23" : "id-ce-authorityKeyIdentifier",
|
||||
// "0603551d25" : "id-ce-extKeyUsage",
|
||||
// "06032a864886f70d010901" : "Email",
|
||||
// "06032a864886f70d010101" : "RSAEncryption",
|
||||
// "06032a864886f70d010102" : "md2WithRSAEncryption",
|
||||
// "06032a864886f70d010104" : "md5withRSAEncryption",
|
||||
// "06032a864886f70d010105" : "SHA-1WithRSAEncryption",
|
||||
// "06032a8648ce380403" : "id-dsa-with-sha-1",
|
||||
// "06032b06010505070302" : "idKpClientAuth",
|
||||
// "06032b06010505070304" : "idKpSecurityemail",
|
||||
"06032b06010505070201" : "idCertificatePolicies",
|
||||
"06036086480186f8420101" : "netscape-cert-type",
|
||||
"06036086480186f8420102" : "netscape-base-url",
|
||||
"06036086480186f8420103" : "netscape-revocation-url",
|
||||
"06036086480186f8420104" : "netscape-ca-revocation-url",
|
||||
"06036086480186f8420107" : "netscape-cert-renewal-url",
|
||||
"06036086480186f8420108" : "netscape-ca-policy-url",
|
||||
"06036086480186f842010c" : "netscape-ssl-server-name",
|
||||
"06036086480186f842010d" : "netscape-comment",
|
||||
"0603604c010201" : "A1",
|
||||
"0603604c010203" : "A3",
|
||||
"0603604c01020110" : "Certification Practice Statement pointer",
|
||||
"0603604c010301" : "Dados do cert parte 1",
|
||||
"0603604c010305" : "Dados do cert parte 2",
|
||||
"0603604c010306" : "Dados do cert parte 3",
|
||||
"06030992268993f22c640119" : "domainComponent",
|
||||
"06032a24a0f2a07d01010a" : "Signet pilot",
|
||||
"06032a24a0f2a07d01010b" : "Signet intraNet",
|
||||
"06032a24a0f2a07d010102" : "Signet personal",
|
||||
"06032a24a0f2a07d010114" : "Signet securityPolicy",
|
||||
"06032a24a0f2a07d010103" : "Signet business",
|
||||
"06032a24a0f2a07d010104" : "Signet legal",
|
||||
"06032a24a497a35301640101" : "Certificates Australia policyIdentifier",
|
||||
"06032a85702201" : "seis-cp",
|
||||
"06032a8570220101" : "SEIS certificatePolicy-s10",
|
||||
"06032a85702202" : "SEIS pe",
|
||||
"06032a85702203" : "SEIS at",
|
||||
"06032a8570220301" : "SEIS at-personalIdentifier",
|
||||
"06032a8648ce380201" : "holdinstruction-none",
|
||||
"06032a8648ce380202" : "holdinstruction-callissuer",
|
||||
"06032a8648ce380203" : "holdinstruction-reject",
|
||||
"06032a8648ce380401" : "dsa",
|
||||
"06032a8648ce380403" : "dsaWithSha1",
|
||||
"06032a8648ce3d01" : "fieldType",
|
||||
"06032a8648ce3d0101" : "prime-field",
|
||||
"06032a8648ce3d0102" : "characteristic-two-field",
|
||||
"06032a8648ce3d010201" : "ecPublicKey",
|
||||
"06032a8648ce3d010203" : "characteristic-two-basis",
|
||||
"06032a8648ce3d01020301" : "onBasis",
|
||||
"06032a8648ce3d01020302" : "tpBasis",
|
||||
"06032a8648ce3d01020303" : "ppBasis",
|
||||
"06032a8648ce3d02" : "publicKeyType",
|
||||
"06032a8648ce3d0201" : "ecPublicKey",
|
||||
"06032a8648ce3e0201" : "dhPublicNumber",
|
||||
"06032a864886f67d07" : "nsn",
|
||||
"06032a864886f67d0741" : "nsn-ce",
|
||||
"06032a864886f67d074100" : "entrustVersInfo",
|
||||
"06032a864886f67d0742" : "nsn-alg",
|
||||
"06032a864886f67d07420a" : "cast5CBC",
|
||||
"06032a864886f67d07420b" : "cast5MAC",
|
||||
"06032a864886f67d07420c" : "pbeWithMD5AndCAST5-CBC",
|
||||
"06032a864886f67d07420d" : "passwordBasedMac",
|
||||
"06032a864886f67d074203" : "cast3CBC",
|
||||
"06032a864886f67d0743" : "nsn-oc",
|
||||
"06032a864886f67d074300" : "entrustUser",
|
||||
"06032a864886f67d0744" : "nsn-at",
|
||||
"06032a864886f67d074400" : "entrustCAInfo",
|
||||
"06032a864886f67d07440a" : "attributeCertificate",
|
||||
"06032a864886f70d0101" : "pkcs-1",
|
||||
"06032a864886f70d010101" : "rsaEncryption",
|
||||
"06032a864886f70d010102" : "md2withRSAEncryption",
|
||||
"06032a864886f70d010103" : "md4withRSAEncryption",
|
||||
"06032a864886f70d010104" : "md5withRSAEncryption",
|
||||
"06032a864886f70d010105" : "sha1withRSAEncryption",
|
||||
"06032a864886f70d010106" : "rsaOAEPEncryptionSET",
|
||||
"06032a864886f70d010910020b" : "SMIMEEncryptionKeyPreference",
|
||||
"06032a864886f70d010c" : "pkcs-12",
|
||||
"06032a864886f70d010c01" : "pkcs-12-PbeIds",
|
||||
"06032a864886f70d010c0101" : "pbeWithSHAAnd128BitRC4",
|
||||
"06032a864886f70d010c0102" : "pbeWithSHAAnd40BitRC4",
|
||||
"06032a864886f70d010c0103" : "pbeWithSHAAnd3-KeyTripleDES-CBC",
|
||||
"06032a864886f70d010c0104" : "pbeWithSHAAnd2-KeyTripleDES-CBC",
|
||||
"06032a864886f70d010c0105" : "pbeWithSHAAnd128BitRC2-CBC",
|
||||
"06032a864886f70d010c0106" : "pbeWithSHAAnd40BitRC2-CBC",
|
||||
"06032a864886f70d010c0a" : "pkcs-12Version1",
|
||||
"06032a864886f70d010c0a01" : "pkcs-12BadIds",
|
||||
"06032a864886f70d010c0a0101" : "pkcs-12-keyBag",
|
||||
"06032a864886f70d010c0a0102" : "pkcs-12-pkcs-8ShroudedKeyBag",
|
||||
"06032a864886f70d010c0a0103" : "pkcs-12-certBag",
|
||||
"06032a864886f70d010c0a0104" : "pkcs-12-crlBag",
|
||||
"06032a864886f70d010c0a0105" : "pkcs-12-secretBag",
|
||||
"06032a864886f70d010c0a0106" : "pkcs-12-safeContentsBag",
|
||||
"06032a864886f70d010c02" : "pkcs-12-ESPVKID",
|
||||
"06032a864886f70d010c0201" : "pkcs-12-PKCS8KeyShrouding",
|
||||
"06032a864886f70d010c03" : "pkcs-12-BagIds",
|
||||
"06032a864886f70d010c0301" : "pkcs-12-keyBagId",
|
||||
"06032a864886f70d010c0302" : "pkcs-12-certAndCRLBagId",
|
||||
"06032a864886f70d010c0303" : "pkcs-12-secretBagId",
|
||||
"06032a864886f70d010c0304" : "pkcs-12-safeContentsId",
|
||||
"06032a864886f70d010c0305" : "pkcs-12-pkcs-8ShroudedKeyBagId",
|
||||
"06032a864886f70d010c04" : "pkcs-12-CertBagID",
|
||||
"06032a864886f70d010c0401" : "pkcs-12-X509CertCRLBagID",
|
||||
"06032a864886f70d010c0402" : "pkcs-12-SDSICertBagID",
|
||||
"06032a864886f70d010c05" : "pkcs-12-OID",
|
||||
"06032a864886f70d010c0501" : "pkcs-12-PBEID",
|
||||
"06032a864886f70d010c050101" : "pkcs-12-PBEWithSha1And128BitRC4",
|
||||
"06032a864886f70d010c050102" : "pkcs-12-PBEWithSha1And40BitRC4",
|
||||
"06032a864886f70d010c050103" : "pkcs-12-PBEWithSha1AndTripleDESCBC",
|
||||
"06032a864886f70d010c050104" : "pkcs-12-PBEWithSha1And128BitRC2CBC",
|
||||
"06032a864886f70d010c050105" : "pkcs-12-PBEWithSha1And40BitRC2CBC",
|
||||
"06032a864886f70d010c050106" : "pkcs-12-PBEWithSha1AndRC4",
|
||||
"06032a864886f70d010c050107" : "pkcs-12-PBEWithSha1AndRC2CBC",
|
||||
"06032a864886f70d010c0502" : "pkcs-12-EnvelopingID",
|
||||
"06032a864886f70d010c050201" : "pkcs-12-RSAEncryptionWith128BitRC4",
|
||||
"06032a864886f70d010c050202" : "pkcs-12-RSAEncryptionWith40BitRC4",
|
||||
"06032a864886f70d010c050203" : "pkcs-12-RSAEncryptionWithTripleDES",
|
||||
"06032a864886f70d010c0503" : "pkcs-12-SignatureID",
|
||||
"06032a864886f70d010c050301" : "pkcs-12-RSASignatureWithSHA1Digest",
|
||||
"06032a864886f70d0103" : "pkcs-3",
|
||||
"06032a864886f70d010301" : "dhKeyAgreement",
|
||||
"06032a864886f70d0105" : "pkcs-5",
|
||||
"06032a864886f70d010501" : "pbeWithMD2AndDES-CBC",
|
||||
"06032a864886f70d01050a" : "pbeWithSHAAndDES-CBC",
|
||||
"06032a864886f70d010503" : "pbeWithMD5AndDES-CBC",
|
||||
"06032a864886f70d010504" : "pbeWithMD2AndRC2-CBC",
|
||||
"06032a864886f70d010506" : "pbeWithMD5AndRC2-CBC",
|
||||
"06032a864886f70d010509" : "pbeWithMD5AndXOR",
|
||||
"06032a864886f70d0107" : "pkcs-7",
|
||||
"06032a864886f70d010701" : "data",
|
||||
"06032a864886f70d010702" : "signedData",
|
||||
"06032a864886f70d010703" : "envelopedData",
|
||||
"06032a864886f70d010704" : "signedAndEnvelopedData",
|
||||
"06032a864886f70d010705" : "digestData",
|
||||
"06032a864886f70d010706" : "encryptedData",
|
||||
"06032a864886f70d010707" : "dataWithAttributes",
|
||||
"06032a864886f70d010708" : "encryptedPrivateKeyInfo",
|
||||
"06032a864886f70d0109" : "pkcs-9",
|
||||
"06032a864886f70d010901" : "emailAddress",
|
||||
"06032a864886f70d01090a" : "issuerAndSerialNumber",
|
||||
"06032a864886f70d01090b" : "passwordCheck",
|
||||
"06032a864886f70d01090c" : "publicKey",
|
||||
"06032a864886f70d01090d" : "signingDescription",
|
||||
"06032a864886f70d01090e" : "extensionReq",
|
||||
"06032a864886f70d01090f" : "sMIMECapabilities",
|
||||
"06032a864886f70d01090f01" : "preferSignedData",
|
||||
"06032a864886f70d01090f02" : "canNotDecryptAny",
|
||||
"06032a864886f70d01090f03" : "receiptRequest",
|
||||
"06032a864886f70d01090f04" : "receipt",
|
||||
"06032a864886f70d01090f05" : "contentHints",
|
||||
"06032a864886f70d01090f06" : "mlExpansionHistory",
|
||||
"06032a864886f70d010910" : "id-sMIME",
|
||||
"06032a864886f70d01091000" : "id-mod",
|
||||
"06032a864886f70d0109100001" : "id-mod-cms",
|
||||
"06032a864886f70d0109100002" : "id-mod-ess",
|
||||
"06032a864886f70d01091001" : "id-ct",
|
||||
"06032a864886f70d0109100101" : "id-ct-receipt",
|
||||
"06032a864886f70d01091002" : "id-aa",
|
||||
"06032a864886f70d0109100201" : "id-aa-receiptRequest",
|
||||
"06032a864886f70d0109100202" : "id-aa-securityLabel",
|
||||
"06032a864886f70d0109100203" : "id-aa-mlExpandHistory",
|
||||
"06032a864886f70d0109100204" : "id-aa-contentHint",
|
||||
"06032a864886f70d010902" : "unstructuredName",
|
||||
"06032a864886f70d010914" : "friendlyName",
|
||||
"06032a864886f70d010915" : "localKeyID",
|
||||
"06032a864886f70d010916" : "certTypes",
|
||||
"06032a864886f70d01091601" : "x509Certificate",
|
||||
"06032a864886f70d01091602" : "sdsiCertificate",
|
||||
"06032a864886f70d010917" : "crlTypes",
|
||||
"06032a864886f70d01091701" : "x509Crl",
|
||||
"06032a864886f70d010903" : "contentType",
|
||||
"06032a864886f70d010904" : "messageDigest",
|
||||
"06032a864886f70d010905" : "signingTime",
|
||||
"06032a864886f70d010906" : "countersignature",
|
||||
"06032a864886f70d010907" : "challengePassword",
|
||||
"06032a864886f70d010908" : "unstructuredAddress",
|
||||
"06032a864886f70d010909" : "extendedCertificateAttributes",
|
||||
"06032a864886f70d02" : "digestAlgorithm",
|
||||
"06032a864886f70d0202" : "md2",
|
||||
"06032a864886f70d0204" : "md4",
|
||||
"06032a864886f70d0205" : "md5",
|
||||
"06032a864886f70d03" : "encryptionAlgorithm",
|
||||
"06032a864886f70d030a" : "desCDMF",
|
||||
"06032a864886f70d0302" : "rc2CBC",
|
||||
"06032a864886f70d0303" : "rc2ECB",
|
||||
"06032a864886f70d0304" : "rc4",
|
||||
"06032a864886f70d0305" : "rc4WithMAC",
|
||||
"06032a864886f70d0306" : "DESX-CBC",
|
||||
"06032a864886f70d0307" : "DES-EDE3-CBC",
|
||||
"06032a864886f70d0308" : "RC5CBC",
|
||||
"06032a864886f70d0309" : "RC5-CBCPad",
|
||||
"06032a864886f7140403" : "microsoftExcel",
|
||||
"06032a864886f7140404" : "titledWithOID",
|
||||
"06032a864886f7140405" : "microsoftPowerPoint",
|
||||
"06032b81051086480954" : "x9-84",
|
||||
"06032b8105108648095400" : "x9-84-Module",
|
||||
"06032b810510864809540001" : "x9-84-Biometrics",
|
||||
"06032b810510864809540002" : "x9-84-CMS",
|
||||
"06032b810510864809540003" : "x9-84-Identifiers",
|
||||
"06032b8105108648095401" : "biometric",
|
||||
"06032b810510864809540100" : "id-unknown-Type",
|
||||
"06032b810510864809540101" : "id-body-Odor",
|
||||
"06032b81051086480954010a" : "id-palm",
|
||||
"06032b81051086480954010b" : "id-retina",
|
||||
"06032b81051086480954010c" : "id-signature",
|
||||
"06032b81051086480954010d" : "id-speech-Pattern",
|
||||
"06032b81051086480954010e" : "id-thermal-Image",
|
||||
"06032b81051086480954010f" : "id-vein-Pattern",
|
||||
"06032b810510864809540110" : "id-thermal-Face-Image",
|
||||
"06032b810510864809540111" : "id-thermal-Hand-Image",
|
||||
"06032b810510864809540112" : "id-lip-Movement",
|
||||
"06032b810510864809540113" : "id-gait",
|
||||
"06032b810510864809540102" : "id-dna",
|
||||
"06032b810510864809540103" : "id-ear-Shape",
|
||||
"06032b810510864809540104" : "id-facial-Features",
|
||||
"06032b810510864809540105" : "id-finger-Image",
|
||||
"06032b810510864809540106" : "id-finger-Geometry",
|
||||
"06032b810510864809540107" : "id-hand-Geometry",
|
||||
"06032b810510864809540108" : "id-iris-Features",
|
||||
"06032b810510864809540109" : "id-keystroke-Dynamics",
|
||||
"06032b8105108648095402" : "processing-algorithm",
|
||||
"06032b8105108648095403" : "matching-method",
|
||||
"06032b8105108648095404" : "format-Owner",
|
||||
"06032b810510864809540400" : "cbeff-Owner",
|
||||
"06032b810510864809540401" : "ibia-Owner",
|
||||
"06032b81051086480954040101" : "id-ibia-SAFLINK",
|
||||
"06032b8105108648095404010a" : "id-ibia-SecuGen",
|
||||
"06032b8105108648095404010b" : "id-ibia-PreciseBiometric",
|
||||
"06032b8105108648095404010c" : "id-ibia-Identix",
|
||||
"06032b8105108648095404010d" : "id-ibia-DERMALOG",
|
||||
"06032b8105108648095404010e" : "id-ibia-LOGICO",
|
||||
"06032b8105108648095404010f" : "id-ibia-NIST",
|
||||
"06032b81051086480954040110" : "id-ibia-A3Vision",
|
||||
"06032b81051086480954040111" : "id-ibia-NEC",
|
||||
"06032b81051086480954040112" : "id-ibia-STMicroelectronics",
|
||||
"06032b81051086480954040102" : "id-ibia-Bioscrypt",
|
||||
"06032b81051086480954040103" : "id-ibia-Visionics",
|
||||
"06032b81051086480954040104" : "id-ibia-InfineonTechnologiesAG",
|
||||
"06032b81051086480954040105" : "id-ibia-IridianTechnologies",
|
||||
"06032b81051086480954040106" : "id-ibia-Veridicom",
|
||||
"06032b81051086480954040107" : "id-ibia-CyberSIGN",
|
||||
"06032b81051086480954040108" : "id-ibia-eCryp.",
|
||||
"06032b81051086480954040109" : "id-ibia-FingerprintCardsAB",
|
||||
"06032b810510864809540402" : "x9-Owner",
|
||||
"06032b0e021a05" : "sha",
|
||||
"06032b0e03020101" : "rsa",
|
||||
"06032b0e03020a" : "desMAC",
|
||||
"06032b0e03020b" : "rsaSignature",
|
||||
"06032b0e03020c" : "dsa",
|
||||
"06032b0e03020d" : "dsaWithSHA",
|
||||
"06032b0e03020e" : "mdc2WithRSASignature",
|
||||
"06032b0e03020f" : "shaWithRSASignature",
|
||||
"06032b0e030210" : "dhWithCommonModulus",
|
||||
"06032b0e030211" : "desEDE",
|
||||
"06032b0e030212" : "sha",
|
||||
"06032b0e030213" : "mdc-2",
|
||||
"06032b0e030202" : "md4WitRSA",
|
||||
"06032b0e03020201" : "sqmod-N",
|
||||
"06032b0e030214" : "dsaCommon",
|
||||
"06032b0e030215" : "dsaCommonWithSHA",
|
||||
"06032b0e030216" : "rsaKeyTransport",
|
||||
"06032b0e030217" : "keyed-hash-seal",
|
||||
"06032b0e030218" : "md2WithRSASignature",
|
||||
"06032b0e030219" : "md5WithRSASignature",
|
||||
"06032b0e03021a" : "sha1",
|
||||
"06032b0e03021b" : "dsaWithSHA1",
|
||||
"06032b0e03021c" : "dsaWithCommonSHA1",
|
||||
"06032b0e03021d" : "sha-1WithRSAEncryption",
|
||||
"06032b0e030203" : "md5WithRSA",
|
||||
"06032b0e03020301" : "sqmod-NwithRSA",
|
||||
"06032b0e030204" : "md4WithRSAEncryption",
|
||||
"06032b0e030206" : "desECB",
|
||||
"06032b0e030207" : "desCBC",
|
||||
"06032b0e030208" : "desOFB",
|
||||
"06032b0e030209" : "desCFB",
|
||||
"06032b0e030301" : "simple-strong-auth-mechanism",
|
||||
"06032b0e07020101" : "ElGamal",
|
||||
"06032b0e07020301" : "md2WithRSA",
|
||||
"06032b0e07020302" : "md2WithElGamal",
|
||||
"06032b2403" : "algorithm",
|
||||
"06032b240301" : "encryptionAlgorithm",
|
||||
"06032b24030101" : "des",
|
||||
"06032b240301010101" : "desECBPad",
|
||||
"06032b24030101010101" : "desECBPadISO",
|
||||
"06032b240301010201" : "desCBCPad",
|
||||
"06032b24030101020101" : "desCBCPadISO",
|
||||
"06032b24030102" : "idea",
|
||||
"06032b2403010201" : "ideaECB",
|
||||
"06032b240301020101" : "ideaECBPad",
|
||||
"06032b24030102010101" : "ideaECBPadISO",
|
||||
"06032b2403010202" : "ideaCBC",
|
||||
"06032b240301020201" : "ideaCBCPad",
|
||||
"06032b24030102020101" : "ideaCBCPadISO",
|
||||
"06032b2403010203" : "ideaOFB",
|
||||
"06032b2403010204" : "ideaCFB",
|
||||
"06032b24030103" : "des-3",
|
||||
"06032b240301030101" : "des-3ECBPad",
|
||||
"06032b24030103010101" : "des-3ECBPadISO",
|
||||
"06032b240301030201" : "des-3CBCPad",
|
||||
"06032b24030103020101" : "des-3CBCPadISO",
|
||||
"06032b240302" : "hashAlgorithm",
|
||||
"06032b24030201" : "ripemd160",
|
||||
"06032b24030202" : "ripemd128",
|
||||
"06032b24030203" : "ripemd256",
|
||||
"06032b24030204" : "mdc2singleLength",
|
||||
"06032b24030205" : "mdc2doubleLength",
|
||||
"06032b240303" : "signatureAlgorithm",
|
||||
"06032b24030301" : "rsa",
|
||||
"06032b2403030101" : "rsaMitSHA-1",
|
||||
"06032b2403030102" : "rsaMitRIPEMD160",
|
||||
"06032b24030302" : "ellipticCurve",
|
||||
"06032b240304" : "signatureScheme",
|
||||
"06032b24030401" : "iso9796-1",
|
||||
"06032b2403040201" : "iso9796-2",
|
||||
"06032b2403040202" : "iso9796-2rsa",
|
||||
"06032b2404" : "attribute",
|
||||
"06032b2405" : "policy",
|
||||
"06032b2406" : "api",
|
||||
"06032b240601" : "manufacturerSpecific",
|
||||
"06032b240602" : "functionalitySpecific",
|
||||
"06032b2407" : "api",
|
||||
"06032b240701" : "keyAgreement",
|
||||
"06032b240702" : "keyTransport",
|
||||
"06032b06010401927c0a0101" : "UNINETT policyIdentifier",
|
||||
"06032b0601040195180a" : "ICE-TEL policyIdentifier",
|
||||
"06032b0601040197552001" : "cryptlibEnvelope",
|
||||
"06032b0601040197552002" : "cryptlibPrivateKey",
|
||||
"060a2b060104018237" : "Microsoft OID",
|
||||
"060a2b0601040182370a" : "Crypto 2.0",
|
||||
"060a2b0601040182370a01" : "certTrustList",
|
||||
"060a2b0601040182370a0101" : "szOID_SORTED_CTL",
|
||||
"060a2b0601040182370a0a" : "Microsoft CMC OIDs",
|
||||
"060a2b0601040182370a0a01" : "szOID_CMC_ADD_ATTRIBUTES",
|
||||
"060a2b0601040182370a0b" : "Microsoft certificate property OIDs",
|
||||
"060a2b0601040182370a0b01" : "szOID_CERT_PROP_ID_PREFIX",
|
||||
"060a2b0601040182370a0c" : "CryptUI",
|
||||
"060a2b0601040182370a0c01" : "szOID_ANY_APPLICATION_POLICY",
|
||||
"060a2b0601040182370a02" : "nextUpdateLocation",
|
||||
"060a2b0601040182370a0301" : "certTrustListSigning",
|
||||
"060a2b0601040182370a030a" : "szOID_KP_QUALIFIED_SUBORDINATION",
|
||||
"060a2b0601040182370a030b" : "szOID_KP_KEY_RECOVERY",
|
||||
"060a2b0601040182370a030c" : "szOID_KP_DOCUMENT_SIGNING",
|
||||
"060a2b0601040182370a0302" : "timeStampSigning",
|
||||
"060a2b0601040182370a0303" : "serverGatedCrypto",
|
||||
"060a2b0601040182370a030301" : "szOID_SERIALIZED",
|
||||
"060a2b0601040182370a0304" : "encryptedFileSystem",
|
||||
"060a2b0601040182370a030401" : "szOID_EFS_RECOVERY",
|
||||
"060a2b0601040182370a0305" : "szOID_WHQL_CRYPTO",
|
||||
"060a2b0601040182370a0306" : "szOID_NT5_CRYPTO",
|
||||
"060a2b0601040182370a0307" : "szOID_OEM_WHQL_CRYPTO",
|
||||
"060a2b0601040182370a0308" : "szOID_EMBEDDED_NT_CRYPTO",
|
||||
"060a2b0601040182370a0309" : "szOID_ROOT_LIST_SIGNER",
|
||||
"060a2b0601040182370a0401" : "yesnoTrustAttr",
|
||||
"060a2b0601040182370a0501" : "szOID_DRM",
|
||||
"060a2b0601040182370a0502" : "szOID_DRM_INDIVIDUALIZATION",
|
||||
"060a2b0601040182370a0601" : "szOID_LICENSES",
|
||||
"060a2b0601040182370a0602" : "szOID_LICENSE_SERVER",
|
||||
"060a2b0601040182370a07" : "szOID_MICROSOFT_RDN_PREFIX",
|
||||
"060a2b0601040182370a0701" : "szOID_KEYID_RDN",
|
||||
"060a2b0601040182370a0801" : "szOID_REMOVE_CERTIFICATE",
|
||||
"060a2b0601040182370a0901" : "szOID_CROSS_CERT_DIST_POINTS",
|
||||
"060a2b0601040182370c" : "Catalog",
|
||||
"060a2b0601040182370c0101" : "szOID_CATALOG_LIST",
|
||||
"060a2b0601040182370c0102" : "szOID_CATALOG_LIST_MEMBER",
|
||||
"060a2b0601040182370c0201" : "CAT_NAMEVALUE_OBJID",
|
||||
"060a2b0601040182370c0202" : "CAT_MEMBERINFO_OBJID",
|
||||
"060a2b0601040182370d" : "Microsoft PKCS10 OIDs",
|
||||
"060a2b0601040182370d01" : "szOID_RENEWAL_CERTIFICATE",
|
||||
"060a2b0601040182370d0201" : "szOID_ENROLLMENT_NAME_VALUE_PAIR",
|
||||
"060a2b0601040182370d0202" : "szOID_ENROLLMENT_CSP_PROVIDER",
|
||||
"060a2b0601040182370d0203" : "OS Version",
|
||||
"060a2b0601040182370f" : "Microsoft Java",
|
||||
"060a2b06010401823710" : "Microsoft Outlook/Exchange",
|
||||
"060a2b0601040182371004" : "Outlook Express",
|
||||
"060a2b06010401823711" : "Microsoft PKCS12 attributes",
|
||||
"060a2b0601040182371101" : "szOID_LOCAL_MACHINE_KEYSET",
|
||||
"060a2b06010401823712" : "Microsoft Hydra",
|
||||
"060a2b06010401823713" : "Microsoft ISPU Test",
|
||||
"060a2b06010401823702" : "Authenticode",
|
||||
"060a2b06010401823702010a" : "spcAgencyInfo",
|
||||
"060a2b06010401823702010b" : "spcStatementType",
|
||||
"060a2b06010401823702010c" : "spcSpOpusInfo",
|
||||
"060a2b06010401823702010e" : "certExtensions",
|
||||
"060a2b06010401823702010f" : "spcPelmageData",
|
||||
"060a2b060104018237020112" : "SPC_RAW_FILE_DATA_OBJID",
|
||||
"060a2b060104018237020113" : "SPC_STRUCTURED_STORAGE_DATA_OBJID",
|
||||
"060a2b060104018237020114" : "spcLink",
|
||||
"060a2b060104018237020115" : "individualCodeSigning",
|
||||
"060a2b060104018237020116" : "commercialCodeSigning",
|
||||
"060a2b060104018237020119" : "spcLink",
|
||||
"060a2b06010401823702011a" : "spcMinimalCriteriaInfo",
|
||||
"060a2b06010401823702011b" : "spcFinancialCriteriaInfo",
|
||||
"060a2b06010401823702011c" : "spcLink",
|
||||
"060a2b06010401823702011d" : "SPC_HASH_INFO_OBJID",
|
||||
"060a2b06010401823702011e" : "SPC_SIPINFO_OBJID",
|
||||
"060a2b060104018237020104" : "spcIndirectDataContext",
|
||||
"060a2b0601040182370202" : "CTL for Software Publishers Trusted CAs",
|
||||
"060a2b060104018237020201" : "szOID_TRUSTED_CODESIGNING_CA_LIST",
|
||||
"060a2b060104018237020202" : "szOID_TRUSTED_CLIENT_AUTH_CA_LIST",
|
||||
"060a2b060104018237020203" : "szOID_TRUSTED_SERVER_AUTH_CA_LIST",
|
||||
"060a2b06010401823714" : "Microsoft Enrollment Infrastructure",
|
||||
"060a2b0601040182371401" : "szOID_AUTO_ENROLL_CTL_USAGE",
|
||||
"060a2b0601040182371402" : "szOID_ENROLL_CERTTYPE_EXTENSION",
|
||||
"060a2b060104018237140201" : "szOID_ENROLLMENT_AGENT",
|
||||
"060a2b060104018237140202" : "szOID_KP_SMARTCARD_LOGON",
|
||||
"060a2b060104018237140203" : "szOID_NT_PRINCIPAL_NAME",
|
||||
"060a2b0601040182371403" : "szOID_CERT_MANIFOLD",
|
||||
"06092b06010401823715" : "Microsoft CertSrv Infrastructure",
|
||||
"06092b0601040182371501" : "szOID_CERTSRV_CA_VERSION",
|
||||
"06092b0601040182371514" : "Client Information",
|
||||
"060a2b06010401823719" : "Microsoft Directory Service",
|
||||
"060a2b0601040182371901" : "szOID_NTDS_REPLICATION",
|
||||
"060a2b06010401823703" : "Time Stamping",
|
||||
"060a2b060104018237030201" : "SPC_TIME_STAMP_REQUEST_OBJID",
|
||||
"060a2b0601040182371e" : "IIS",
|
||||
"060a2b0601040182371f" : "Windows updates and service packs",
|
||||
"060a2b0601040182371f01" : "szOID_PRODUCT_UPDATE",
|
||||
"060a2b06010401823704" : "Permissions",
|
||||
"060a2b06010401823728" : "Fonts",
|
||||
"060a2b06010401823729" : "Microsoft Licensing and Registration",
|
||||
"060a2b0601040182372a" : "Microsoft Corporate PKI (ITG)",
|
||||
"060a2b06010401823758" : "CAPICOM",
|
||||
"060a2b0601040182375801" : "szOID_CAPICOM_VERSION",
|
||||
"060a2b0601040182375802" : "szOID_CAPICOM_ATTRIBUTE",
|
||||
"060a2b060104018237580201" : "szOID_CAPICOM_DOCUMENT_NAME",
|
||||
"060a2b060104018237580202" : "szOID_CAPICOM_DOCUMENT_DESCRIPTION",
|
||||
"060a2b0601040182375803" : "szOID_CAPICOM_ENCRYPTED_DATA",
|
||||
"060a2b060104018237580301" : "szOID_CAPICOM_ENCRYPTED_CONTENT",
|
||||
"06032b0601050507" : "pkix",
|
||||
"06032b060105050701" : "privateExtension",
|
||||
"06032b06010505070101" : "authorityInfoAccess",
|
||||
"06032b06010505070c02" : "CMC Data",
|
||||
"06032b060105050702" : "policyQualifierIds",
|
||||
// "06032b06010505070201" : "cps",
|
||||
"06032b06010505070202" : "unotice",
|
||||
"06032b060105050703" : "keyPurpose",
|
||||
"06032b06010505070301" : "serverAuth",
|
||||
"06032b06010505070302" : "clientAuth",
|
||||
"06032b06010505070303" : "codeSigning",
|
||||
"06032b06010505070304" : "emailProtection",
|
||||
"06032b06010505070305" : "ipsecEndSystem",
|
||||
"06032b06010505070306" : "ipsecTunnel",
|
||||
"06032b06010505070307" : "ipsecUser",
|
||||
"06032b06010505070308" : "timeStamping",
|
||||
"06032b060105050704" : "cmpInformationTypes",
|
||||
"06032b06010505070401" : "caProtEncCert",
|
||||
"06032b06010505070402" : "signKeyPairTypes",
|
||||
"06032b06010505070403" : "encKeyPairTypes",
|
||||
"06032b06010505070404" : "preferredSymmAlg",
|
||||
"06032b06010505070405" : "caKeyUpdateInfo",
|
||||
"06032b06010505070406" : "currentCRL",
|
||||
"06032b06010505073001" : "ocsp",
|
||||
"06032b06010505073002" : "caIssuers",
|
||||
"06032b06010505080101" : "HMAC-MD5",
|
||||
"06032b06010505080102" : "HMAC-SHA",
|
||||
"060360864801650201010a" : "mosaicKeyManagementAlgorithm",
|
||||
"060360864801650201010b" : "sdnsKMandSigAlgorithm",
|
||||
"060360864801650201010c" : "mosaicKMandSigAlgorithm",
|
||||
"060360864801650201010d" : "SuiteASignatureAlgorithm",
|
||||
"060360864801650201010e" : "SuiteAConfidentialityAlgorithm",
|
||||
"060360864801650201010f" : "SuiteAIntegrityAlgorithm",
|
||||
"06036086480186f84201" : "cert-extension",
|
||||
// "06036086480186f8420101" : "netscape-cert-type",
|
||||
"06036086480186f842010a" : "EntityLogo",
|
||||
"06036086480186f842010b" : "UserPicture",
|
||||
// "06036086480186f842010c" : "netscape-ssl-server-name",
|
||||
// "06036086480186f842010d" : "netscape-comment",
|
||||
// "06036086480186f8420102" : "netscape-base-url",
|
||||
// "06036086480186f8420103" : "netscape-revocation-url",
|
||||
// "06036086480186f8420104" : "netscape-ca-revocation-url",
|
||||
// "06036086480186f8420107" : "netscape-cert-renewal-url",
|
||||
// "06036086480186f8420108" : "netscape-ca-policy-url",
|
||||
"06036086480186f8420109" : "HomePage-url",
|
||||
"06036086480186f84202" : "data-type",
|
||||
"06036086480186f8420201" : "GIF",
|
||||
"06036086480186f8420202" : "JPEG",
|
||||
"06036086480186f8420203" : "URL",
|
||||
"06036086480186f8420204" : "HTML",
|
||||
"06036086480186f8420205" : "netscape-cert-sequence",
|
||||
"06036086480186f8420206" : "netscape-cert-url",
|
||||
"06036086480186f84203" : "directory",
|
||||
"06036086480186f8420401" : "serverGatedCrypto",
|
||||
"06036086480186f845010603" : "Unknown Verisign extension",
|
||||
"06036086480186f845010606" : "Unknown Verisign extension",
|
||||
"06036086480186f84501070101" : "Verisign certificatePolicy",
|
||||
"06036086480186f8450107010101" : "Unknown Verisign policy qualifier",
|
||||
"06036086480186f8450107010102" : "Unknown Verisign policy qualifier",
|
||||
"0603678105" : "TCPA",
|
||||
"060367810501" : "tcpaSpecVersion",
|
||||
"060367810502" : "tcpaAttribute",
|
||||
"06036781050201" : "tcpaAtTpmManufacturer",
|
||||
"0603678105020a" : "tcpaAtSecurityQualities",
|
||||
"0603678105020b" : "tcpaAtTpmProtectionProfile",
|
||||
"0603678105020c" : "tcpaAtTpmSecurityTarget",
|
||||
"0603678105020d" : "tcpaAtFoundationProtectionProfile",
|
||||
"0603678105020e" : "tcpaAtFoundationSecurityTarget",
|
||||
"0603678105020f" : "tcpaAtTpmIdLabel",
|
||||
"06036781050202" : "tcpaAtTpmModel",
|
||||
"06036781050203" : "tcpaAtTpmVersion",
|
||||
"06036781050204" : "tcpaAtPlatformManufacturer",
|
||||
"06036781050205" : "tcpaAtPlatformModel",
|
||||
"06036781050206" : "tcpaAtPlatformVersion",
|
||||
"06036781050207" : "tcpaAtComponentManufacturer",
|
||||
"06036781050208" : "tcpaAtComponentModel",
|
||||
"06036781050209" : "tcpaAtComponentVersion",
|
||||
"060367810503" : "tcpaProtocol",
|
||||
"06036781050301" : "tcpaPrttTpmIdProtocol",
|
||||
"0603672a00" : "contentType",
|
||||
"0603672a0000" : "PANData",
|
||||
"0603672a0001" : "PANToken",
|
||||
"0603672a0002" : "PANOnly",
|
||||
"0603672a01" : "msgExt",
|
||||
"0603672a0a" : "national",
|
||||
"0603672a0a8140" : "Japan",
|
||||
"0603672a02" : "field",
|
||||
"0603672a0200" : "fullName",
|
||||
"0603672a0201" : "givenName",
|
||||
"0603672a020a" : "amount",
|
||||
"0603672a0202" : "familyName",
|
||||
"0603672a0203" : "birthFamilyName",
|
||||
"0603672a0204" : "placeName",
|
||||
"0603672a0205" : "identificationNumber",
|
||||
"0603672a0206" : "month",
|
||||
"0603672a0207" : "date",
|
||||
"0603672a02070b" : "accountNumber",
|
||||
"0603672a02070c" : "passPhrase",
|
||||
"0603672a0208" : "address",
|
||||
"0603672a0209" : "telephone",
|
||||
"0603672a03" : "attribute",
|
||||
"0603672a0300" : "cert",
|
||||
"0603672a030000" : "rootKeyThumb",
|
||||
"0603672a030001" : "additionalPolicy",
|
||||
"0603672a04" : "algorithm",
|
||||
"0603672a05" : "policy",
|
||||
"0603672a0500" : "root",
|
||||
"0603672a06" : "module",
|
||||
"0603672a07" : "certExt",
|
||||
"0603672a0700" : "hashedRootKey",
|
||||
"0603672a0701" : "certificateType",
|
||||
"0603672a0702" : "merchantData",
|
||||
"0603672a0703" : "cardCertRequired",
|
||||
"0603672a0704" : "tunneling",
|
||||
"0603672a0705" : "setExtensions",
|
||||
"0603672a0706" : "setQualifier",
|
||||
"0603672a08" : "brand",
|
||||
"0603672a0801" : "IATA-ATA",
|
||||
"0603672a081e" : "Diners",
|
||||
"0603672a0822" : "AmericanExpress",
|
||||
"0603672a0804" : "VISA",
|
||||
"0603672a0805" : "MasterCard",
|
||||
"0603672a08ae7b" : "Novus",
|
||||
"0603672a09" : "vendor",
|
||||
"0603672a0900" : "GlobeSet",
|
||||
"0603672a0901" : "IBM",
|
||||
"0603672a090a" : "Griffin",
|
||||
"0603672a090b" : "Certicom",
|
||||
"0603672a090c" : "OSS",
|
||||
"0603672a090d" : "TenthMountain",
|
||||
"0603672a090e" : "Antares",
|
||||
"0603672a090f" : "ECC",
|
||||
"0603672a0910" : "Maithean",
|
||||
"0603672a0911" : "Netscape",
|
||||
"0603672a0912" : "Verisign",
|
||||
"0603672a0913" : "BlueMoney",
|
||||
"0603672a0902" : "CyberCash",
|
||||
"0603672a0914" : "Lacerte",
|
||||
"0603672a0915" : "Fujitsu",
|
||||
"0603672a0916" : "eLab",
|
||||
"0603672a0917" : "Entrust",
|
||||
"0603672a0918" : "VIAnet",
|
||||
"0603672a0919" : "III",
|
||||
"0603672a091a" : "OpenMarket",
|
||||
"0603672a091b" : "Lexem",
|
||||
"0603672a091c" : "Intertrader",
|
||||
"0603672a091d" : "Persimmon",
|
||||
"0603672a0903" : "Terisa",
|
||||
"0603672a091e" : "NABLE",
|
||||
"0603672a091f" : "espace-net",
|
||||
"0603672a0920" : "Hitachi",
|
||||
"0603672a0921" : "Microsoft",
|
||||
"0603672a0922" : "NEC",
|
||||
"0603672a0923" : "Mitsubishi",
|
||||
"0603672a0924" : "NCR",
|
||||
"0603672a0925" : "e-COMM",
|
||||
"0603672a0926" : "Gemplus",
|
||||
"0603672a0904" : "RSADSI",
|
||||
"0603672a0905" : "VeriFone",
|
||||
"0603672a0906" : "TrinTech",
|
||||
"0603672a0907" : "BankGate",
|
||||
"0603672a0908" : "GTE",
|
||||
"0603672a0909" : "CompuSource",
|
||||
"0603551d01" : "authorityKeyIdentifier",
|
||||
"0603551d0a" : "basicConstraints",
|
||||
"0603551d0b" : "nameConstraints",
|
||||
"0603551d0c" : "policyConstraints",
|
||||
"0603551d0d" : "basicConstraints",
|
||||
"0603551d0e" : "subjectKeyIdentifier",
|
||||
"0603551d0f" : "keyUsage",
|
||||
"0603551d10" : "privateKeyUsagePeriod",
|
||||
"0603551d11" : "subjectAltName",
|
||||
"0603551d12" : "issuerAltName",
|
||||
"0603551d13" : "basicConstraints",
|
||||
"0603551d02" : "keyAttributes",
|
||||
"0603551d14" : "cRLNumber",
|
||||
"0603551d15" : "cRLReason",
|
||||
"0603551d16" : "expirationDate",
|
||||
"0603551d17" : "instructionCode",
|
||||
"0603551d18" : "invalidityDate",
|
||||
"0603551d1a" : "issuingDistributionPoint",
|
||||
"0603551d1b" : "deltaCRLIndicator",
|
||||
"0603551d1c" : "issuingDistributionPoint",
|
||||
"0603551d1d" : "certificateIssuer",
|
||||
"0603551d03" : "certificatePolicies",
|
||||
"0603551d1e" : "nameConstraints",
|
||||
"0603551d1f" : "cRLDistributionPoints",
|
||||
"0603551d20" : "certificatePolicies",
|
||||
"0603551d21" : "policyMappings",
|
||||
"0603551d22" : "policyConstraints",
|
||||
"0603551d23" : "authorityKeyIdentifier",
|
||||
"0603551d24" : "policyConstraints",
|
||||
"0603551d25" : "extKeyUsage",
|
||||
"0603551d04" : "keyUsageRestriction",
|
||||
"0603551d05" : "policyMapping",
|
||||
"0603551d06" : "subtreesConstraint",
|
||||
"0603551d07" : "subjectAltName",
|
||||
"0603551d08" : "issuerAltName",
|
||||
"0603551d09" : "subjectDirectoryAttributes",
|
||||
"0603550400" : "objectClass",
|
||||
"0603550401" : "aliasObjectName",
|
||||
// "060355040c" : "title",
|
||||
"060355040d" : "description",
|
||||
"060355040e" : "searchGuide",
|
||||
"060355040f" : "businessCategory",
|
||||
"0603550410" : "postalAddress",
|
||||
"0603550411" : "postalCode",
|
||||
"0603550412" : "postOfficeBox",
|
||||
"0603550413" : "physicalDeliveryOfficeName",
|
||||
"0603550402" : "knowledgeInformation",
|
||||
// "0603550414" : "telephoneNumber",
|
||||
"0603550415" : "telexNumber",
|
||||
"0603550416" : "teletexTerminalIdentifier",
|
||||
"0603550417" : "facsimileTelephoneNumber",
|
||||
"0603550418" : "x121Address",
|
||||
"0603550419" : "internationalISDNNumber",
|
||||
"060355041a" : "registeredAddress",
|
||||
"060355041b" : "destinationIndicator",
|
||||
"060355041c" : "preferredDeliveryMehtod",
|
||||
"060355041d" : "presentationAddress",
|
||||
"060355041e" : "supportedApplicationContext",
|
||||
"060355041f" : "member",
|
||||
"0603550420" : "owner",
|
||||
"0603550421" : "roleOccupant",
|
||||
"0603550422" : "seeAlso",
|
||||
"0603550423" : "userPassword",
|
||||
"0603550424" : "userCertificate",
|
||||
"0603550425" : "caCertificate",
|
||||
"0603550426" : "authorityRevocationList",
|
||||
"0603550427" : "certificateRevocationList",
|
||||
"0603550428" : "crossCertificatePair",
|
||||
"0603550429" : "givenName",
|
||||
// "060355042a" : "givenName",
|
||||
"0603550405" : "serialNumber",
|
||||
"0603550434" : "supportedAlgorithms",
|
||||
"0603550435" : "deltaRevocationList",
|
||||
"060355043a" : "crossCertificatePair",
|
||||
// "0603550409" : "streetAddress",
|
||||
"06035508" : "X.500-Algorithms",
|
||||
"0603550801" : "X.500-Alg-Encryption",
|
||||
"060355080101" : "rsa",
|
||||
"0603604c0101" : "DPC"
|
||||
};
|
||||
|
|
|
@ -61,7 +61,7 @@ const QuotedPrintable = {
|
|||
* @returns {byteArray}
|
||||
*/
|
||||
runFrom: function (input, args) {
|
||||
const str = input.replace(/\=(?:\r?\n|$)/g, "");
|
||||
const str = input.replace(/=(?:\r?\n|$)/g, "");
|
||||
return QuotedPrintable.mimeDecode(str);
|
||||
},
|
||||
|
||||
|
@ -73,7 +73,7 @@ const QuotedPrintable = {
|
|||
* @returns {byteArray}
|
||||
*/
|
||||
mimeDecode: function(str) {
|
||||
let encodedBytesCount = (str.match(/\=[\da-fA-F]{2}/g) || []).length,
|
||||
let encodedBytesCount = (str.match(/=[\da-fA-F]{2}/g) || []).length,
|
||||
bufferLength = str.length - encodedBytesCount * 2,
|
||||
chr, hex,
|
||||
buffer = new Array(bufferLength),
|
||||
|
@ -219,21 +219,21 @@ const QuotedPrintable = {
|
|||
result += line;
|
||||
pos += line.length;
|
||||
continue;
|
||||
} else if (line.length > lineLengthMax - lineMargin && (match = line.substr(-lineMargin).match(/[ \t\.,!\?][^ \t\.,!\?]*$/))) {
|
||||
} else if (line.length > lineLengthMax - lineMargin && (match = line.substr(-lineMargin).match(/[ \t.,!?][^ \t.,!?]*$/))) {
|
||||
// truncate to nearest space
|
||||
line = line.substr(0, line.length - (match[0].length - 1));
|
||||
} else if (line.substr(-1) === "\r") {
|
||||
line = line.substr(0, line.length - 1);
|
||||
} else {
|
||||
if (line.match(/\=[\da-f]{0,2}$/i)) {
|
||||
if (line.match(/=[\da-f]{0,2}$/i)) {
|
||||
|
||||
// push incomplete encoding sequences to the next line
|
||||
if ((match = line.match(/\=[\da-f]{0,1}$/i))) {
|
||||
if ((match = line.match(/=[\da-f]{0,1}$/i))) {
|
||||
line = line.substr(0, line.length - match[0].length);
|
||||
}
|
||||
|
||||
// ensure that utf-8 sequences are not split
|
||||
while (line.length > 3 && line.length < len - pos && !line.match(/^(?:=[\da-f]{2}){1,4}$/i) && (match = line.match(/\=[\da-f]{2}$/ig))) {
|
||||
while (line.length > 3 && line.length < len - pos && !line.match(/^(?:=[\da-f]{2}){1,4}$/i) && (match = line.match(/=[\da-f]{2}$/ig))) {
|
||||
code = parseInt(match[0].substr(1, 2), 16);
|
||||
if (code < 128) {
|
||||
break;
|
||||
|
@ -250,7 +250,7 @@ const QuotedPrintable = {
|
|||
}
|
||||
|
||||
if (pos + line.length < len && line.substr(-1) !== "\n") {
|
||||
if (line.length === 76 && line.match(/\=[\da-f]{2}$/i)) {
|
||||
if (line.length === 76 && line.match(/=[\da-f]{2}$/i)) {
|
||||
line = line.substr(0, line.length - 3);
|
||||
} else if (line.length === 76) {
|
||||
line = line.substr(0, line.length - 1);
|
||||
|
|
|
@ -20,7 +20,7 @@ const Rotate = {
|
|||
* @constant
|
||||
* @default
|
||||
*/
|
||||
ROTATE_WHOLE: false,
|
||||
ROTATE_CARRY: false,
|
||||
|
||||
/**
|
||||
* Runs rotation operations across the input data.
|
||||
|
@ -53,7 +53,7 @@ const Rotate = {
|
|||
*/
|
||||
runRotr: function(input, args) {
|
||||
if (args[1]) {
|
||||
return Rotate._rotrWhole(input, args[0]);
|
||||
return Rotate._rotrCarry(input, args[0]);
|
||||
} else {
|
||||
return Rotate._rot(input, args[0], Rotate._rotr);
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ const Rotate = {
|
|||
*/
|
||||
runRotl: function(input, args) {
|
||||
if (args[1]) {
|
||||
return Rotate._rotlWhole(input, args[0]);
|
||||
return Rotate._rotlCarry(input, args[0]);
|
||||
} else {
|
||||
return Rotate._rot(input, args[0], Rotate._rotl);
|
||||
}
|
||||
|
@ -135,7 +135,7 @@ const Rotate = {
|
|||
/**
|
||||
* ROT47 operation.
|
||||
*
|
||||
* @author Matt C [matt@artemisbot.pw]
|
||||
* @author Matt C [matt@artemisbot.uk]
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
|
@ -197,7 +197,7 @@ const Rotate = {
|
|||
* @param {number} amount
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
_rotrWhole: function(data, amount) {
|
||||
_rotrCarry: function(data, amount) {
|
||||
let carryBits = 0,
|
||||
newByte,
|
||||
result = [];
|
||||
|
@ -223,7 +223,7 @@ const Rotate = {
|
|||
* @param {number} amount
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
_rotlWhole: function(data, amount) {
|
||||
_rotlCarry: function(data, amount) {
|
||||
let carryBits = 0,
|
||||
newByte,
|
||||
result = [];
|
||||
|
|
|
@ -249,7 +249,7 @@ const SeqUtils = {
|
|||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
return a.localeCompare(b);
|
||||
},
|
||||
|
||||
};
|
||||
|
|
96
src/core/operations/Shellcode.js
Normal file
|
@ -0,0 +1,96 @@
|
|||
import disassemble from "../lib/DisassembleX86-64.js";
|
||||
|
||||
|
||||
/**
|
||||
* Shellcode operations.
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*
|
||||
* @namespace
|
||||
*/
|
||||
const Shellcode = {
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
MODE: ["64", "32", "16"],
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
COMPATIBILITY: [
|
||||
"Full x86 architecture",
|
||||
"Knights Corner",
|
||||
"Larrabee",
|
||||
"Cyrix",
|
||||
"Geode",
|
||||
"Centaur",
|
||||
"X86/486"
|
||||
],
|
||||
|
||||
/**
|
||||
* Disassemble x86 operation.
|
||||
*
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
runDisassemble: function(input, args) {
|
||||
const mode = args[0],
|
||||
compatibility = args[1],
|
||||
codeSegment = args[2],
|
||||
offset = args[3],
|
||||
showInstructionHex = args[4],
|
||||
showInstructionPos = args[5];
|
||||
|
||||
switch (mode) {
|
||||
case "64":
|
||||
disassemble.setBitMode(2);
|
||||
break;
|
||||
case "32":
|
||||
disassemble.setBitMode(1);
|
||||
break;
|
||||
case "16":
|
||||
disassemble.setBitMode(0);
|
||||
break;
|
||||
default:
|
||||
throw "Invalid mode value";
|
||||
}
|
||||
|
||||
switch (compatibility) {
|
||||
case "Full x86 architecture":
|
||||
disassemble.CompatibilityMode(0);
|
||||
break;
|
||||
case "Knights Corner":
|
||||
disassemble.CompatibilityMode(1);
|
||||
break;
|
||||
case "Larrabee":
|
||||
disassemble.CompatibilityMode(2);
|
||||
break;
|
||||
case "Cyrix":
|
||||
disassemble.CompatibilityMode(3);
|
||||
break;
|
||||
case "Geode":
|
||||
disassemble.CompatibilityMode(4);
|
||||
break;
|
||||
case "Centaur":
|
||||
disassemble.CompatibilityMode(5);
|
||||
break;
|
||||
case "X86/486":
|
||||
disassemble.CompatibilityMode(6);
|
||||
break;
|
||||
}
|
||||
|
||||
disassemble.SetBasePosition(codeSegment + ":" + offset);
|
||||
disassemble.setShowInstructionHex(showInstructionHex);
|
||||
disassemble.setShowInstructionPos(showInstructionPos);
|
||||
disassemble.LoadBinCode(input.replace(/\s/g, ""));
|
||||
return disassemble.LDisassemble();
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
export default Shellcode;
|
|
@ -1,5 +1,4 @@
|
|||
import Utils from "../Utils.js";
|
||||
import * as JsDiff from "diff";
|
||||
|
||||
|
||||
/**
|
||||
|
@ -36,11 +35,11 @@ const StrUtils = {
|
|||
},
|
||||
{
|
||||
name: "URL",
|
||||
value: "([A-Za-z]+://)([-\\w]+(?:\\.\\w[-\\w]*)+)(:\\d+)?(/[^.!,?;\"\\x27<>()\\[\\]{}\\s\\x7F-\\xFF]*(?:[.!,?]+[^.!,?;\"\\x27<>()\\[\\]{}\\s\\x7F-\\xFF]+)*)?"
|
||||
value: "([A-Za-z]+://)([-\\w]+(?:\\.\\w[-\\w]*)+)(:\\d+)?(/[^.!,?\"<>\\[\\]{}\\s\\x7F-\\xFF]*(?:[.!,?]+[^.!,?\"<>\\[\\]{}\\s\\x7F-\\xFF]+)*)?"
|
||||
},
|
||||
{
|
||||
name: "Domain",
|
||||
value: "(?:(https?):\\/\\/)?([-\\w.]+)\\.(com|net|org|biz|info|co|uk|onion|int|mobi|name|edu|gov|mil|eu|ac|ae|af|de|ca|ch|cn|cy|es|gb|hk|il|in|io|tv|me|nl|no|nz|ro|ru|tr|us|az|ir|kz|uz|pk)+"
|
||||
value: "\\b((?=[a-z0-9-]{1,63}\\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\\.)+[a-z]{2,63}\\b"
|
||||
},
|
||||
{
|
||||
name: "Windows file path",
|
||||
|
@ -193,17 +192,17 @@ const StrUtils = {
|
|||
* @constant
|
||||
* @default
|
||||
*/
|
||||
FIND_REPLACE_GLOBAL : true,
|
||||
FIND_REPLACE_GLOBAL: true,
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
FIND_REPLACE_CASE : false,
|
||||
FIND_REPLACE_CASE: false,
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
FIND_REPLACE_MULTILINE : true,
|
||||
FIND_REPLACE_MULTILINE: true,
|
||||
|
||||
/**
|
||||
* Find / Replace operation.
|
||||
|
@ -227,14 +226,16 @@ const StrUtils = {
|
|||
|
||||
if (type === "Regex") {
|
||||
find = new RegExp(find, modifiers);
|
||||
} else if (type.indexOf("Extended") === 0) {
|
||||
return input.replace(find, replace);
|
||||
}
|
||||
|
||||
if (type.indexOf("Extended") === 0) {
|
||||
find = Utils.parseEscapedChars(find);
|
||||
}
|
||||
|
||||
return input.replace(find, replace, modifiers);
|
||||
// Non-standard addition of flags in the third argument. This will work in Firefox but
|
||||
// probably nowhere else. The purpose is to allow global matching when the `find` parameter
|
||||
// is just a string.
|
||||
find = new RegExp(Utils.escapeRegex(find), modifiers);
|
||||
|
||||
return input.replace(find, replace);
|
||||
},
|
||||
|
||||
|
||||
|
@ -292,83 +293,6 @@ const StrUtils = {
|
|||
},
|
||||
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
DIFF_SAMPLE_DELIMITER: "\\n\\n",
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
DIFF_BY: ["Character", "Word", "Line", "Sentence", "CSS", "JSON"],
|
||||
|
||||
/**
|
||||
* Diff operation.
|
||||
*
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {html}
|
||||
*/
|
||||
runDiff: function(input, args) {
|
||||
let sampleDelim = args[0],
|
||||
diffBy = args[1],
|
||||
showAdded = args[2],
|
||||
showRemoved = args[3],
|
||||
ignoreWhitespace = args[4],
|
||||
samples = input.split(sampleDelim),
|
||||
output = "",
|
||||
diff;
|
||||
|
||||
if (!samples || samples.length !== 2) {
|
||||
return "Incorrect number of samples, perhaps you need to modify the sample delimiter or add more samples?";
|
||||
}
|
||||
|
||||
switch (diffBy) {
|
||||
case "Character":
|
||||
diff = JsDiff.diffChars(samples[0], samples[1]);
|
||||
break;
|
||||
case "Word":
|
||||
if (ignoreWhitespace) {
|
||||
diff = JsDiff.diffWords(samples[0], samples[1]);
|
||||
} else {
|
||||
diff = JsDiff.diffWordsWithSpace(samples[0], samples[1]);
|
||||
}
|
||||
break;
|
||||
case "Line":
|
||||
if (ignoreWhitespace) {
|
||||
diff = JsDiff.diffTrimmedLines(samples[0], samples[1]);
|
||||
} else {
|
||||
diff = JsDiff.diffLines(samples[0], samples[1]);
|
||||
}
|
||||
break;
|
||||
case "Sentence":
|
||||
diff = JsDiff.diffSentences(samples[0], samples[1]);
|
||||
break;
|
||||
case "CSS":
|
||||
diff = JsDiff.diffCss(samples[0], samples[1]);
|
||||
break;
|
||||
case "JSON":
|
||||
diff = JsDiff.diffJson(samples[0], samples[1]);
|
||||
break;
|
||||
default:
|
||||
return "Invalid 'Diff by' option.";
|
||||
}
|
||||
|
||||
for (let i = 0; i < diff.length; i++) {
|
||||
if (diff[i].added) {
|
||||
if (showAdded) output += "<span class='hlgreen'>" + Utils.escapeHtml(diff[i].value) + "</span>";
|
||||
} else if (diff[i].removed) {
|
||||
if (showRemoved) output += "<span class='hlred'>" + Utils.escapeHtml(diff[i].value) + "</span>";
|
||||
} else {
|
||||
output += Utils.escapeHtml(diff[i].value);
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
|
@ -422,7 +346,7 @@ const StrUtils = {
|
|||
}
|
||||
|
||||
if (match && !inMatch) {
|
||||
outputs[s] += "<span class='hlgreen'>" + Utils.escapeHtml(samples[s][i]);
|
||||
outputs[s] += "<span class='hl5'>" + Utils.escapeHtml(samples[s][i]);
|
||||
if (samples[s].length === i + 1) outputs[s] += "</span>";
|
||||
if (s === samples.length - 1) inMatch = true;
|
||||
} else if (!match && inMatch) {
|
||||
|
@ -448,14 +372,84 @@ const StrUtils = {
|
|||
|
||||
|
||||
/**
|
||||
* Parse escaped string operation.
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
ESCAPE_REPLACEMENTS: [
|
||||
{"escaped": "\\\\", "unescaped": "\\"}, // Must be first
|
||||
{"escaped": "\\'", "unescaped": "'"},
|
||||
{"escaped": "\\\"", "unescaped": "\""},
|
||||
{"escaped": "\\n", "unescaped": "\n"},
|
||||
{"escaped": "\\r", "unescaped": "\r"},
|
||||
{"escaped": "\\t", "unescaped": "\t"},
|
||||
{"escaped": "\\b", "unescaped": "\b"},
|
||||
{"escaped": "\\f", "unescaped": "\f"},
|
||||
],
|
||||
|
||||
/**
|
||||
* Escape string operation.
|
||||
*
|
||||
* @author Vel0x [dalemy@microsoft.com]
|
||||
*
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*
|
||||
* @example
|
||||
* StrUtils.runUnescape("Don't do that", [])
|
||||
* > "Don\'t do that"
|
||||
* StrUtils.runUnescape(`Hello
|
||||
* World`, [])
|
||||
* > "Hello\nWorld"
|
||||
*/
|
||||
runParseEscapedString: function(input, args) {
|
||||
return Utils.parseEscapedChars(input);
|
||||
runEscape: function(input, args) {
|
||||
return StrUtils._replaceByKeys(input, "unescaped", "escaped");
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Unescape string operation.
|
||||
*
|
||||
* @author Vel0x [dalemy@microsoft.com]
|
||||
*
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*
|
||||
* @example
|
||||
* StrUtils.runUnescape("Don\'t do that", [])
|
||||
* > "Don't do that"
|
||||
* StrUtils.runUnescape("Hello\nWorld", [])
|
||||
* > `Hello
|
||||
* World`
|
||||
*/
|
||||
runUnescape: function(input, args) {
|
||||
return StrUtils._replaceByKeys(input, "escaped", "unescaped");
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Replaces all matching tokens in ESCAPE_REPLACEMENTS with the correction. The
|
||||
* ordering is determined by the patternKey and the replacementKey.
|
||||
*
|
||||
* @author Vel0x [dalemy@microsoft.com]
|
||||
* @author Matt C [matt@artemisbot.uk]
|
||||
*
|
||||
* @param {string} input
|
||||
* @param {string} pattern_key
|
||||
* @param {string} replacement_key
|
||||
* @returns {string}
|
||||
*/
|
||||
_replaceByKeys: function(input, patternKey, replacementKey) {
|
||||
let output = input;
|
||||
|
||||
// Catch the \\x encoded characters
|
||||
if (patternKey === "escaped") output = Utils.parseEscapedChars(input);
|
||||
|
||||
StrUtils.ESCAPE_REPLACEMENTS.forEach(replacement => {
|
||||
output = output.split(replacement[patternKey]).join(replacement[replacementKey]);
|
||||
});
|
||||
return output;
|
||||
},
|
||||
|
||||
|
||||
|
@ -474,16 +468,16 @@ const StrUtils = {
|
|||
const splitInput = input.split(delimiter);
|
||||
|
||||
return splitInput
|
||||
.filter((line, lineIndex) => {
|
||||
lineIndex += 1;
|
||||
.filter((line, lineIndex) => {
|
||||
lineIndex += 1;
|
||||
|
||||
if (number < 0) {
|
||||
return lineIndex <= splitInput.length + number;
|
||||
} else {
|
||||
return lineIndex <= number;
|
||||
}
|
||||
})
|
||||
.join(delimiter);
|
||||
if (number < 0) {
|
||||
return lineIndex <= splitInput.length + number;
|
||||
} else {
|
||||
return lineIndex <= number;
|
||||
}
|
||||
})
|
||||
.join(delimiter);
|
||||
},
|
||||
|
||||
|
||||
|
@ -502,16 +496,16 @@ const StrUtils = {
|
|||
const splitInput = input.split(delimiter);
|
||||
|
||||
return splitInput
|
||||
.filter((line, lineIndex) => {
|
||||
lineIndex += 1;
|
||||
.filter((line, lineIndex) => {
|
||||
lineIndex += 1;
|
||||
|
||||
if (number < 0) {
|
||||
return lineIndex > -number;
|
||||
} else {
|
||||
return lineIndex > splitInput.length - number;
|
||||
}
|
||||
})
|
||||
.join(delimiter);
|
||||
if (number < 0) {
|
||||
return lineIndex > -number;
|
||||
} else {
|
||||
return lineIndex > splitInput.length - number;
|
||||
}
|
||||
})
|
||||
.join(delimiter);
|
||||
},
|
||||
|
||||
|
||||
|
|
|
@ -16,32 +16,32 @@ const Tidy = {
|
|||
* @constant
|
||||
* @default
|
||||
*/
|
||||
REMOVE_SPACES : true,
|
||||
REMOVE_SPACES: true,
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
REMOVE_CARIAGE_RETURNS : true,
|
||||
REMOVE_CARIAGE_RETURNS: true,
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
REMOVE_LINE_FEEDS : true,
|
||||
REMOVE_LINE_FEEDS: true,
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
REMOVE_TABS : true,
|
||||
REMOVE_TABS: true,
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
REMOVE_FORM_FEEDS : true,
|
||||
REMOVE_FORM_FEEDS: true,
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
REMOVE_FULL_STOPS : false,
|
||||
REMOVE_FULL_STOPS: false,
|
||||
|
||||
/**
|
||||
* Remove whitespace operation.
|
||||
|
@ -89,17 +89,17 @@ const Tidy = {
|
|||
* @constant
|
||||
* @default
|
||||
*/
|
||||
APPLY_TO_EACH_LINE : false,
|
||||
APPLY_TO_EACH_LINE: false,
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
DROP_START : 0,
|
||||
DROP_START: 0,
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
DROP_LENGTH : 5,
|
||||
DROP_LENGTH: 5,
|
||||
|
||||
/**
|
||||
* Drop bytes operation.
|
||||
|
@ -200,17 +200,17 @@ const Tidy = {
|
|||
* @constant
|
||||
* @default
|
||||
*/
|
||||
PAD_POSITION : ["Start", "End"],
|
||||
PAD_POSITION: ["Start", "End"],
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
PAD_LENGTH : 5,
|
||||
PAD_LENGTH: 5,
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
*/
|
||||
PAD_CHAR : " ",
|
||||
PAD_CHAR: " ",
|
||||
|
||||
/**
|
||||
* Pad lines operation.
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
/* globals unescape */
|
||||
import Utils from "../Utils.js";
|
||||
import url from "url";
|
||||
|
||||
|
||||
/**
|
||||
|
@ -58,56 +59,36 @@ const URL_ = {
|
|||
* @returns {string}
|
||||
*/
|
||||
runParse: function(input, args) {
|
||||
if (!document) {
|
||||
throw "This operation only works in a browser.";
|
||||
}
|
||||
const uri = url.parse(input, true);
|
||||
|
||||
const a = document.createElement("a");
|
||||
let output = "";
|
||||
|
||||
// Overwrite base href which will be the current CyberChef URL to reduce confusion.
|
||||
a.href = "http://example.com/";
|
||||
a.href = input;
|
||||
if (uri.protocol) output += "Protocol:\t" + uri.protocol + "\n";
|
||||
if (uri.auth) output += "Auth:\t\t" + uri.auth + "\n";
|
||||
if (uri.hostname) output += "Hostname:\t" + uri.hostname + "\n";
|
||||
if (uri.port) output += "Port:\t\t" + uri.port + "\n";
|
||||
if (uri.pathname) output += "Path name:\t" + uri.pathname + "\n";
|
||||
if (uri.query) {
|
||||
let keys = Object.keys(uri.query),
|
||||
padding = 0;
|
||||
|
||||
if (a.protocol) {
|
||||
let output = "";
|
||||
if (a.hostname !== window.location.hostname) {
|
||||
output = "Protocol:\t" + a.protocol + "\n";
|
||||
if (a.hostname) output += "Hostname:\t" + a.hostname + "\n";
|
||||
if (a.port) output += "Port:\t\t" + a.port + "\n";
|
||||
}
|
||||
keys.forEach(k => {
|
||||
padding = (k.length > padding) ? k.length : padding;
|
||||
});
|
||||
|
||||
if (a.pathname && a.pathname !== window.location.pathname) {
|
||||
let pathname = a.pathname;
|
||||
if (pathname.indexOf(window.location.pathname) === 0)
|
||||
pathname = pathname.replace(window.location.pathname, "");
|
||||
if (pathname)
|
||||
output += "Path name:\t" + pathname + "\n";
|
||||
}
|
||||
|
||||
if (a.hash && a.hash !== window.location.hash) {
|
||||
output += "Hash:\t\t" + a.hash + "\n";
|
||||
}
|
||||
|
||||
if (a.search && a.search !== window.location.search) {
|
||||
output += "Arguments:\n";
|
||||
const args_ = (a.search.slice(1, a.search.length)).split("&");
|
||||
let splitArgs = [], padding = 0, i;
|
||||
for (i = 0; i < args_.length; i++) {
|
||||
splitArgs.push(args_[i].split("="));
|
||||
padding = (splitArgs[i][0].length > padding) ? splitArgs[i][0].length : padding;
|
||||
}
|
||||
for (i = 0; i < splitArgs.length; i++) {
|
||||
output += "\t" + Utils.padRight(splitArgs[i][0], padding);
|
||||
if (splitArgs[i].length > 1 && splitArgs[i][1].length)
|
||||
output += " = " + splitArgs[i][1] + "\n";
|
||||
else output += "\n";
|
||||
output += "Arguments:\n";
|
||||
for (let key in uri.query) {
|
||||
output += "\t" + Utils.padRight(key, padding);
|
||||
if (uri.query[key].length) {
|
||||
output += " = " + uri.query[key] + "\n";
|
||||
} else {
|
||||
output += "\n";
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
if (uri.hash) output += "Hash:\t\t" + uri.hash + "\n";
|
||||
|
||||
return "Invalid URI";
|
||||
return output;
|
||||
},
|
||||
|
||||
|
||||
|
@ -127,7 +108,7 @@ const URL_ = {
|
|||
.replace(/\(/g, "%28")
|
||||
.replace(/\)/g, "%29")
|
||||
.replace(/\*/g, "%2A")
|
||||
.replace(/\-/g, "%2D")
|
||||
.replace(/-/g, "%2D")
|
||||
.replace(/\./g, "%2E")
|
||||
.replace(/_/g, "%5F")
|
||||
.replace(/~/g, "%7E");
|
||||
|
|
|
@ -9,17 +9,19 @@ require("babel-polyfill");
|
|||
|
||||
const Chef = require("../core/Chef.js").default;
|
||||
|
||||
const CyberChef = module.exports = {
|
||||
const CyberChef = {
|
||||
|
||||
bake: function(input, recipeConfig) {
|
||||
this.chef = new Chef();
|
||||
return this.chef.bake(
|
||||
input,
|
||||
recipeConfig,
|
||||
{},
|
||||
0,
|
||||
false
|
||||
);
|
||||
input,
|
||||
recipeConfig,
|
||||
{},
|
||||
0,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
module.exports = CyberChef;
|
||||
|
|
286
src/web/App.js
|
@ -1,5 +1,4 @@
|
|||
import Utils from "../core/Utils.js";
|
||||
import Chef from "../core/Chef.js";
|
||||
import Manager from "./Manager.js";
|
||||
import HTMLCategory from "./HTMLCategory.js";
|
||||
import HTMLOperation from "./HTMLOperation.js";
|
||||
|
@ -27,7 +26,6 @@ const App = function(categories, operations, defaultFavourites, defaultOptions)
|
|||
this.doptions = defaultOptions;
|
||||
this.options = Utils.extend({}, defaultOptions);
|
||||
|
||||
this.chef = new Chef();
|
||||
this.manager = new Manager(this);
|
||||
|
||||
this.baking = false;
|
||||
|
@ -35,8 +33,6 @@ const App = function(categories, operations, defaultFavourites, defaultOptions)
|
|||
this.autoBakePause = false;
|
||||
this.progress = 0;
|
||||
this.ingId = 0;
|
||||
|
||||
window.chef = this.chef;
|
||||
};
|
||||
|
||||
|
||||
|
@ -54,14 +50,23 @@ App.prototype.setup = function() {
|
|||
this.resetLayout();
|
||||
this.setCompileMessage();
|
||||
this.loadURIParams();
|
||||
|
||||
this.appLoaded = true;
|
||||
this.loaded();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Fires once all setup activities have completed.
|
||||
*
|
||||
* @fires Manager#apploaded
|
||||
*/
|
||||
App.prototype.loaded = function() {
|
||||
// Check that both the app and the worker have loaded successfully, and that
|
||||
// we haven't already loaded before attempting to remove the loading screen.
|
||||
if (!this.workerLoaded || !this.appLoaded ||
|
||||
!document.getElementById("loader-wrapper")) return;
|
||||
|
||||
// Trigger CSS animations to remove preloader
|
||||
document.body.classList.add("loaded");
|
||||
|
||||
|
@ -73,7 +78,9 @@ App.prototype.loaded = function() {
|
|||
}, 1000);
|
||||
|
||||
// Clear the loading message interval
|
||||
clearInterval(window.loadingMsgInt);
|
||||
clearInterval(window.loadingMsgsInt);
|
||||
|
||||
document.dispatchEvent(this.manager.apploaded);
|
||||
};
|
||||
|
||||
|
||||
|
@ -81,85 +88,34 @@ App.prototype.loaded = function() {
|
|||
* An error handler for displaying the error to the user.
|
||||
*
|
||||
* @param {Error} err
|
||||
* @param {boolean} [logToConsole=false]
|
||||
*/
|
||||
App.prototype.handleError = function(err) {
|
||||
console.error(err);
|
||||
App.prototype.handleError = function(err, logToConsole) {
|
||||
if (logToConsole) console.error(err);
|
||||
const msg = err.displayStr || err.toString();
|
||||
this.alert(msg, "danger", this.options.errorTimeout, !this.options.showErrors);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Updates the UI to show if baking is in process or not.
|
||||
*
|
||||
* @param {bakingStatus}
|
||||
*/
|
||||
App.prototype.setBakingStatus = function(bakingStatus) {
|
||||
this.baking = bakingStatus;
|
||||
|
||||
let inputLoadingIcon = document.querySelector("#input .title .loading-icon"),
|
||||
outputLoadingIcon = document.querySelector("#output .title .loading-icon"),
|
||||
outputElement = document.querySelector("#output-text");
|
||||
|
||||
if (bakingStatus) {
|
||||
inputLoadingIcon.style.display = "inline-block";
|
||||
outputLoadingIcon.style.display = "inline-block";
|
||||
outputElement.classList.add("disabled");
|
||||
outputElement.disabled = true;
|
||||
} else {
|
||||
inputLoadingIcon.style.display = "none";
|
||||
outputLoadingIcon.style.display = "none";
|
||||
outputElement.classList.remove("disabled");
|
||||
outputElement.disabled = false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Calls the Chef to bake the current input using the current recipe.
|
||||
* Asks the ChefWorker to bake the current input using the current recipe.
|
||||
*
|
||||
* @param {boolean} [step] - Set to true if we should only execute one operation instead of the
|
||||
* whole recipe.
|
||||
*/
|
||||
App.prototype.bake = async function(step) {
|
||||
let response;
|
||||
|
||||
App.prototype.bake = function(step) {
|
||||
if (this.baking) return;
|
||||
|
||||
this.setBakingStatus(true);
|
||||
// Reset attemptHighlight flag
|
||||
this.options.attemptHighlight = true;
|
||||
|
||||
try {
|
||||
response = await this.chef.bake(
|
||||
this.getInput(), // The user's input
|
||||
this.getRecipeConfig(), // The configuration of the recipe
|
||||
this.options, // Options set by the user
|
||||
this.progress, // The current position in the recipe
|
||||
step // Whether or not to take one step or execute the whole recipe
|
||||
);
|
||||
} catch (err) {
|
||||
this.handleError(err);
|
||||
}
|
||||
|
||||
this.setBakingStatus(false);
|
||||
|
||||
if (!response) return;
|
||||
|
||||
if (response.error) {
|
||||
this.handleError(response.error);
|
||||
}
|
||||
|
||||
this.options = response.options;
|
||||
this.dishStr = response.type === "html" ? Utils.stripHtmlTags(response.result, true) : response.result;
|
||||
this.progress = response.progress;
|
||||
this.manager.recipe.updateBreakpointIndicator(response.progress);
|
||||
this.manager.output.set(response.result, response.type, response.duration);
|
||||
|
||||
// If baking took too long, disable auto-bake
|
||||
if (response.duration > this.options.autoBakeThreshold && this.autoBake_) {
|
||||
this.manager.controls.setAutoBake(false);
|
||||
this.alert("Baking took longer than " + this.options.autoBakeThreshold +
|
||||
"ms, Auto Bake has been disabled.", "warning", 5000);
|
||||
}
|
||||
this.manager.worker.bake(
|
||||
this.getInput(), // The user's input
|
||||
this.getRecipeConfig(), // The configuration of the recipe
|
||||
this.options, // Options set by the user
|
||||
this.progress, // The current position in the recipe
|
||||
step // Whether or not to take one step or execute the whole recipe
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
|
@ -167,30 +123,36 @@ App.prototype.bake = async function(step) {
|
|||
* Runs Auto Bake if it is set.
|
||||
*/
|
||||
App.prototype.autoBake = function() {
|
||||
if (this.autoBake_ && !this.autoBakePause) {
|
||||
// If autoBakePause is set, we are loading a full recipe (and potentially input), so there is no
|
||||
// need to set the staleness indicator. Just exit and wait until auto bake is called after loading
|
||||
// has completed.
|
||||
if (this.autoBakePause) return false;
|
||||
|
||||
if (this.autoBake_ && !this.baking) {
|
||||
this.bake();
|
||||
} else {
|
||||
this.manager.controls.showStaleIndicator();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Runs a silent bake forcing the browser to load and cache all the relevant JavaScript code needed
|
||||
* Runs a silent bake, forcing the browser to load and cache all the relevant JavaScript code needed
|
||||
* to do a real bake.
|
||||
*
|
||||
* The output will not be modified (hence "silent" bake). This will only actually execute the
|
||||
* recipe if auto-bake is enabled, otherwise it will just load the recipe, ingredients and dish.
|
||||
*
|
||||
* @returns {number} - The number of miliseconds it took to run the silent bake.
|
||||
* The output will not be modified (hence "silent" bake). This will only actually execute the recipe
|
||||
* if auto-bake is enabled, otherwise it will just wake up the ChefWorker with an empty recipe.
|
||||
*/
|
||||
App.prototype.silentBake = function() {
|
||||
let startTime = new Date().getTime(),
|
||||
recipeConfig = this.getRecipeConfig();
|
||||
let recipeConfig = [];
|
||||
|
||||
if (this.autoBake_) {
|
||||
this.chef.silentBake(recipeConfig);
|
||||
// If auto-bake is not enabled we don't want to actually run the recipe as it may be disabled
|
||||
// for a good reason.
|
||||
recipeConfig = this.getRecipeConfig();
|
||||
}
|
||||
|
||||
return new Date().getTime() - startTime;
|
||||
this.manager.worker.silentBake(recipeConfig);
|
||||
};
|
||||
|
||||
|
||||
|
@ -200,13 +162,7 @@ App.prototype.silentBake = function() {
|
|||
* @returns {string}
|
||||
*/
|
||||
App.prototype.getInput = function() {
|
||||
const input = this.manager.input.get();
|
||||
|
||||
// Save to session storage in case we need to restore it later
|
||||
sessionStorage.setItem("inputLength", input.length);
|
||||
sessionStorage.setItem("input", input);
|
||||
|
||||
return input;
|
||||
return this.manager.input.get();
|
||||
};
|
||||
|
||||
|
||||
|
@ -216,8 +172,6 @@ App.prototype.getInput = function() {
|
|||
* @param {string} input - The string to set the input to
|
||||
*/
|
||||
App.prototype.setInput = function(input) {
|
||||
sessionStorage.setItem("inputLength", input.length);
|
||||
sessionStorage.setItem("input", input);
|
||||
this.manager.input.set(input);
|
||||
};
|
||||
|
||||
|
@ -268,7 +222,7 @@ App.prototype.populateOperationsList = function() {
|
|||
App.prototype.initialiseSplitter = function() {
|
||||
this.columnSplitter = Split(["#operations", "#recipe", "#IO"], {
|
||||
sizes: [20, 30, 50],
|
||||
minSize: [240, 325, 440],
|
||||
minSize: [240, 325, 450],
|
||||
gutterSize: 4,
|
||||
onDrag: function() {
|
||||
this.manager.controls.adjustWidth();
|
||||
|
@ -292,7 +246,7 @@ App.prototype.initialiseSplitter = function() {
|
|||
App.prototype.loadLocalStorage = function() {
|
||||
// Load options
|
||||
let lOptions;
|
||||
if (localStorage.options !== undefined) {
|
||||
if (this.isLocalStorageAvailable() && localStorage.options !== undefined) {
|
||||
lOptions = JSON.parse(localStorage.options);
|
||||
}
|
||||
this.manager.options.load(lOptions);
|
||||
|
@ -308,13 +262,17 @@ App.prototype.loadLocalStorage = function() {
|
|||
* If the user currently has no saved favourites, the defaults from the view constructor are used.
|
||||
*/
|
||||
App.prototype.loadFavourites = function() {
|
||||
let favourites = localStorage.favourites &&
|
||||
localStorage.favourites.length > 2 ?
|
||||
JSON.parse(localStorage.favourites) :
|
||||
this.dfavourites;
|
||||
let favourites;
|
||||
|
||||
favourites = this.validFavourites(favourites);
|
||||
this.saveFavourites(favourites);
|
||||
if (this.isLocalStorageAvailable()) {
|
||||
favourites = localStorage.favourites && localStorage.favourites.length > 2 ?
|
||||
JSON.parse(localStorage.favourites) :
|
||||
this.dfavourites;
|
||||
favourites = this.validFavourites(favourites);
|
||||
this.saveFavourites(favourites);
|
||||
} else {
|
||||
favourites = this.dfavourites;
|
||||
}
|
||||
|
||||
const favCat = this.categories.filter(function(c) {
|
||||
return c.name === "Favourites";
|
||||
|
@ -358,6 +316,15 @@ App.prototype.validFavourites = function(favourites) {
|
|||
* @param {string[]} favourites - A list of the user's favourite operations
|
||||
*/
|
||||
App.prototype.saveFavourites = function(favourites) {
|
||||
if (!this.isLocalStorageAvailable()) {
|
||||
this.alert(
|
||||
"Your security settings do not allow access to local storage so your favourites cannot be saved.",
|
||||
"danger",
|
||||
5000
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
localStorage.setItem("favourites", JSON.stringify(this.validFavourites(favourites)));
|
||||
};
|
||||
|
||||
|
@ -399,39 +366,29 @@ App.prototype.addFavourite = function(name) {
|
|||
* Checks for input and recipe in the URI parameters and loads them if present.
|
||||
*/
|
||||
App.prototype.loadURIParams = function() {
|
||||
// Load query string from URI
|
||||
this.queryString = (function(a) {
|
||||
if (a === "") return {};
|
||||
const b = {};
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
const p = a[i].split("=");
|
||||
if (p.length !== 2) {
|
||||
b[a[i]] = true;
|
||||
} else {
|
||||
b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " "));
|
||||
}
|
||||
}
|
||||
return b;
|
||||
})(window.location.search.substr(1).split("&"));
|
||||
// Load query string or hash from URI (depending on which is populated)
|
||||
// We prefer getting the hash by splitting the href rather than referencing
|
||||
// location.hash as some browsers (Firefox) automatically URL decode it,
|
||||
// which cause issues.
|
||||
const params = window.location.search ||
|
||||
window.location.href.split("#")[1] ||
|
||||
window.location.hash;
|
||||
this.uriParams = Utils.parseURIParams(params);
|
||||
|
||||
// Pause auto-bake while loading but don't modify `this.autoBake_`
|
||||
// otherwise `manualBake` cannot trigger.
|
||||
this.autoBakePause = true;
|
||||
|
||||
// Read in recipe from query string
|
||||
if (this.queryString.recipe) {
|
||||
// Read in recipe from URI params
|
||||
if (this.uriParams.recipe) {
|
||||
try {
|
||||
const recipeConfig = JSON.parse(this.queryString.recipe);
|
||||
const recipeConfig = Utils.parseRecipeConfig(this.uriParams.recipe);
|
||||
this.setRecipeConfig(recipeConfig);
|
||||
} catch (err) {}
|
||||
} else if (this.queryString.op) {
|
||||
} else if (this.uriParams.op) {
|
||||
// If there's no recipe, look for single operations
|
||||
this.manager.recipe.clearRecipe();
|
||||
try {
|
||||
this.manager.recipe.addOperation(this.queryString.op);
|
||||
this.manager.recipe.addOperation(this.uriParams.op);
|
||||
} catch (err) {
|
||||
// If no exact match, search for nearest match and add that
|
||||
const matchedOps = this.manager.ops.filterOperations(this.queryString.op, false);
|
||||
const matchedOps = this.manager.ops.filterOperations(this.uriParams.op, false);
|
||||
if (matchedOps.length) {
|
||||
this.manager.recipe.addOperation(matchedOps[0].name);
|
||||
}
|
||||
|
@ -439,21 +396,23 @@ App.prototype.loadURIParams = function() {
|
|||
// Populate search with the string
|
||||
const search = document.getElementById("search");
|
||||
|
||||
search.value = this.queryString.op;
|
||||
search.value = this.uriParams.op;
|
||||
search.dispatchEvent(new Event("search"));
|
||||
}
|
||||
}
|
||||
|
||||
// Read in input data from query string
|
||||
if (this.queryString.input) {
|
||||
// Read in input data from URI params
|
||||
if (this.uriParams.input) {
|
||||
this.autoBakePause = true;
|
||||
try {
|
||||
const inputData = Utils.fromBase64(this.queryString.input);
|
||||
const inputData = Utils.fromBase64(this.uriParams.input);
|
||||
this.setInput(inputData);
|
||||
} catch (err) {}
|
||||
} catch (err) {
|
||||
} finally {
|
||||
this.autoBakePause = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Unpause auto-bake
|
||||
this.autoBakePause = false;
|
||||
this.autoBake();
|
||||
};
|
||||
|
||||
|
@ -474,9 +433,7 @@ App.prototype.nextIngId = function() {
|
|||
* @returns {Object[]}
|
||||
*/
|
||||
App.prototype.getRecipeConfig = function() {
|
||||
const recipeConfig = this.manager.recipe.getConfig();
|
||||
sessionStorage.setItem("recipeConfig", JSON.stringify(recipeConfig));
|
||||
return recipeConfig;
|
||||
return this.manager.recipe.getConfig();
|
||||
};
|
||||
|
||||
|
||||
|
@ -486,15 +443,19 @@ App.prototype.getRecipeConfig = function() {
|
|||
* @param {Object[]} recipeConfig - The recipe configuration
|
||||
*/
|
||||
App.prototype.setRecipeConfig = function(recipeConfig) {
|
||||
sessionStorage.setItem("recipeConfig", JSON.stringify(recipeConfig));
|
||||
document.getElementById("rec-list").innerHTML = null;
|
||||
|
||||
// Pause auto-bake while loading but don't modify `this.autoBake_`
|
||||
// otherwise `manualBake` cannot trigger.
|
||||
this.autoBakePause = true;
|
||||
|
||||
for (let i = 0; i < recipeConfig.length; i++) {
|
||||
const item = this.manager.recipe.addOperation(recipeConfig[i].op);
|
||||
|
||||
// Populate arguments
|
||||
const args = item.querySelectorAll(".arg");
|
||||
for (let j = 0; j < args.length; j++) {
|
||||
if (recipeConfig[i].args[j] === undefined) continue;
|
||||
if (args[j].getAttribute("type") === "checkbox") {
|
||||
// checkbox
|
||||
args[j].checked = recipeConfig[i].args[j];
|
||||
|
@ -520,6 +481,9 @@ App.prototype.setRecipeConfig = function(recipeConfig) {
|
|||
|
||||
this.progress = 0;
|
||||
}
|
||||
|
||||
// Unpause auto bake
|
||||
this.autoBakePause = false;
|
||||
};
|
||||
|
||||
|
||||
|
@ -541,19 +505,44 @@ App.prototype.resetLayout = function() {
|
|||
App.prototype.setCompileMessage = function() {
|
||||
// Display time since last build and compile message
|
||||
let now = new Date(),
|
||||
timeSinceCompile = Utils.fuzzyTime(now.getTime() - window.compileTime),
|
||||
compileInfo = "<span style=\"font-weight: normal\">Last build: " +
|
||||
timeSinceCompile.substr(0, 1).toUpperCase() + timeSinceCompile.substr(1) + " ago";
|
||||
timeSinceCompile = Utils.fuzzyTime(now.getTime() - window.compileTime);
|
||||
|
||||
// Calculate previous version to compare to
|
||||
let prev = PKG_VERSION.split(".").map(n => {
|
||||
return parseInt(n, 10);
|
||||
});
|
||||
if (prev[2] > 0) prev[2]--;
|
||||
else if (prev[1] > 0) prev[1]--;
|
||||
else prev[0]--;
|
||||
|
||||
const compareURL = `https://github.com/gchq/CyberChef/compare/v${prev.join(".")}...v${PKG_VERSION}`;
|
||||
|
||||
let compileInfo = `<a href='${compareURL}'>Last build: ${timeSinceCompile.substr(0, 1).toUpperCase() + timeSinceCompile.substr(1)} ago</a>`;
|
||||
|
||||
if (window.compileMessage !== "") {
|
||||
compileInfo += " - " + window.compileMessage;
|
||||
}
|
||||
|
||||
compileInfo += "</span>";
|
||||
document.getElementById("notice").innerHTML = compileInfo;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Determines whether the browser supports Local Storage and if it is accessible.
|
||||
*
|
||||
* @returns {boolean}
|
||||
*/
|
||||
App.prototype.isLocalStorageAvailable = function() {
|
||||
try {
|
||||
if (!localStorage) return false;
|
||||
return true;
|
||||
} catch (err) {
|
||||
// Access to LocalStorage is denied
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Pops up a message to the user and writes it to the console log.
|
||||
*
|
||||
|
@ -674,10 +663,27 @@ App.prototype.alertCloseClick = function() {
|
|||
App.prototype.stateChange = function(e) {
|
||||
this.autoBake();
|
||||
|
||||
// Set title
|
||||
const recipeConfig = this.getRecipeConfig();
|
||||
let title = "CyberChef";
|
||||
if (recipeConfig.length === 1) {
|
||||
title = `${recipeConfig[0].op} - ${title}`;
|
||||
} else if (recipeConfig.length > 1) {
|
||||
// See how long the full recipe is
|
||||
const ops = recipeConfig.map(op => op.op).join(", ");
|
||||
if (ops.length < 45) {
|
||||
title = `${ops} - ${title}`;
|
||||
} else {
|
||||
// If it's too long, just use the first one and say how many more there are
|
||||
title = `${recipeConfig[0].op}, ${recipeConfig.length - 1} more - ${title}`;
|
||||
}
|
||||
}
|
||||
document.title = title;
|
||||
|
||||
// Update the current history state (not creating a new one)
|
||||
if (this.options.updateUrl) {
|
||||
this.lastStateUrl = this.manager.controls.generateStateUrl(true, true);
|
||||
window.history.replaceState({}, "CyberChef", this.lastStateUrl);
|
||||
this.lastStateUrl = this.manager.controls.generateStateUrl(true, true, recipeConfig);
|
||||
window.history.replaceState({}, title, this.lastStateUrl);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -689,9 +695,7 @@ App.prototype.stateChange = function(e) {
|
|||
* @param {event} e
|
||||
*/
|
||||
App.prototype.popState = function(e) {
|
||||
if (window.location.href.split("#")[0] !== this.lastStateUrl) {
|
||||
this.loadURIParams();
|
||||
}
|
||||
this.loadURIParams();
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -78,10 +78,11 @@ ControlsWaiter.prototype.setAutoBake = function(value) {
|
|||
* Handler to trigger baking.
|
||||
*/
|
||||
ControlsWaiter.prototype.bakeClick = function() {
|
||||
this.app.bake();
|
||||
const outputText = document.getElementById("output-text");
|
||||
outputText.focus();
|
||||
outputText.setSelectionRange(0, 0);
|
||||
if (document.getElementById("bake").textContent.indexOf("Bake") > 0) {
|
||||
this.app.bake();
|
||||
} else {
|
||||
this.manager.worker.cancelBake();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
@ -90,9 +91,6 @@ ControlsWaiter.prototype.bakeClick = function() {
|
|||
*/
|
||||
ControlsWaiter.prototype.stepClick = function() {
|
||||
this.app.bake(true);
|
||||
const outputText = document.getElementById("output-text");
|
||||
outputText.focus();
|
||||
outputText.setSelectionRange(0, 0);
|
||||
};
|
||||
|
||||
|
||||
|
@ -170,24 +168,25 @@ ControlsWaiter.prototype.generateStateUrl = function(includeRecipe, includeInput
|
|||
const link = baseURL || window.location.protocol + "//" +
|
||||
window.location.host +
|
||||
window.location.pathname;
|
||||
const recipeStr = JSON.stringify(recipeConfig);
|
||||
const recipeStr = Utils.generatePrettyRecipe(recipeConfig);
|
||||
const inputStr = Utils.toBase64(this.app.getInput(), "A-Za-z0-9+/"); // B64 alphabet with no padding
|
||||
|
||||
includeRecipe = includeRecipe && (recipeConfig.length > 0);
|
||||
includeInput = includeInput && (inputStr.length > 0) && (inputStr.length < 8000);
|
||||
// Only inlcude input if it is less than 50KB (51200 * 4/3 as it is Base64 encoded)
|
||||
includeInput = includeInput && (inputStr.length > 0) && (inputStr.length <= 68267);
|
||||
|
||||
const params = [
|
||||
includeRecipe ? ["recipe", recipeStr] : undefined,
|
||||
includeInput ? ["input", inputStr] : undefined,
|
||||
];
|
||||
|
||||
const query = params
|
||||
.filter(v => v)
|
||||
.map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
|
||||
.join("&");
|
||||
const hash = params
|
||||
.filter(v => v)
|
||||
.map(([key, value]) => `${key}=${Utils.encodeURIFragment(value)}`)
|
||||
.join("&");
|
||||
|
||||
if (query) {
|
||||
return `${link}?${query}`;
|
||||
if (hash) {
|
||||
return `${link}#${hash}`;
|
||||
}
|
||||
|
||||
return link;
|
||||
|
@ -197,9 +196,9 @@ ControlsWaiter.prototype.generateStateUrl = function(includeRecipe, includeInput
|
|||
/**
|
||||
* Handler for changes made to the save dialog text area. Re-initialises the save link.
|
||||
*/
|
||||
ControlsWaiter.prototype.saveTextChange = function() {
|
||||
ControlsWaiter.prototype.saveTextChange = function(e) {
|
||||
try {
|
||||
const recipeConfig = JSON.parse(document.getElementById("save-text").value);
|
||||
const recipeConfig = Utils.parseRecipeConfig(e.target.value);
|
||||
this.initialiseSaveLink(recipeConfig);
|
||||
} catch (err) {}
|
||||
};
|
||||
|
@ -210,9 +209,16 @@ ControlsWaiter.prototype.saveTextChange = function() {
|
|||
*/
|
||||
ControlsWaiter.prototype.saveClick = function() {
|
||||
const recipeConfig = this.app.getRecipeConfig();
|
||||
const recipeStr = JSON.stringify(recipeConfig).replace(/},{/g, "},\n{");
|
||||
const recipeStr = JSON.stringify(recipeConfig);
|
||||
|
||||
document.getElementById("save-text").value = recipeStr;
|
||||
document.getElementById("save-text-chef").value = Utils.generatePrettyRecipe(recipeConfig, true);
|
||||
document.getElementById("save-text-clean").value = JSON.stringify(recipeConfig, null, 2)
|
||||
.replace(/{\n\s+"/g, "{ \"")
|
||||
.replace(/\[\n\s{3,}/g, "[")
|
||||
.replace(/\n\s{3,}]/g, "]")
|
||||
.replace(/\s*\n\s*}/g, " }")
|
||||
.replace(/\n\s{6,}/g, " ");
|
||||
document.getElementById("save-text-compact").value = recipeStr;
|
||||
|
||||
this.initialiseSaveLink(recipeConfig);
|
||||
$("#save-modal").modal();
|
||||
|
@ -248,8 +254,17 @@ ControlsWaiter.prototype.loadClick = function() {
|
|||
* Saves the recipe specified in the save textarea to local storage.
|
||||
*/
|
||||
ControlsWaiter.prototype.saveButtonClick = function() {
|
||||
if (!this.app.isLocalStorageAvailable()) {
|
||||
this.app.alert(
|
||||
"Your security settings do not allow access to local storage so your recipe cannot be saved.",
|
||||
"danger",
|
||||
5000
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
||||
const recipeName = Utils.escapeHtml(document.getElementById("save-name").value);
|
||||
const recipeStr = document.getElementById("save-text").value;
|
||||
const recipeStr = document.querySelector("#save-texts .tab-pane.active textarea").value;
|
||||
|
||||
if (!recipeName) {
|
||||
this.app.alert("Please enter a recipe name", "danger", 2000);
|
||||
|
@ -277,6 +292,8 @@ ControlsWaiter.prototype.saveButtonClick = function() {
|
|||
* Populates the list of saved recipes in the load dialog box from local storage.
|
||||
*/
|
||||
ControlsWaiter.prototype.populateLoadRecipesList = function() {
|
||||
if (!this.app.isLocalStorageAvailable()) return false;
|
||||
|
||||
const loadNameEl = document.getElementById("load-name");
|
||||
|
||||
// Remove current recipes from select
|
||||
|
@ -287,7 +304,7 @@ ControlsWaiter.prototype.populateLoadRecipesList = function() {
|
|||
|
||||
// Add recipes to select
|
||||
const savedRecipes = localStorage.savedRecipes ?
|
||||
JSON.parse(localStorage.savedRecipes) : [];
|
||||
JSON.parse(localStorage.savedRecipes) : [];
|
||||
|
||||
for (i = 0; i < savedRecipes.length; i++) {
|
||||
const opt = document.createElement("option");
|
||||
|
@ -307,9 +324,11 @@ ControlsWaiter.prototype.populateLoadRecipesList = function() {
|
|||
* Removes the currently selected recipe from local storage.
|
||||
*/
|
||||
ControlsWaiter.prototype.loadDeleteClick = function() {
|
||||
if (!this.app.isLocalStorageAvailable()) return false;
|
||||
|
||||
const id = parseInt(document.getElementById("load-name").value, 10);
|
||||
const rawSavedRecipes = localStorage.savedRecipes ?
|
||||
JSON.parse(localStorage.savedRecipes) : [];
|
||||
JSON.parse(localStorage.savedRecipes) : [];
|
||||
|
||||
const savedRecipes = rawSavedRecipes.filter(r => r.id !== id);
|
||||
|
||||
|
@ -322,9 +341,11 @@ ControlsWaiter.prototype.loadDeleteClick = function() {
|
|||
* Displays the selected recipe in the load text box.
|
||||
*/
|
||||
ControlsWaiter.prototype.loadNameChange = function(e) {
|
||||
if (!this.app.isLocalStorageAvailable()) return false;
|
||||
|
||||
const el = e.target;
|
||||
const savedRecipes = localStorage.savedRecipes ?
|
||||
JSON.parse(localStorage.savedRecipes) : [];
|
||||
JSON.parse(localStorage.savedRecipes) : [];
|
||||
const id = parseInt(el.value, 10);
|
||||
|
||||
const recipe = savedRecipes.find(r => r.id === id);
|
||||
|
@ -338,8 +359,9 @@ ControlsWaiter.prototype.loadNameChange = function(e) {
|
|||
*/
|
||||
ControlsWaiter.prototype.loadButtonClick = function() {
|
||||
try {
|
||||
const recipeConfig = JSON.parse(document.getElementById("load-text").value);
|
||||
const recipeConfig = Utils.parseRecipeConfig(document.getElementById("load-text").value);
|
||||
this.app.setRecipeConfig(recipeConfig);
|
||||
this.app.autoBake();
|
||||
|
||||
$("#rec-list [data-toggle=popover]").popover();
|
||||
} catch (e) {
|
||||
|
@ -350,16 +372,66 @@ ControlsWaiter.prototype.loadButtonClick = function() {
|
|||
|
||||
/**
|
||||
* Populates the bug report information box with useful technical info.
|
||||
*
|
||||
* @param {event} e
|
||||
*/
|
||||
ControlsWaiter.prototype.supportButtonClick = function() {
|
||||
ControlsWaiter.prototype.supportButtonClick = function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const reportBugInfo = document.getElementById("report-bug-info");
|
||||
const saveLink = this.generateStateUrl(true, true, null, "https://gchq.github.io/CyberChef/");
|
||||
|
||||
if (reportBugInfo) {
|
||||
reportBugInfo.innerHTML = "* CyberChef compile time: " + COMPILE_TIME + "\n" +
|
||||
reportBugInfo.innerHTML = "* Version: " + PKG_VERSION + "\n" +
|
||||
"* Compile time: " + COMPILE_TIME + "\n" +
|
||||
"* User-Agent: \n" + navigator.userAgent + "\n" +
|
||||
"* [Link to reproduce](" + saveLink + ")\n\n";
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Shows the stale indicator to show that the input or recipe has changed
|
||||
* since the last bake.
|
||||
*/
|
||||
ControlsWaiter.prototype.showStaleIndicator = function() {
|
||||
const staleIndicator = document.getElementById("stale-indicator");
|
||||
|
||||
staleIndicator.style.visibility = "visible";
|
||||
staleIndicator.style.opacity = 1;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Hides the stale indicator to show that the input or recipe has not changed
|
||||
* since the last bake.
|
||||
*/
|
||||
ControlsWaiter.prototype.hideStaleIndicator = function() {
|
||||
const staleIndicator = document.getElementById("stale-indicator");
|
||||
|
||||
staleIndicator.style.opacity = 0;
|
||||
staleIndicator.style.visibility = "hidden";
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Switches the Bake button between 'Bake' and 'Cancel' functions.
|
||||
*
|
||||
* @param {boolean} cancel - Whether to change to cancel or not
|
||||
*/
|
||||
ControlsWaiter.prototype.toggleBakeButtonFunction = function(cancel) {
|
||||
const bakeButton = document.getElementById("bake"),
|
||||
btnText = bakeButton.querySelector("span");
|
||||
|
||||
if (cancel) {
|
||||
btnText.innerText = "Cancel";
|
||||
bakeButton.classList.remove("btn-success");
|
||||
bakeButton.classList.add("btn-danger");
|
||||
} else {
|
||||
btnText.innerText = "Bake!";
|
||||
bakeButton.classList.remove("btn-danger");
|
||||
bakeButton.classList.add("btn-success");
|
||||
}
|
||||
};
|
||||
|
||||
export default ControlsWaiter;
|
||||
|
|
|
@ -10,9 +10,11 @@ import Utils from "../core/Utils.js";
|
|||
*
|
||||
* @constructor
|
||||
* @param {App} app - The main view object for CyberChef.
|
||||
* @param {Manager} manager - The CyberChef event manager.
|
||||
*/
|
||||
const HighlighterWaiter = function(app) {
|
||||
const HighlighterWaiter = function(app, manager) {
|
||||
this.app = app;
|
||||
this.manager = manager;
|
||||
|
||||
this.mouseButtonDown = false;
|
||||
this.mouseTarget = null;
|
||||
|
@ -329,41 +331,6 @@ HighlighterWaiter.prototype.removeHighlights = function() {
|
|||
};
|
||||
|
||||
|
||||
/**
|
||||
* Generates a list of all the highlight functions assigned to operations in the recipe, if the
|
||||
* entire recipe supports highlighting.
|
||||
*
|
||||
* @returns {Object[]} highlights
|
||||
* @returns {function} highlights[].f
|
||||
* @returns {function} highlights[].b
|
||||
* @returns {Object[]} highlights[].args
|
||||
*/
|
||||
HighlighterWaiter.prototype.generateHighlightList = function() {
|
||||
const recipeConfig = this.app.getRecipeConfig();
|
||||
const highlights = [];
|
||||
|
||||
for (let i = 0; i < recipeConfig.length; i++) {
|
||||
if (recipeConfig[i].disabled) continue;
|
||||
|
||||
// If any breakpoints are set, do not attempt to highlight
|
||||
if (recipeConfig[i].breakpoint) return false;
|
||||
|
||||
const op = this.app.operations[recipeConfig[i].op];
|
||||
|
||||
// If any of the operations do not support highlighting, fail immediately.
|
||||
if (op.highlight === false || op.highlight === undefined) return false;
|
||||
|
||||
highlights.push({
|
||||
f: op.highlight,
|
||||
b: op.highlightReverse,
|
||||
args: recipeConfig[i].args
|
||||
});
|
||||
}
|
||||
|
||||
return highlights;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Highlights the given offsets in the output.
|
||||
* We will only highlight if:
|
||||
|
@ -376,26 +343,8 @@ HighlighterWaiter.prototype.generateHighlightList = function() {
|
|||
* @param {number} pos.end - The end offset.
|
||||
*/
|
||||
HighlighterWaiter.prototype.highlightOutput = function(pos) {
|
||||
const highlights = this.generateHighlightList();
|
||||
|
||||
if (!highlights || !this.app.autoBake_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < highlights.length; i++) {
|
||||
// Remove multiple highlights before processing again
|
||||
pos = [pos[0]];
|
||||
|
||||
if (typeof highlights[i].f == "function") {
|
||||
pos = highlights[i].f(pos, highlights[i].args);
|
||||
}
|
||||
}
|
||||
|
||||
document.getElementById("output-selection-info").innerHTML = this.selectionInfo(pos[0].start, pos[0].end);
|
||||
this.highlight(
|
||||
document.getElementById("output-text"),
|
||||
document.getElementById("output-highlighter"),
|
||||
pos);
|
||||
if (!this.app.autoBake_ || this.app.baking) return false;
|
||||
this.manager.worker.highlight(this.app.getRecipeConfig(), "forward", pos);
|
||||
};
|
||||
|
||||
|
||||
|
@ -411,25 +360,28 @@ HighlighterWaiter.prototype.highlightOutput = function(pos) {
|
|||
* @param {number} pos.end - The end offset.
|
||||
*/
|
||||
HighlighterWaiter.prototype.highlightInput = function(pos) {
|
||||
const highlights = this.generateHighlightList();
|
||||
if (!this.app.autoBake_ || this.app.baking) return false;
|
||||
this.manager.worker.highlight(this.app.getRecipeConfig(), "reverse", pos);
|
||||
};
|
||||
|
||||
if (!highlights || !this.app.autoBake_) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (let i = 0; i < highlights.length; i++) {
|
||||
// Remove multiple highlights before processing again
|
||||
pos = [pos[0]];
|
||||
/**
|
||||
* Displays highlight offsets sent back from the Chef.
|
||||
*
|
||||
* @param {Object} pos - The position object for the highlight.
|
||||
* @param {number} pos.start - The start offset.
|
||||
* @param {number} pos.end - The end offset.
|
||||
* @param {string} direction
|
||||
*/
|
||||
HighlighterWaiter.prototype.displayHighlights = function(pos, direction) {
|
||||
if (!pos) return;
|
||||
|
||||
if (typeof highlights[i].b == "function") {
|
||||
pos = highlights[i].b(pos, highlights[i].args);
|
||||
}
|
||||
}
|
||||
const io = direction === "forward" ? "output" : "input";
|
||||
|
||||
document.getElementById("input-selection-info").innerHTML = this.selectionInfo(pos[0].start, pos[0].end);
|
||||
document.getElementById(io + "-selection-info").innerHTML = this.selectionInfo(pos[0].start, pos[0].end);
|
||||
this.highlight(
|
||||
document.getElementById("input-text"),
|
||||
document.getElementById("input-highlighter"),
|
||||
document.getElementById(io + "-text"),
|
||||
document.getElementById(io + "-highlighter"),
|
||||
pos);
|
||||
};
|
||||
|
||||
|
@ -493,13 +445,14 @@ HighlighterWaiter.prototype.highlight = function(textarea, highlighter, pos) {
|
|||
//if (colour) cssClass += "-"+colour;
|
||||
|
||||
// Remove HTML tags
|
||||
text = text.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/\n/g, " ")
|
||||
// Convert placeholders to tags
|
||||
.replace(startPlaceholderRegex, "<span class=\""+cssClass+"\">")
|
||||
.replace(endPlaceholderRegex, "</span>") + " ";
|
||||
text = text
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/\n/g, " ")
|
||||
// Convert placeholders to tags
|
||||
.replace(startPlaceholderRegex, "<span class=\""+cssClass+"\">")
|
||||
.replace(endPlaceholderRegex, "</span>") + " ";
|
||||
|
||||
// Adjust width to allow for scrollbars
|
||||
highlighter.style.width = textarea.clientWidth + "px";
|
||||
|
|
|
@ -158,17 +158,13 @@ InputWaiter.prototype.inputDrop = function(e) {
|
|||
const CHUNK_SIZE = 20480; // 20KB
|
||||
|
||||
const setInput = function() {
|
||||
if (inputCharcode.length > 100000 && this.app.autoBake_) {
|
||||
this.manager.controls.setAutoBake(false);
|
||||
this.app.alert("Turned off Auto Bake as the input is large", "warning", 5000);
|
||||
const recipeConfig = this.app.getRecipeConfig();
|
||||
if (!recipeConfig[0] || recipeConfig[0].op !== "From Hex") {
|
||||
recipeConfig.unshift({op: "From Hex", args: ["Space"]});
|
||||
this.app.setRecipeConfig(recipeConfig);
|
||||
}
|
||||
|
||||
this.set(inputCharcode);
|
||||
const recipeConfig = this.app.getRecipeConfig();
|
||||
if (!recipeConfig[0] || recipeConfig[0].op !== "From Hex") {
|
||||
recipeConfig.unshift({op:"From Hex", args:["Space"]});
|
||||
this.app.setRecipeConfig(recipeConfig);
|
||||
}
|
||||
|
||||
el.classList.remove("loadingFile");
|
||||
}.bind(this);
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import WorkerWaiter from "./WorkerWaiter.js";
|
||||
import WindowWaiter from "./WindowWaiter.js";
|
||||
import ControlsWaiter from "./ControlsWaiter.js";
|
||||
import RecipeWaiter from "./RecipeWaiter.js";
|
||||
|
@ -27,6 +28,10 @@ const Manager = function(app) {
|
|||
* @event Manager#appstart
|
||||
*/
|
||||
this.appstart = new CustomEvent("appstart", {bubbles: true});
|
||||
/**
|
||||
* @event Manager#apploaded
|
||||
*/
|
||||
this.apploaded = new CustomEvent("apploaded", {bubbles: true});
|
||||
/**
|
||||
* @event Manager#operationadd
|
||||
*/
|
||||
|
@ -45,6 +50,7 @@ const Manager = function(app) {
|
|||
this.statechange = new CustomEvent("statechange", {bubbles: true});
|
||||
|
||||
// Define Waiter objects to handle various areas
|
||||
this.worker = new WorkerWaiter(this.app, this);
|
||||
this.window = new WindowWaiter(this.app);
|
||||
this.controls = new ControlsWaiter(this.app, this);
|
||||
this.recipe = new RecipeWaiter(this.app, this);
|
||||
|
@ -52,7 +58,7 @@ const Manager = function(app) {
|
|||
this.input = new InputWaiter(this.app, this);
|
||||
this.output = new OutputWaiter(this.app, this);
|
||||
this.options = new OptionsWaiter(this.app);
|
||||
this.highlighter = new HighlighterWaiter(this.app);
|
||||
this.highlighter = new HighlighterWaiter(this.app, this);
|
||||
this.seasonal = new SeasonalWaiter(this.app, this);
|
||||
|
||||
// Object to store dynamic handlers to fire on elements that may not exist yet
|
||||
|
@ -66,6 +72,7 @@ const Manager = function(app) {
|
|||
* Sets up the various components and listeners.
|
||||
*/
|
||||
Manager.prototype.setup = function() {
|
||||
this.worker.registerChefWorker();
|
||||
this.recipe.initialiseOperationDragNDrop();
|
||||
this.controls.autoBakeChange();
|
||||
this.seasonal.load();
|
||||
|
@ -98,7 +105,7 @@ Manager.prototype.initialiseEventListeners = function() {
|
|||
document.getElementById("load-name").addEventListener("change", this.controls.loadNameChange.bind(this.controls));
|
||||
document.getElementById("load-button").addEventListener("click", this.controls.loadButtonClick.bind(this.controls));
|
||||
document.getElementById("support").addEventListener("click", this.controls.supportButtonClick.bind(this.controls));
|
||||
this.addMultiEventListener("#save-text", "keyup paste", this.controls.saveTextChange, this.controls);
|
||||
this.addMultiEventListeners("#save-texts textarea", "keyup paste", this.controls.saveTextChange, this.controls);
|
||||
|
||||
// Operations
|
||||
this.addMultiEventListener("#search", "keyup paste search", this.ops.searchOperations, this.ops);
|
||||
|
@ -112,8 +119,8 @@ Manager.prototype.initialiseEventListeners = function() {
|
|||
this.addDynamicListener("li.operation", "operationadd", this.recipe.opAdd.bind(this.recipe));
|
||||
|
||||
// Recipe
|
||||
this.addDynamicListener(".arg", "keyup", this.recipe.ingChange, this.recipe);
|
||||
this.addDynamicListener(".arg", "change", this.recipe.ingChange, this.recipe);
|
||||
this.addDynamicListener(".arg:not(select)", "input", this.recipe.ingChange, this.recipe);
|
||||
this.addDynamicListener(".arg[type=checkbox], .arg[type=radio], select.arg", "change", this.recipe.ingChange, this.recipe);
|
||||
this.addDynamicListener(".disable-icon", "click", this.recipe.disableClick, this.recipe);
|
||||
this.addDynamicListener(".breakpoint", "click", this.recipe.breakpointClick, this.recipe);
|
||||
this.addDynamicListener("#rec-list li.operation", "dblclick", this.recipe.operationDblclick, this.recipe);
|
||||
|
@ -145,6 +152,7 @@ Manager.prototype.initialiseEventListeners = function() {
|
|||
document.getElementById("output-html").addEventListener("mousemove", this.highlighter.outputHtmlMousemove.bind(this.highlighter));
|
||||
this.addMultiEventListener("#output-text", "mousedown dblclick select", this.highlighter.outputMousedown, this.highlighter);
|
||||
this.addMultiEventListener("#output-html", "mousedown dblclick select", this.highlighter.outputHtmlMousedown, this.highlighter);
|
||||
this.addDynamicListener(".file-switch", "click", this.output.fileSwitch, this.output);
|
||||
|
||||
// Options
|
||||
document.getElementById("options").addEventListener("click", this.options.optionsClick.bind(this.options));
|
||||
|
|
|
@ -38,7 +38,6 @@ OperationsWaiter.prototype.searchOperations = function(e) {
|
|||
selected = this.getSelectedOp(ops);
|
||||
if (selected > -1) {
|
||||
this.manager.recipe.addOperation(ops[selected].innerHTML);
|
||||
this.app.autoBake();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -155,7 +154,35 @@ OperationsWaiter.prototype.getSelectedOp = function(ops) {
|
|||
*/
|
||||
OperationsWaiter.prototype.opListCreate = function(e) {
|
||||
this.manager.recipe.createSortableSeedList(e.target);
|
||||
$("[data-toggle=popover]").popover();
|
||||
this.enableOpsListPopovers(e.target);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets up popovers, allowing the popover itself to gain focus which enables scrolling
|
||||
* and other interactions.
|
||||
*
|
||||
* @param {Element} el - The element to start selecting from
|
||||
*/
|
||||
OperationsWaiter.prototype.enableOpsListPopovers = function(el) {
|
||||
$(el).find("[data-toggle=popover]").addBack("[data-toggle=popover]")
|
||||
.popover({trigger: "manual"})
|
||||
.on("mouseenter", function() {
|
||||
const _this = this;
|
||||
$(this).popover("show");
|
||||
$(".popover").on("mouseleave", function () {
|
||||
$(_this).popover("hide");
|
||||
});
|
||||
}).on("mouseleave", function () {
|
||||
const _this = this;
|
||||
setTimeout(function() {
|
||||
// Determine if the popover associated with this element is being hovered over
|
||||
if ($(_this).data("bs.popover") &&
|
||||
!$(_this).data("bs.popover").$tip.is(":hover")) {
|
||||
$(_this).popover("hide");
|
||||
}
|
||||
}, 50);
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
|
@ -169,7 +196,6 @@ OperationsWaiter.prototype.operationDblclick = function(e) {
|
|||
const li = e.target;
|
||||
|
||||
this.manager.recipe.addOperation(li.textContent);
|
||||
this.app.autoBake();
|
||||
};
|
||||
|
||||
|
||||
|
@ -203,7 +229,7 @@ OperationsWaiter.prototype.editFavouritesClick = function(e) {
|
|||
filter: ".remove-icon",
|
||||
onFilter: function (evt) {
|
||||
const el = editableList.closest(evt.item);
|
||||
if (el) {
|
||||
if (el && el.parentNode) {
|
||||
$(el).popover("destroy");
|
||||
el.parentNode.removeChild(el);
|
||||
}
|
||||
|
|
|
@ -57,8 +57,11 @@ OptionsWaiter.prototype.load = function(options) {
|
|||
/**
|
||||
* Handler for options click events.
|
||||
* Dispays the options pane.
|
||||
*
|
||||
* @param {event} e
|
||||
*/
|
||||
OptionsWaiter.prototype.optionsClick = function() {
|
||||
OptionsWaiter.prototype.optionsClick = function(e) {
|
||||
e.preventDefault();
|
||||
$("#options-modal").modal();
|
||||
};
|
||||
|
||||
|
@ -84,7 +87,9 @@ OptionsWaiter.prototype.switchChange = function(e, state) {
|
|||
const option = el.getAttribute("option");
|
||||
|
||||
this.app.options[option] = state;
|
||||
localStorage.setItem("options", JSON.stringify(this.app.options));
|
||||
|
||||
if (this.app.isLocalStorageAvailable())
|
||||
localStorage.setItem("options", JSON.stringify(this.app.options));
|
||||
};
|
||||
|
||||
|
||||
|
@ -99,7 +104,9 @@ OptionsWaiter.prototype.numberChange = function(e) {
|
|||
const option = el.getAttribute("option");
|
||||
|
||||
this.app.options[option] = parseInt(el.value, 10);
|
||||
localStorage.setItem("options", JSON.stringify(this.app.options));
|
||||
|
||||
if (this.app.isLocalStorageAvailable())
|
||||
localStorage.setItem("options", JSON.stringify(this.app.options));
|
||||
};
|
||||
|
||||
|
||||
|
@ -114,7 +121,9 @@ OptionsWaiter.prototype.selectChange = function(e) {
|
|||
const option = el.getAttribute("option");
|
||||
|
||||
this.app.options[option] = el.value;
|
||||
localStorage.setItem("options", JSON.stringify(this.app.options));
|
||||
|
||||
if (this.app.isLocalStorageAvailable())
|
||||
localStorage.setItem("options", JSON.stringify(this.app.options));
|
||||
};
|
||||
|
||||
|
||||
|
|
|
@ -167,6 +167,17 @@ OutputWaiter.prototype.undoSwitchClick = function() {
|
|||
document.getElementById("undo-switch").disabled = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Handler for file switch click events.
|
||||
* Moves a files data for items created via Utils.displayFilesAsHTML to the input.
|
||||
*/
|
||||
OutputWaiter.prototype.fileSwitch = function(e) {
|
||||
e.preventDefault();
|
||||
this.switchOrigData = this.manager.input.get();
|
||||
this.app.setInput(e.target.getAttribute("fileValue"));
|
||||
document.getElementById("undo-switch").disabled = false;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handler for maximise output click events.
|
||||
|
@ -190,4 +201,44 @@ OutputWaiter.prototype.maximiseOutputClick = function(e) {
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Shows or hides the loading icon.
|
||||
*
|
||||
* @param {boolean} value
|
||||
*/
|
||||
OutputWaiter.prototype.toggleLoader = function(value) {
|
||||
const outputLoader = document.getElementById("output-loader"),
|
||||
outputElement = document.getElementById("output-text");
|
||||
|
||||
if (value) {
|
||||
this.manager.controls.hideStaleIndicator();
|
||||
this.bakingStatusTimeout = setTimeout(function() {
|
||||
outputElement.disabled = true;
|
||||
outputLoader.style.visibility = "visible";
|
||||
outputLoader.style.opacity = 1;
|
||||
this.manager.controls.toggleBakeButtonFunction(true);
|
||||
}.bind(this), 200);
|
||||
} else {
|
||||
clearTimeout(this.bakingStatusTimeout);
|
||||
outputElement.disabled = false;
|
||||
outputLoader.style.opacity = 0;
|
||||
outputLoader.style.visibility = "hidden";
|
||||
this.manager.controls.toggleBakeButtonFunction(false);
|
||||
this.setStatusMsg("");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the baking status message value.
|
||||
*
|
||||
* @param {string} msg
|
||||
*/
|
||||
OutputWaiter.prototype.setStatusMsg = function(msg) {
|
||||
const el = document.querySelector("#output-loader .loading-msg");
|
||||
|
||||
el.textContent = msg;
|
||||
};
|
||||
|
||||
export default OutputWaiter;
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import HTMLOperation from "./HTMLOperation.js";
|
||||
import Sortable from "sortablejs";
|
||||
import Utils from "../core/Utils.js";
|
||||
|
||||
|
||||
/**
|
||||
|
@ -93,7 +94,7 @@ RecipeWaiter.prototype.createSortableSeedList = function(listEl) {
|
|||
// Removes popover element and event bindings from the dragged operation but not the
|
||||
// event bindings from the one left in the operations list. Without manually removing
|
||||
// these bindings, we cannot re-initialise the popover on the stub operation.
|
||||
$(evt.item).popover("destroy");
|
||||
$(evt.item).popover("destroy").removeData("bs.popover").off("mouseenter").off("mouseleave");
|
||||
$(evt.clone).off(".popover").removeData("bs.popover");
|
||||
evt.item.setAttribute("data-toggle", "popover-disabled");
|
||||
},
|
||||
|
@ -120,8 +121,7 @@ RecipeWaiter.prototype.opSortEnd = function(evt) {
|
|||
|
||||
// Reinitialise the popover on the original element in the ops list because for some reason it
|
||||
// gets destroyed and recreated.
|
||||
$(evt.clone).popover();
|
||||
$(evt.clone).children("[data-toggle=popover]").popover();
|
||||
this.manager.ops.enableOpsListPopovers(evt.clone);
|
||||
|
||||
if (evt.item.parentNode.id !== "rec-list") {
|
||||
return;
|
||||
|
@ -192,7 +192,7 @@ RecipeWaiter.prototype.favDrop = function(e) {
|
|||
*
|
||||
* @fires Manager#statechange
|
||||
*/
|
||||
RecipeWaiter.prototype.ingChange = function() {
|
||||
RecipeWaiter.prototype.ingChange = function(e) {
|
||||
window.dispatchEvent(this.manager.statechange);
|
||||
};
|
||||
|
||||
|
@ -296,6 +296,9 @@ RecipeWaiter.prototype.getConfig = function() {
|
|||
option: ingList[j].previousSibling.children[0].textContent.slice(0, -1),
|
||||
string: ingList[j].value
|
||||
};
|
||||
} else if (ingList[j].getAttribute("type") === "number") {
|
||||
// number
|
||||
ingredients[j] = parseFloat(ingList[j].value, 10);
|
||||
} else {
|
||||
// all others
|
||||
ingredients[j] = ingList[j].value;
|
||||
|
@ -433,4 +436,30 @@ RecipeWaiter.prototype.opRemove = function(e) {
|
|||
window.dispatchEvent(this.manager.statechange);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets register values.
|
||||
*
|
||||
* @param {number} opIndex
|
||||
* @param {number} numPrevRegisters
|
||||
* @param {string[]} registers
|
||||
*/
|
||||
RecipeWaiter.prototype.setRegisters = function(opIndex, numPrevRegisters, registers) {
|
||||
const op = document.querySelector(`#rec-list .operation:nth-child(${opIndex + 1})`),
|
||||
prevRegList = op.querySelector(".register-list");
|
||||
|
||||
// Remove previous div
|
||||
if (prevRegList) prevRegList.remove();
|
||||
|
||||
let registerList = [];
|
||||
for (let i = 0; i < registers.length; i++) {
|
||||
registerList.push(`$R${numPrevRegisters + i} = ${Utils.escapeHtml(Utils.truncate(Utils.printable(registers[i]), 100))}`);
|
||||
}
|
||||
const registerListEl = `<div class="register-list">
|
||||
${registerList.join("<br>")}
|
||||
</div>`;
|
||||
|
||||
op.insertAdjacentHTML("beforeend", registerListEl);
|
||||
};
|
||||
|
||||
export default RecipeWaiter;
|
||||
|
|
183
src/web/WorkerWaiter.js
Normal file
|
@ -0,0 +1,183 @@
|
|||
import Utils from "../core/Utils.js";
|
||||
import ChefWorker from "worker-loader?inline&fallback=false!../core/ChefWorker.js";
|
||||
|
||||
/**
|
||||
* Waiter to handle conversations with the ChefWorker.
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*
|
||||
* @constructor
|
||||
* @param {App} app - The main view object for CyberChef.
|
||||
* @param {Manager} manager - The CyberChef event manager.
|
||||
*/
|
||||
const WorkerWaiter = function(app, manager) {
|
||||
this.app = app;
|
||||
this.manager = manager;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets up the ChefWorker and associated listeners.
|
||||
*/
|
||||
WorkerWaiter.prototype.registerChefWorker = function() {
|
||||
this.chefWorker = new ChefWorker();
|
||||
this.chefWorker.addEventListener("message", this.handleChefMessage.bind(this));
|
||||
|
||||
let docURL = document.location.href.split(/[#?]/)[0];
|
||||
const index = docURL.lastIndexOf("/");
|
||||
if (index > 0) {
|
||||
docURL = docURL.substring(0, index);
|
||||
}
|
||||
this.chefWorker.postMessage({"action": "docURL", "data": docURL});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handler for messages sent back by the ChefWorker.
|
||||
*
|
||||
* @param {MessageEvent} e
|
||||
*/
|
||||
WorkerWaiter.prototype.handleChefMessage = function(e) {
|
||||
const r = e.data;
|
||||
switch (r.action) {
|
||||
case "bakeSuccess":
|
||||
this.bakingComplete(r.data);
|
||||
break;
|
||||
case "bakeError":
|
||||
this.app.handleError(r.data);
|
||||
this.setBakingStatus(false);
|
||||
break;
|
||||
case "silentBakeComplete":
|
||||
break;
|
||||
case "workerLoaded":
|
||||
this.app.workerLoaded = true;
|
||||
this.app.loaded();
|
||||
break;
|
||||
case "statusMessage":
|
||||
this.manager.output.setStatusMsg(r.data);
|
||||
break;
|
||||
case "optionUpdate":
|
||||
this.app.options[r.data.option] = r.data.value;
|
||||
break;
|
||||
case "setRegisters":
|
||||
this.manager.recipe.setRegisters(r.data.opIndex, r.data.numPrevRegisters, r.data.registers);
|
||||
break;
|
||||
case "highlightsCalculated":
|
||||
this.manager.highlighter.displayHighlights(r.data.pos, r.data.direction);
|
||||
break;
|
||||
default:
|
||||
console.error("Unrecognised message from ChefWorker", e);
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Updates the UI to show if baking is in process or not.
|
||||
*
|
||||
* @param {bakingStatus}
|
||||
*/
|
||||
WorkerWaiter.prototype.setBakingStatus = function(bakingStatus) {
|
||||
this.app.baking = bakingStatus;
|
||||
|
||||
this.manager.output.toggleLoader(bakingStatus);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Cancels the current bake by terminating the ChefWorker and creating a new one.
|
||||
*/
|
||||
WorkerWaiter.prototype.cancelBake = function() {
|
||||
this.chefWorker.terminate();
|
||||
this.registerChefWorker();
|
||||
this.setBakingStatus(false);
|
||||
this.manager.controls.showStaleIndicator();
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handler for completed bakes.
|
||||
*
|
||||
* @param {Object} response
|
||||
*/
|
||||
WorkerWaiter.prototype.bakingComplete = function(response) {
|
||||
this.setBakingStatus(false);
|
||||
|
||||
if (!response) return;
|
||||
|
||||
if (response.error) {
|
||||
this.app.handleError(response.error);
|
||||
}
|
||||
|
||||
this.app.dishStr = response.type === "html" ? Utils.stripHtmlTags(response.result, true) : response.result;
|
||||
this.app.progress = response.progress;
|
||||
this.manager.recipe.updateBreakpointIndicator(response.progress);
|
||||
this.manager.output.set(response.result, response.type, response.duration);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Asks the ChefWorker to bake the current input using the current recipe.
|
||||
*
|
||||
* @param {string} input
|
||||
* @param {Object[]} recipeConfig
|
||||
* @param {Object} options
|
||||
* @param {number} progress
|
||||
* @param {boolean} step
|
||||
*/
|
||||
WorkerWaiter.prototype.bake = function(input, recipeConfig, options, progress, step) {
|
||||
this.setBakingStatus(true);
|
||||
|
||||
this.chefWorker.postMessage({
|
||||
action: "bake",
|
||||
data: {
|
||||
input: input,
|
||||
recipeConfig: recipeConfig,
|
||||
options: options,
|
||||
progress: progress,
|
||||
step: step
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Asks the ChefWorker to run a silent bake, forcing the browser to load and cache all the relevant
|
||||
* JavaScript code needed to do a real bake.
|
||||
*
|
||||
* @param {Objectp[]} [recipeConfig]
|
||||
*/
|
||||
WorkerWaiter.prototype.silentBake = function(recipeConfig) {
|
||||
this.chefWorker.postMessage({
|
||||
action: "silentBake",
|
||||
data: {
|
||||
recipeConfig: recipeConfig
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Asks the ChefWorker to calculate highlight offsets if possible.
|
||||
*
|
||||
* @param {Object[]} recipeConfig
|
||||
* @param {string} direction
|
||||
* @param {Object} pos - The position object for the highlight.
|
||||
* @param {number} pos.start - The start offset.
|
||||
* @param {number} pos.end - The end offset.
|
||||
*/
|
||||
WorkerWaiter.prototype.highlight = function(recipeConfig, direction, pos) {
|
||||
this.chefWorker.postMessage({
|
||||
action: "highlight",
|
||||
data: {
|
||||
recipeConfig: recipeConfig,
|
||||
direction: direction,
|
||||
pos: pos
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
export default WorkerWaiter;
|
|
@ -26,14 +26,20 @@
|
|||
<title>CyberChef</title>
|
||||
|
||||
<meta name="copyright" content="Crown Copyright 2016" />
|
||||
<meta name="description" content="The Cyber Swiss Army Knife" />
|
||||
<meta name="description" content="The Cyber Swiss Army Knife - a web app for encryption, encoding, compression and data analysis" />
|
||||
<meta name="keywords" content="base64, hex, decode, encode, encrypt, decrypt, compress, decompress, regex, regular expressions, hash, crypt, hexadecimal, user agent, url, certificate, x.509, parser, JSON, gzip, md5, sha1, aes, des, blowfish, xor" />
|
||||
|
||||
<link rel="icon" type="image/ico" href="<%- require('../static/images/favicon.ico') %>" />
|
||||
|
||||
<script type="application/javascript">
|
||||
"use strict";
|
||||
|
||||
// Load theme before the preloader is shown
|
||||
document.querySelector(":root").className = JSON.parse(localStorage.getItem("options")).theme;
|
||||
try {
|
||||
document.querySelector(":root").className = (JSON.parse(localStorage.getItem("options")) || {}).theme;
|
||||
} catch (err) {
|
||||
// LocalStorage access is denied by security settings
|
||||
}
|
||||
|
||||
// Define loading messages
|
||||
const loadingMsgs = [
|
||||
|
@ -44,10 +50,15 @@
|
|||
"Initialising Skynet...",
|
||||
"[REDACTED]",
|
||||
"Downloading more RAM...",
|
||||
"Loading more loading messages...",
|
||||
"Ordering 1s and 0s...",
|
||||
"Navigating neural network...",
|
||||
"Importing machine learning..."
|
||||
"Importing machine learning...",
|
||||
"Issuing Alice and Bob one-time pads...",
|
||||
"Mining bitcoin cash...",
|
||||
"Generating key material by trying to escape vim...",
|
||||
"for i in range(additional): Pylon()",
|
||||
"(creating unresolved tension...",
|
||||
"Symlinking emacs and vim to ed...",
|
||||
];
|
||||
|
||||
// Shuffle array using Durstenfeld algorithm
|
||||
|
@ -58,26 +69,32 @@
|
|||
loadingMsgs[j] = temp;
|
||||
}
|
||||
|
||||
// Show next loading message then move it to the end of the array
|
||||
// Show next loading message and move it to the end of the array
|
||||
function changeLoadingMsg() {
|
||||
const msg = loadingMsgs.shift();
|
||||
loadingMsgs.push(msg);
|
||||
try {
|
||||
const el = document.getElementById("preloader-msg");
|
||||
el.className = "loading"; // Causes CSS transition on first message
|
||||
if (!el.classList.contains("loading"))
|
||||
el.classList.add("loading"); // Causes CSS transition on first message
|
||||
el.innerHTML = msg;
|
||||
} catch (err) {} // Ignore errors if DOM not yet ready
|
||||
loadingMsgs.push(msg);
|
||||
}
|
||||
|
||||
changeLoadingMsg();
|
||||
window.loadingMsgsInt = setInterval(changeLoadingMsg, (Math.random() * 1000) + 1000);
|
||||
window.loadingMsgsInt = setInterval(changeLoadingMsg, (Math.random() * 2000) + 1500);
|
||||
</script>
|
||||
<% if (!htmlWebpackPlugin.options.inline) { %>
|
||||
<script type="application/ld+json">
|
||||
<% print(JSON.stringify(require("../static/structuredData.json"))); %>
|
||||
</script>
|
||||
<% } %>
|
||||
</head>
|
||||
<body>
|
||||
<!-- Preloader overlay -->
|
||||
<div id="loader-wrapper">
|
||||
<div id="preloader"></div>
|
||||
<div id="preloader-msg"></div>
|
||||
<div id="preloader" class="loader"></div>
|
||||
<div id="preloader-msg" class="loading-msg"></div>
|
||||
</div>
|
||||
<!-- End preloader overlay -->
|
||||
<span id="edit-favourites" class="btn btn-default btn-sm"><img aria-hidden="true" src="<%- require('../static/images/favourite-16x16.png') %>" alt="Star Icon"/> Edit</span>
|
||||
|
@ -87,23 +104,29 @@
|
|||
</div>
|
||||
<div id="content-wrapper">
|
||||
<div id="banner">
|
||||
<% if (htmlWebpackPlugin.options.inline) { %>
|
||||
<span style="float: left; margin-left: 10px;">Compile time: <%= htmlWebpackPlugin.options.compileTime %></span>
|
||||
<% } else { %>
|
||||
<a href="cyberchef.htm" style="float: left; margin-left: 10px; margin-right: 80px;" download>Download CyberChef<img aria-hidden="true" src="<%- require('../static/images/download-24x24.png') %>" alt="Download Icon"/></a>
|
||||
<% } %>
|
||||
<span id="notice">
|
||||
<script type="text/javascript">
|
||||
// Must be text/javascript rather than application/javascript otherwise IE won't recognise it...
|
||||
if (navigator.userAgent && navigator.userAgent.match(/MSIE \d\d?\./)) {
|
||||
document.write("Internet Explorer is not supported, please use Firefox or Chrome instead");
|
||||
alert("Internet Explorer is not supported, please use Firefox or Chrome instead");
|
||||
}
|
||||
</script>
|
||||
<noscript>JavaScript is not enabled. Good luck.</noscript>
|
||||
</span>
|
||||
<a href="#" id="support" class="banner-right" data-toggle="modal" data-target="#support-modal">About / Support<img aria-hidden="true" src="<%- require('../static/images/help-22x22.png') %>" alt="Question Mark Icon"/></a>
|
||||
<a href="#" id="options" class="banner-right">Options<img aria-hidden="true" src="<%- require('../static/images/settings-22x22.png') %>" alt="Settings Icon"/></a>
|
||||
<div class="col-md-4" style="text-align: left; padding-left: 10px;">
|
||||
<% if (htmlWebpackPlugin.options.inline) { %>
|
||||
<span>Version <%= htmlWebpackPlugin.options.version %></span>
|
||||
<% } else { %>
|
||||
<a href="cyberchef.htm" download>Download CyberChef<img aria-hidden="true" src="<%- require('../static/images/download-24x24.png') %>" alt="Download Icon"/></a>
|
||||
<% } %>
|
||||
</div>
|
||||
<div class="col-md-4" style="text-align: center;">
|
||||
<span id="notice">
|
||||
<script type="text/javascript">
|
||||
// Must be text/javascript rather than application/javascript otherwise IE won't recognise it...
|
||||
if (navigator.userAgent && navigator.userAgent.match(/MSIE \d\d?\./)) {
|
||||
document.write("Internet Explorer is not supported, please use Firefox or Chrome instead");
|
||||
alert("Internet Explorer is not supported, please use Firefox or Chrome instead");
|
||||
}
|
||||
</script>
|
||||
<noscript>JavaScript is not enabled. Good luck.</noscript>
|
||||
</span>
|
||||
</div>
|
||||
<div class="col-md-4" style="text-align: right; padding-right: 0;">
|
||||
<a href="#" id="options">Options<img aria-hidden="true" src="<%- require('../static/images/settings-22x22.png') %>" alt="Settings Icon"/></a>
|
||||
<a href="#" id="support" data-toggle="modal" data-target="#support-modal">About / Support<img aria-hidden="true" src="<%- require('../static/images/help-22x22.png') %>" alt="Question Mark Icon"/></a>
|
||||
</div>
|
||||
</div>
|
||||
<div id="workspace-wrapper">
|
||||
<div id="operations" class="split split-horizontal no-select">
|
||||
|
@ -122,7 +145,7 @@
|
|||
<div id="bake-group">
|
||||
<button type="button" class="btn btn-success btn-lg" id="bake">
|
||||
<img aria-hidden="true" src="<%- require('../static/images/cook_male-32x32.png') %>" alt="Chef Icon"/>
|
||||
Bake!
|
||||
<span>Bake!</span>
|
||||
</button>
|
||||
<label class="btn btn-success btn-lg" id="auto-bake-label" for="auto-bake">
|
||||
<input type="checkbox" checked="checked" id="auto-bake">
|
||||
|
@ -148,7 +171,6 @@
|
|||
<div id="input" class="split no-select">
|
||||
<div class="title no-select">
|
||||
<label for="input-text">Input</label>
|
||||
<div class="loading-icon" style="display: none"></div>
|
||||
<div class="btn-group io-btn-group">
|
||||
<button type="button" class="btn btn-default btn-sm" id="clr-io"><img aria-hidden="true" src="<%- require('../static/images/recycle-16x16.png') %>" alt="Recycle Icon"/> Clear I/O</button>
|
||||
<button type="button" class="btn btn-default btn-sm" id="reset-layout"><img aria-hidden="true" src="<%- require('../static/images/layout-16x16.png') %>" alt="Grid Icon"/> Reset layout</button>
|
||||
|
@ -165,7 +187,6 @@
|
|||
<div id="output" class="split">
|
||||
<div class="title no-select">
|
||||
<label for="output-text">Output</label>
|
||||
<div class="loading-icon" style="display: none"></div>
|
||||
<div class="btn-group io-btn-group">
|
||||
<button type="button" class="btn btn-default btn-sm" id="save-to-file" title="Save to file"><img aria-hidden="true" src="<%- require('../static/images/save_as-16x16.png') %>" alt="Save Icon"/> Save to file</button>
|
||||
<button type="button" class="btn btn-default btn-sm" id="switch" title="Move output to input"><img aria-hidden="true" src="<%- require('../static/images/switch-16x16.png') %>" alt="Switch Icon"/> Move output to input</button>
|
||||
|
@ -174,11 +195,16 @@
|
|||
</div>
|
||||
<div class="io-info" id="output-info"></div>
|
||||
<div class="io-info" id="output-selection-info"></div>
|
||||
<span id="stale-indicator" title="The output is stale. The input or recipe has changed since this output was generated. Bake again to get the new value.">🕑</span>
|
||||
</div>
|
||||
<div class="textarea-wrapper">
|
||||
<div id="output-highlighter" class="no-select"></div>
|
||||
<div id="output-html"></div>
|
||||
<textarea id="output-text" readonly="readonly"></textarea>
|
||||
<div id="output-loader">
|
||||
<div class="loader"></div>
|
||||
<div class="loading-msg"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -195,7 +221,22 @@
|
|||
<div class="modal-body">
|
||||
<div class="form-group">
|
||||
<label for="save-text">Save your recipe to local storage or copy the following string to load later</label>
|
||||
<textarea class="form-control" id="save-text" rows="5"></textarea>
|
||||
<ul class="nav nav-tabs" role="tablist">
|
||||
<li role="presentation" class="active"><a href="#chef-format" role="tab" data-toggle="tab">Chef format</a></li>
|
||||
<li role="presentation"><a href="#clean-json" role="tab" data-toggle="tab">Clean JSON</a></li>
|
||||
<li role="presentation"><a href="#compact-json" role="tab" data-toggle="tab">Compact JSON</a></li>
|
||||
</ul>
|
||||
<div class="tab-content" id="save-texts">
|
||||
<div role="tabpanel" class="tab-pane active" id="chef-format">
|
||||
<textarea class="form-control" id="save-text-chef" rows="5"></textarea>
|
||||
</div>
|
||||
<div role="tabpanel" class="tab-pane" id="clean-json">
|
||||
<textarea class="form-control" id="save-text-clean" rows="5"></textarea>
|
||||
</div>
|
||||
<div role="tabpanel" class="tab-pane" id="compact-json">
|
||||
<textarea class="form-control" id="save-text-compact" rows="5"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="save-name">Recipe name</label>
|
||||
|
@ -260,36 +301,33 @@
|
|||
<select option="theme" id="theme">
|
||||
<option value="classic">Classic</option>
|
||||
<option value="dark">Dark</option>
|
||||
<option value="geocities">GeoCities</option>
|
||||
</select>
|
||||
<label for="theme"> Theme (only supported in modern browsers)</label>
|
||||
</div>
|
||||
<div class="option-item">
|
||||
<input type="checkbox" option="update_url" id="update_url" checked />
|
||||
<label for="update_url"> Update the URL when the input or recipe changes </label>
|
||||
<input type="checkbox" option="updateUrl" id="updateUrl" checked />
|
||||
<label for="updateUrl"> Update the URL when the input or recipe changes </label>
|
||||
</div>
|
||||
<div class="option-item">
|
||||
<input type="checkbox" option="show_highlighter" id="show_highlighter" checked />
|
||||
<label for="show_highlighter"> Highlight selected bytes in output and input (when possible) </label>
|
||||
<input type="checkbox" option="showHighlighter" id="showHighlighter" checked />
|
||||
<label for="showHighlighter"> Highlight selected bytes in output and input (when possible) </label>
|
||||
</div>
|
||||
<div class="option-item">
|
||||
<input type="checkbox" option="treat_as_utf8" id="treat_as_utf8" checked />
|
||||
<label for="treat_as_utf8"> Treat output as UTF-8 if possible </label>
|
||||
<input type="checkbox" option="treatAsUtf8" id="treatAsUtf8" checked />
|
||||
<label for="treatAsUtf8"> Treat output as UTF-8 if possible </label>
|
||||
</div>
|
||||
<div class="option-item">
|
||||
<input type="checkbox" option="word_wrap" id="word_wrap" checked />
|
||||
<label for="word_wrap"> Word wrap the input and output </label>
|
||||
<input type="checkbox" option="wordWrap" id="wordWrap" checked />
|
||||
<label for="wordWrap"> Word wrap the input and output </label>
|
||||
</div>
|
||||
<div class="option-item">
|
||||
<input type="checkbox" option="show_errors" id="show_errors" checked />
|
||||
<label for="show_errors"> Operation error reporting (recommended) </label>
|
||||
<input type="checkbox" option="showErrors" id="showErrors" checked />
|
||||
<label for="showErrors"> Operation error reporting (recommended) </label>
|
||||
</div>
|
||||
<div class="option-item">
|
||||
<input type="number" option="error_timeout" id="error_timeout" />
|
||||
<label for="error_timeout"> Operation error timeout in ms (0 for never) </label>
|
||||
</div>
|
||||
<div class="option-item">
|
||||
<input type="number" option="auto_bake_threshold" id="auto_bake_threshold"/>
|
||||
<label for="auto_bake_threshold"> Auto Bake threshold in ms </label>
|
||||
<input type="number" option="errorTimeout" id="errorTimeout" />
|
||||
<label for="errorTimeout"> Operation error timeout in ms (0 for never) </label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
|
@ -341,7 +379,12 @@
|
|||
Compile time: <%= htmlWebpackPlugin.options.compileTime %>
|
||||
</p>
|
||||
<p>© Crown Copyright 2016.</p>
|
||||
<p>Licenced under the Apache Licence, Version 2.0.</p>
|
||||
<p>Released under the Apache Licence, Version 2.0.</p>
|
||||
<p>
|
||||
<a href="https://gitter.im/gchq/CyberChef">
|
||||
<img src="<%- require('../static/images/gitter-badge.svg') %>">
|
||||
</a>
|
||||
</p>
|
||||
<br>
|
||||
<br>
|
||||
<div>
|
||||
|
@ -368,14 +411,16 @@
|
|||
</a>
|
||||
</blockquote>
|
||||
<div class="collapse" id="faq-examples">
|
||||
<p>There are well over 100 operations in CyberChef allowing you to carry simple and complex tasks easily. Here are some examples:</p>
|
||||
<p>There are around 200 operations in CyberChef allowing you to carry out simple and complex tasks easily. Here are some examples:</p>
|
||||
<ul>
|
||||
<li><a href="?recipe=%5B%7B%22op%22%3A%22From%20Base64%22%2C%22args%22%3A%5B%22A-Za-z0-9%2B%2F%3D%22%2Ctrue%5D%7D%5D&input=VTI4Z2JHOXVaeUJoYm1RZ2RHaGhibXR6SUdadmNpQmhiR3dnZEdobElHWnBjMmd1">Decode a Base64-encoded string</a></li>
|
||||
<li><a href="?recipe=%5B%7B%22op%22%3A%22Translate%20DateTime%20Format%22%2C%22args%22%3A%5B%22Standard%20date%20and%20time%22%2C%22DD%2FMM%2FYYYY%20HH%3Amm%3Ass%22%2C%22UTC%22%2C%22dddd%20Do%20MMMM%20YYYY%20HH%3Amm%3Ass%20Z%20z%22%2C%22Australia%2FQueensland%22%5D%7D%5D&input=MTUvMDYvMjAxNSAyMDo0NTowMA">Convert a date and time to a different time zone</a></li>
|
||||
<li><a href="?recipe=%5B%7B%22op%22%3A%22Parse%20IPv6%20address%22%2C%22args%22%3A%5B%5D%7D%5D&input=MjAwMTowMDAwOjQxMzY6ZTM3ODo4MDAwOjYzYmY6M2ZmZjpmZGQy">Parse a Teredo IPv6 address</a></li>
|
||||
<li><a href="?recipe=%5B%7B%22op%22%3A%22From%20Hexdump%22%2C%22args%22%3A%5B%5D%7D%2C%7B%22op%22%3A%22Gunzip%22%2C%22args%22%3A%5B%5D%7D%5D&input=MDAwMDAwMDAgIDFmIDhiIDA4IDAwIDEyIGJjIGYzIDU3IDAwIGZmIDBkIGM3IGMxIDA5IDAwIDIwICB8Li4uLi6881cu%2Fy7HwS4uIHwKMDAwMDAwMTAgIDA4IDA1IGQwIDU1IGZlIDA0IDJkIGQzIDA0IDFmIGNhIDhjIDQ0IDIxIDViIGZmICB8Li7QVf4uLdMuLsouRCFb%2F3wKMDAwMDAwMjAgIDYwIGM3IGQ3IDAzIDE2IGJlIDQwIDFmIDc4IDRhIDNmIDA5IDg5IDBiIDlhIDdkICB8YMfXLi6%2BQC54Sj8uLi4ufXwKMDAwMDAwMzAgIDRlIGM4IDRlIDZkIDA1IDFlIDAxIDhiIDRjIDI0IDAwIDAwIDAwICAgICAgICAgICB8TshObS4uLi5MJC4uLnw">Convert data from a hexdump, then decompress</a></li>
|
||||
<li><a href="?recipe=%5B%7B%22op%22%3A%22Fork%22%2C%22args%22%3A%5B%22%5C%5Cn%22%2C%22%5C%5Cn%22%5D%7D%2C%7B%22op%22%3A%22From%20UNIX%20Timestamp%22%2C%22args%22%3A%5B%22Seconds%20(s)%22%5D%7D%5D&input=OTc4MzQ2ODAwCjEwMTI2NTEyMDAKMTA0NjY5NjQwMAoxMDgxMDg3MjAwCjExMTUzMDUyMDAKMTE0OTYwOTYwMA">Display multiple timestamps as full dates</a></li>
|
||||
<li><a href="?recipe=%5B%7B%22op%22%3A%22Fork%22%2C%22args%22%3A%5B%22%5C%5Cn%22%2C%22%5C%5Cn%22%5D%7D%2C%7B%22op%22%3A%22Conditional%20Jump%22%2C%22args%22%3A%5B%221%22%2C%222%22%2C%2210%22%5D%7D%2C%7B%22op%22%3A%22To%20Hex%22%2C%22args%22%3A%5B%22Space%22%5D%7D%2C%7B%22op%22%3A%22Return%22%2C%22args%22%3A%5B%5D%7D%2C%7B%22op%22%3A%22To%20Base64%22%2C%22args%22%3A%5B%22A-Za-z0-9%2B%2F%3D%22%5D%7D%5D&input=U29tZSBkYXRhIHdpdGggYSAxIGluIGl0ClNvbWUgZGF0YSB3aXRoIGEgMiBpbiBpdA">Carry out different operations on data of different types</a></li>
|
||||
<li><a href="#recipe=From_Base64('A-Za-z0-9%2B/%3D',true)&input=VTI4Z2JHOXVaeUJoYm1RZ2RHaGhibXR6SUdadmNpQmhiR3dnZEdobElHWnBjMmd1">Decode a Base64-encoded string</a></li>
|
||||
<li><a href="#recipe=Translate_DateTime_Format('Standard%20date%20and%20time','DD/MM/YYYY%20HH:mm:ss','UTC','dddd%20Do%20MMMM%20YYYY%20HH:mm:ss%20Z%20z','Australia/Queensland')&input=MTUvMDYvMjAxNSAyMDo0NTowMA">Convert a date and time to a different time zone</a></li>
|
||||
<li><a href="#recipe=Parse_IPv6_address()&input=MjAwMTowMDAwOjQxMzY6ZTM3ODo4MDAwOjYzYmY6M2ZmZjpmZGQy">Parse a Teredo IPv6 address</a></li>
|
||||
<li><a href="#recipe=From_Hexdump()Gunzip()&input=MDAwMDAwMDAgIDFmIDhiIDA4IDAwIDEyIGJjIGYzIDU3IDAwIGZmIDBkIGM3IGMxIDA5IDAwIDIwICB8Li4uLi6881cu/y7HwS4uIHwKMDAwMDAwMTAgIDA4IDA1IGQwIDU1IGZlIDA0IDJkIGQzIDA0IDFmIGNhIDhjIDQ0IDIxIDViIGZmICB8Li7QVf4uLdMuLsouRCFb/3wKMDAwMDAwMjAgIDYwIGM3IGQ3IDAzIDE2IGJlIDQwIDFmIDc4IDRhIDNmIDA5IDg5IDBiIDlhIDdkICB8YMfXLi6%2BQC54Sj8uLi4ufXwKMDAwMDAwMzAgIDRlIGM4IDRlIDZkIDA1IDFlIDAxIDhiIDRjIDI0IDAwIDAwIDAwICAgICAgICAgICB8TshObS4uLi5MJC4uLnw">Convert data from a hexdump, then decompress</a></li>
|
||||
<li><a href="#recipe=RC4(%7B'option':'UTF8','string':'secret'%7D,'Hex','Hex')Disassemble_x86('64','Full%20x86%20architecture',16,0,true,true)&input=MjFkZGQyNTQwMTYwZWU2NWZlMDc3NzEwM2YyYTM5ZmJlNWJjYjZhYTBhYWJkNDE0ZjkwYzZjYWY1MzEyNzU0YWY3NzRiNzZiM2JiY2QxOTNjYjNkZGZkYmM1YTI2NTMzYTY4NmI1OWI4ZmVkNGQzODBkNDc0NDIwMWFlYzIwNDA1MDcxMzhlMmZlMmIzOTUwNDQ2ZGIzMWQyYmM2MjliZTRkM2YyZWIwMDQzYzI5M2Q3YTVkMjk2MmMwMGZlNmRhMzAwNzJkOGM1YTZiNGZlN2Q4NTlhMDQwZWVhZjI5OTczMzYzMDJmNWEwZWMxOQ">Decrypt and disassemble shellcode</a></li>
|
||||
<li><a href="#recipe=Fork('%5C%5Cn','%5C%5Cn',false)From_UNIX_Timestamp('Seconds%20(s)')&input=OTc4MzQ2ODAwCjEwMTI2NTEyMDAKMTA0NjY5NjQwMAoxMDgxMDg3MjAwCjExMTUzMDUyMDAKMTE0OTYwOTYwMA">Display multiple timestamps as full dates</a></li>
|
||||
<li><a href="#recipe=Fork('%5C%5Cn','%5C%5Cn',false)Conditional_Jump('1',2,10)To_Hex('Space')Return()To_Base64('A-Za-z0-9%2B/%3D')&input=U29tZSBkYXRhIHdpdGggYSAxIGluIGl0ClNvbWUgZGF0YSB3aXRoIGEgMiBpbiBpdA">Carry out different operations on data of different types</a></li>
|
||||
<li><a href="#recipe=Register('key%3D(%5B%5C%5Cda-f%5D*)',true,false)Find_/_Replace(%7B'option':'Regex','string':'.*data%3D(.*)'%7D,'$1',true,false,true)RC4(%7B'option':'Hex','string':'$R0'%7D,'Hex','Latin1')&input=aHR0cDovL21hbHdhcmV6LmJpei9iZWFjb24ucGhwP2tleT0wZTkzMmE1YyZkYXRhPThkYjdkNWViZTM4NjYzYTU0ZWNiYjMzNGUzZGIxMQ">Use parts of the input as arguments to operations</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<blockquote>
|
||||
|
@ -395,7 +440,7 @@
|
|||
<div class="collapse" id="faq-fork">
|
||||
<p>Maybe you have 10 timestamps that you want to parse or 16 encoded strings that all have the same key.</p>
|
||||
<p>The 'Fork' operation (found in the 'Flow control' category) splits up the input line by line and runs all subsequent operations on each line separately. Each output is then displayed on a separate line. These delimiters can be changed, so if your inputs are separated by commas, you can change the split delimiter to a comma instead.</p>
|
||||
<p><a href='?recipe=%5B%7B"op"%3A"Fork"%2C"args"%3A%5B"%5C%5Cn"%2C"%5C%5Cn"%5D%7D%2C%7B"op"%3A"From%20UNIX%20Timestamp"%2C"args"%3A%5B"Seconds%20(s)"%5D%7D%5D&input=OTc4MzQ2ODAwCjEwMTI2NTEyMDAKMTA0NjY5NjQwMAoxMDgxMDg3MjAwCjExMTUzMDUyMDAKMTE0OTYwOTYwMA%3D%3D'>Click here</a> for an example.</p>
|
||||
<p><a href="#recipe=Fork('%5C%5Cn','%5C%5Cn',false)From_UNIX_Timestamp('Seconds%20(s)')&input=OTc4MzQ2ODAwCjEwMTI2NTEyMDAKMTA0NjY5NjQwMAoxMDgxMDg3MjAwCjExMTUzMDUyMDAKMTE0OTYwOTYwMA">Click here</a> for an example.</p>
|
||||
</div>
|
||||
</div>
|
||||
<div role="tabpanel" class="tab-pane" id="report-bug">
|
||||
|
@ -407,21 +452,25 @@
|
|||
<a class="btn btn-primary" href="https://github.com/gchq/CyberChef/issues/new" role="button">Raise issue on GitHub</a>
|
||||
</div>
|
||||
<div role="tabpanel" class="tab-pane" id="about" style="padding: 20px;">
|
||||
<h4>What</h4>
|
||||
<p>A simple, intuitive web app for analysing and decoding data without having to deal with complex tools or programming languages. CyberChef encourages both technical and non-technical people to explore data formats, encryption and compression.</p>
|
||||
<h5><strong>What</strong></h5>
|
||||
<p>A simple, intuitive web app for analysing and decoding data without having to deal with complex tools or programming languages. CyberChef encourages both technical and non-technical people to explore data formats, encryption and compression.</p><br>
|
||||
|
||||
<h4>Why</h4>
|
||||
<p>Digital data comes in all shapes, sizes and formats in the modern world – CyberChef helps to make sense of this data all on one easy-to-use platform.</p>
|
||||
<h5><strong>Why</strong></h5>
|
||||
<p>Digital data comes in all shapes, sizes and formats in the modern world – CyberChef helps to make sense of this data all on one easy-to-use platform.</p><br>
|
||||
|
||||
|
||||
<h4>How</h4>
|
||||
<h5><strong>How</strong></h5>
|
||||
<p>The interface is designed with simplicity at its heart. Complex techniques are now as trivial as drag-and-drop. Simple functions can be combined to build up a "recipe", potentially resulting in complex analysis, which can be shared with other users and used with their input.</p>
|
||||
<p>For those comfortable writing code, CyberChef is a quick and efficient way to prototype solutions to a problem which can then be scripted once proven to work.</p>
|
||||
<p>For those comfortable writing code, CyberChef is a quick and efficient way to prototype solutions to a problem which can then be scripted once proven to work.</p><br>
|
||||
|
||||
|
||||
<h4>Who</h4>
|
||||
<p>It is expected that CyberChef will be useful for cybersecurity and antivirus companies. It should also appeal to the academic world and any individuals or companies involved in the analysis of digital data, be that software developers, analysts, mathematicians or casual puzzle solvers.</p>
|
||||
<h5><strong>Who</strong></h5>
|
||||
<p>It is expected that CyberChef will be useful for cybersecurity and antivirus companies. It should also appeal to the academic world and any individuals or companies involved in the analysis of digital data, be that software developers, analysts, mathematicians or casual puzzle solvers.</p><br>
|
||||
|
||||
|
||||
<h4>Aim</h4>
|
||||
<p>It is hoped that by releasing CyberChef through <a href="https://github.com/gchq/cyberchef">GitHub</a>, contributions can be added which can be rolled out into future versions of the tool.</p>
|
||||
<h5><strong>Aim</strong></h5>
|
||||
<p>It is hoped that by releasing CyberChef through <a href="https://github.com/gchq/CyberChef">GitHub</a>, contributions can be added which can be rolled out into future versions of the tool.</p><br>
|
||||
|
||||
|
||||
<br>
|
||||
<p>There are around 150 useful operations in CyberChef for anyone working on anything vaguely Internet-related, whether you just want to convert a timestamp to a different format, decompress gzipped data, create a SHA3 hash, or parse an X.509 certificate to find out who issued it.</p>
|
||||
|
|
|
@ -17,7 +17,7 @@ import CanvasComponents from "../core/lib/canvascomponents.js";
|
|||
// CyberChef
|
||||
import App from "./App.js";
|
||||
import Categories from "../core/config/Categories.js";
|
||||
import OperationConfig from "../core/config/OperationConfig.js";
|
||||
import OperationConfig from "../core/config/MetaConfig.js";
|
||||
|
||||
|
||||
/**
|
||||
|
@ -38,15 +38,14 @@ function main() {
|
|||
];
|
||||
|
||||
const defaultOptions = {
|
||||
updateUrl : true,
|
||||
showHighlighter : true,
|
||||
treatAsUtf8 : true,
|
||||
wordWrap : true,
|
||||
showErrors : true,
|
||||
errorTimeout : 4000,
|
||||
autoBakeThreshold : 200,
|
||||
attemptHighlight : true,
|
||||
theme : "classic",
|
||||
updateUrl: true,
|
||||
showHighlighter: true,
|
||||
treatAsUtf8: true,
|
||||
wordWrap: true,
|
||||
showErrors: true,
|
||||
errorTimeout: 4000,
|
||||
attemptHighlight: true,
|
||||
theme: "classic",
|
||||
};
|
||||
|
||||
document.removeEventListener("DOMContentLoaded", main, false);
|
||||
|
|
|
@ -2,5 +2,12 @@
|
|||
|
||||
<!-- Begin Google Analytics -->
|
||||
|
||||
ga('create', 'UA-85682716-2', 'auto');
|
||||
|
||||
// Specifying location.pathname here overrides the default URL which could include arguments.
|
||||
// This method prevents Google Analytics from logging any recipe or input data in the URL.
|
||||
ga('send', 'pageview', location.pathname);
|
||||
|
||||
</script>
|
||||
<!-- End Google Analytics -->
|
||||
|
||||
|
|
Before Width: | Height: | Size: 295 B After Width: | Height: | Size: 233 B |
Before Width: | Height: | Size: 773 B After Width: | Height: | Size: 672 B |
Before Width: | Height: | Size: 702 B After Width: | Height: | Size: 654 B |
Before Width: | Height: | Size: 796 B After Width: | Height: | Size: 762 B |
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 1.6 KiB After Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 419 B After Width: | Height: | Size: 245 B |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 1.4 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 3.3 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 746 B After Width: | Height: | Size: 426 B |
Before Width: | Height: | Size: 590 B After Width: | Height: | Size: 467 B |
Before Width: | Height: | Size: 905 B After Width: | Height: | Size: 764 B |
Before Width: | Height: | Size: 680 B After Width: | Height: | Size: 584 B |
Before Width: | Height: | Size: 491 B After Width: | Height: | Size: 351 B |