mirror of
https://github.com/gchq/CyberChef
synced 2025-12-05 23:53:27 +00:00
Compare commits
132 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d54d66cffc | ||
|
|
d2b4c40357 | ||
|
|
f48af97ddc | ||
|
|
f1264d6310 | ||
|
|
4dc5a1499a | ||
|
|
3209c94622 | ||
|
|
6f8a5ea1be | ||
|
|
69837837b0 | ||
|
|
03d8bf2836 | ||
|
|
eca2c142f3 | ||
|
|
715f7bbbc2 | ||
|
|
291ebd5c12 | ||
|
|
ba04cac7ac | ||
|
|
4cabb849f3 | ||
|
|
445a85798b | ||
|
|
55775f48e9 | ||
|
|
4bd923dc06 | ||
|
|
439654ed7f | ||
|
|
69797e58cb | ||
|
|
d1961ca3fa | ||
|
|
2e9b1e079c | ||
|
|
3dfaaf4c25 | ||
|
|
fcc39a0397 | ||
|
|
0602f457ce | ||
|
|
d00b0f4c0e | ||
|
|
5e68959c03 | ||
|
|
ad4451a757 | ||
|
|
4d8127a7d9 | ||
|
|
ee360521bb | ||
|
|
04b0b8c723 | ||
|
|
b3ac8d0835 | ||
|
|
1a88a0164c | ||
|
|
8b77ad7748 | ||
|
|
8d1f668fc5 | ||
|
|
68fbbb64db | ||
|
|
8bba4b2973 | ||
|
|
abdd70c6fa | ||
|
|
9787ab04cd | ||
|
|
79d3c90026 | ||
|
|
c2068b343b | ||
|
|
9e63e40dab | ||
|
|
6424839731 | ||
|
|
863a525625 | ||
|
|
f82a727e24 | ||
|
|
995fcab071 | ||
|
|
c5270d75a1 | ||
|
|
324c409ff1 | ||
|
|
1db8e6dddc | ||
|
|
c49a770c59 | ||
|
|
dd9ba4d250 | ||
|
|
0e601d5b5f | ||
|
|
ebb632e888 | ||
|
|
4db2335107 | ||
|
|
26a2fb6662 | ||
|
|
4c1521a98e | ||
|
|
df8abb099c | ||
|
|
fe1332f18e | ||
|
|
cb9ab7a2c9 | ||
|
|
3a6b2875d5 | ||
|
|
766de7e6fa | ||
|
|
13439e100e | ||
|
|
5ac469b174 | ||
|
|
8ac5b48493 | ||
|
|
1a827ef44f | ||
|
|
0f0e346a02 | ||
|
|
c82971f8db | ||
|
|
cb2c376c63 | ||
|
|
bc00fa0694 | ||
|
|
c86007da71 | ||
|
|
1bf513ca74 | ||
|
|
29411c903f | ||
|
|
017dde364c | ||
|
|
c123d7370a | ||
|
|
76f1e5e8f3 | ||
|
|
4e466c7886 | ||
|
|
d469fb9c58 | ||
|
|
050ab03448 | ||
|
|
40acf751a8 | ||
|
|
126ad585c0 | ||
|
|
1d04b649e0 | ||
|
|
b750006cf0 | ||
|
|
3c16b839b6 | ||
|
|
32aea6b86c | ||
|
|
688c2d0df5 | ||
|
|
0cea56dc62 | ||
|
|
bb44268c30 | ||
|
|
19b3dcf1c2 | ||
|
|
71e0a4e0ce | ||
|
|
7f2e879e24 | ||
|
|
840e44deac | ||
|
|
f7707faece | ||
|
|
b631e3fef6 | ||
|
|
b0fb9db4b8 | ||
|
|
c7e9115994 | ||
|
|
f2d115ee4d | ||
|
|
a1b161493c | ||
|
|
5acee80463 | ||
|
|
e6932401ad | ||
|
|
7a4eff0f5c | ||
|
|
8b533e9893 | ||
|
|
02b92c7977 | ||
|
|
e386863bdb | ||
|
|
16be7cb28a | ||
|
|
f6d97c19d9 | ||
|
|
8fef01d961 | ||
|
|
43dcd544f2 | ||
|
|
b29bb6fdd7 | ||
|
|
d2325306db | ||
|
|
dfe31980b7 | ||
|
|
9734b78aeb | ||
|
|
4ee0800990 | ||
|
|
387008bd9c | ||
|
|
bf24547202 | ||
|
|
454ef0076b | ||
|
|
18693d2471 | ||
|
|
5a9583c970 | ||
|
|
0046f7e3d7 | ||
|
|
c2f6b8df66 | ||
|
|
d0e428b728 | ||
|
|
ae5128a33a | ||
|
|
ed25017e2d | ||
|
|
e5b2b84073 | ||
|
|
1953d9a4c8 | ||
|
|
b3113c109b | ||
|
|
8c3569ea63 | ||
|
|
ae28d476de | ||
|
|
01c4cfdc8d | ||
|
|
8c6c3a1c01 | ||
|
|
ae20a951be | ||
|
|
866dd546c8 | ||
|
|
2070e1a96b | ||
|
|
952f49e2e1 |
@@ -9,6 +9,6 @@ trim_trailing_whitespace = true
|
|||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 4
|
indent_size = 4
|
||||||
|
|
||||||
[{package.json,.travis.yml}]
|
[{package.json,.travis.yml,nightwatch.json}]
|
||||||
indent_style = space
|
indent_style = space
|
||||||
indent_size = 2
|
indent_size = 2
|
||||||
|
|||||||
@@ -87,6 +87,15 @@
|
|||||||
"no-var": "error",
|
"no-var": "error",
|
||||||
"prefer-const": "error"
|
"prefer-const": "error"
|
||||||
},
|
},
|
||||||
|
"overrides": [
|
||||||
|
{
|
||||||
|
"files": "tests/**/*",
|
||||||
|
"rules": {
|
||||||
|
"no-unused-expressions": "off",
|
||||||
|
"no-console": "off"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
"globals": {
|
"globals": {
|
||||||
"$": false,
|
"$": false,
|
||||||
"jQuery": false,
|
"jQuery": false,
|
||||||
|
|||||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -9,4 +9,5 @@ docs/*
|
|||||||
src/core/config/modules/*
|
src/core/config/modules/*
|
||||||
src/core/config/OperationConfig.json
|
src/core/config/OperationConfig.json
|
||||||
src/core/operations/index.mjs
|
src/core/operations/index.mjs
|
||||||
|
tests/browser/output/*
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,19 @@
|
|||||||
language: node_js
|
language: node_js
|
||||||
node_js:
|
node_js:
|
||||||
- node
|
- node
|
||||||
|
addons:
|
||||||
|
chrome: stable
|
||||||
install: npm install
|
install: npm install
|
||||||
before_script:
|
before_script:
|
||||||
- npm install -g grunt
|
- npm install -g grunt
|
||||||
|
- export NODE_OPTIONS=--max_old_space_size=2048
|
||||||
script:
|
script:
|
||||||
- grunt lint
|
- grunt lint
|
||||||
- grunt test
|
- grunt test
|
||||||
- grunt docs
|
- grunt docs
|
||||||
- grunt node
|
- grunt node
|
||||||
- grunt prod --msg="$COMPILE_MSG"
|
- grunt prod --msg="$COMPILE_MSG"
|
||||||
|
- xvfb-run --server-args="-screen 0 1200x800x24" grunt testui
|
||||||
before_deploy:
|
before_deploy:
|
||||||
- grunt exec:sitemap
|
- grunt exec:sitemap
|
||||||
- grunt copy:ghPages
|
- grunt copy:ghPages
|
||||||
|
|||||||
48
CHANGELOG.md
48
CHANGELOG.md
@@ -2,6 +2,33 @@
|
|||||||
All major and minor version changes will be documented in this file. Details of patch-level version changes can be found in [commit messages](https://github.com/gchq/CyberChef/commits/master).
|
All major and minor version changes will be documented in this file. Details of patch-level version changes can be found in [commit messages](https://github.com/gchq/CyberChef/commits/master).
|
||||||
|
|
||||||
|
|
||||||
|
### [8.24.0] - 2019-01-18
|
||||||
|
- 'Convert co-ordinate format' operation added [@j433866] | [#476]
|
||||||
|
|
||||||
|
### [8.23.0] - 2019-01-18
|
||||||
|
- 'YARA Rules' operation added [@artemisbot] | [#468]
|
||||||
|
|
||||||
|
### [8.22.0] - 2019-01-10
|
||||||
|
- 'Subsection' operation added [@j433866] | [#467]
|
||||||
|
|
||||||
|
### [8.21.0] - 2019-01-10
|
||||||
|
- 'To Case Insensitive Regex' and 'From Case Insensitive Regex' operations added [@masq] | [#461]
|
||||||
|
|
||||||
|
### [8.20.0] - 2019-01-09
|
||||||
|
- 'Generate Lorem Ipsum' operation added [@klaxon1] | [#455]
|
||||||
|
|
||||||
|
### [8.19.0] - 2018-12-30
|
||||||
|
- UI test suite added to confirm that the app loads correctly in a reasonable time and that various operations from each module can be run [@n1474335] | [#458]
|
||||||
|
|
||||||
|
### [8.18.0] - 2018-12-26
|
||||||
|
- 'Split Colour Channels' operation added [@artemisbot] | [#449]
|
||||||
|
|
||||||
|
### [8.17.0] - 2018-12-25
|
||||||
|
- 'Generate QR Code' and 'Parse QR Code' operations added [@j433866] | [#448]
|
||||||
|
|
||||||
|
### [8.16.0] - 2018-12-19
|
||||||
|
- 'Play Media' operation added [@anthony-arnold] | [#446]
|
||||||
|
|
||||||
### [8.15.0] - 2018-12-18
|
### [8.15.0] - 2018-12-18
|
||||||
- 'Text Encoding Brute Force' operation added [@Cynser] | [#439]
|
- 'Text Encoding Brute Force' operation added [@Cynser] | [#439]
|
||||||
|
|
||||||
@@ -76,6 +103,15 @@ All major and minor version changes will be documented in this file. Details of
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[8.24.0]: https://github.com/gchq/CyberChef/releases/tag/v8.24.0
|
||||||
|
[8.23.0]: https://github.com/gchq/CyberChef/releases/tag/v8.23.0
|
||||||
|
[8.22.0]: https://github.com/gchq/CyberChef/releases/tag/v8.22.0
|
||||||
|
[8.21.0]: https://github.com/gchq/CyberChef/releases/tag/v8.21.0
|
||||||
|
[8.20.0]: https://github.com/gchq/CyberChef/releases/tag/v8.20.0
|
||||||
|
[8.19.0]: https://github.com/gchq/CyberChef/releases/tag/v8.19.0
|
||||||
|
[8.18.0]: https://github.com/gchq/CyberChef/releases/tag/v8.18.0
|
||||||
|
[8.17.0]: https://github.com/gchq/CyberChef/releases/tag/v8.17.0
|
||||||
|
[8.16.0]: https://github.com/gchq/CyberChef/releases/tag/v8.16.0
|
||||||
[8.15.0]: https://github.com/gchq/CyberChef/releases/tag/v8.15.0
|
[8.15.0]: https://github.com/gchq/CyberChef/releases/tag/v8.15.0
|
||||||
[8.14.0]: https://github.com/gchq/CyberChef/releases/tag/v8.14.0
|
[8.14.0]: https://github.com/gchq/CyberChef/releases/tag/v8.14.0
|
||||||
[8.13.0]: https://github.com/gchq/CyberChef/releases/tag/v8.13.0
|
[8.13.0]: https://github.com/gchq/CyberChef/releases/tag/v8.13.0
|
||||||
@@ -99,6 +135,7 @@ All major and minor version changes will be documented in this file. Details of
|
|||||||
|
|
||||||
[@n1474335]: https://github.com/n1474335
|
[@n1474335]: https://github.com/n1474335
|
||||||
[@d98762625]: https://github.com/d98762625
|
[@d98762625]: https://github.com/d98762625
|
||||||
|
[@j433866]: https://github.com/j433866
|
||||||
[@GCHQ77703]: https://github.com/GCHQ77703
|
[@GCHQ77703]: https://github.com/GCHQ77703
|
||||||
[@artemisbot]: https://github.com/artemisbot
|
[@artemisbot]: https://github.com/artemisbot
|
||||||
[@picapi]: https://github.com/picapi
|
[@picapi]: https://github.com/picapi
|
||||||
@@ -112,6 +149,8 @@ All major and minor version changes will be documented in this file. Details of
|
|||||||
[@jarmovanlenthe]: https://github.com/jarmovanlenthe
|
[@jarmovanlenthe]: https://github.com/jarmovanlenthe
|
||||||
[@tcode2k16]: https://github.com/tcode2k16
|
[@tcode2k16]: https://github.com/tcode2k16
|
||||||
[@Cynser]: https://github.com/Cynser
|
[@Cynser]: https://github.com/Cynser
|
||||||
|
[@anthony-arnold]: https://github.com/anthony-arnold
|
||||||
|
[@masq]: https://github.com/masq
|
||||||
|
|
||||||
[#95]: https://github.com/gchq/CyberChef/pull/299
|
[#95]: https://github.com/gchq/CyberChef/pull/299
|
||||||
[#173]: https://github.com/gchq/CyberChef/pull/173
|
[#173]: https://github.com/gchq/CyberChef/pull/173
|
||||||
@@ -138,3 +177,12 @@ All major and minor version changes will be documented in this file. Details of
|
|||||||
[#439]: https://github.com/gchq/CyberChef/pull/439
|
[#439]: https://github.com/gchq/CyberChef/pull/439
|
||||||
[#441]: https://github.com/gchq/CyberChef/pull/441
|
[#441]: https://github.com/gchq/CyberChef/pull/441
|
||||||
[#443]: https://github.com/gchq/CyberChef/pull/443
|
[#443]: https://github.com/gchq/CyberChef/pull/443
|
||||||
|
[#446]: https://github.com/gchq/CyberChef/pull/446
|
||||||
|
[#448]: https://github.com/gchq/CyberChef/pull/448
|
||||||
|
[#449]: https://github.com/gchq/CyberChef/pull/449
|
||||||
|
[#455]: https://github.com/gchq/CyberChef/pull/455
|
||||||
|
[#458]: https://github.com/gchq/CyberChef/pull/458
|
||||||
|
[#461]: https://github.com/gchq/CyberChef/pull/461
|
||||||
|
[#467]: https://github.com/gchq/CyberChef/pull/467
|
||||||
|
[#468]: https://github.com/gchq/CyberChef/pull/468
|
||||||
|
[#476]: https://github.com/gchq/CyberChef/pull/476
|
||||||
|
|||||||
109
Gruntfile.js
109
Gruntfile.js
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
const webpack = require("webpack");
|
const webpack = require("webpack");
|
||||||
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
||||||
|
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
|
||||||
const NodeExternals = require("webpack-node-externals");
|
const NodeExternals = require("webpack-node-externals");
|
||||||
const Inliner = require("web-resource-inliner");
|
const Inliner = require("web-resource-inliner");
|
||||||
const glob = require("glob");
|
const glob = require("glob");
|
||||||
@@ -29,8 +30,12 @@ module.exports = function (grunt) {
|
|||||||
["clean:node", "clean:config", "exec:generateConfig", "webpack:node", "chmod:build"]);
|
["clean:node", "clean:config", "exec:generateConfig", "webpack:node", "chmod:build"]);
|
||||||
|
|
||||||
grunt.registerTask("test",
|
grunt.registerTask("test",
|
||||||
"A task which runs all the tests in test/tests.",
|
"A task which runs all the operation tests in the tests directory.",
|
||||||
["exec:generateConfig", "exec:tests"]);
|
["exec:generateConfig", "exec:opTests"]);
|
||||||
|
|
||||||
|
grunt.registerTask("testui",
|
||||||
|
"A task which runs all the UI tests in the tests directory. The prod task must already have been run.",
|
||||||
|
["connect:prod", "exec:browserTests"]);
|
||||||
|
|
||||||
grunt.registerTask("docs",
|
grunt.registerTask("docs",
|
||||||
"Compiles documentation in the /docs directory.",
|
"Compiles documentation in the /docs directory.",
|
||||||
@@ -66,6 +71,7 @@ module.exports = function (grunt) {
|
|||||||
grunt.loadNpmTasks("grunt-exec");
|
grunt.loadNpmTasks("grunt-exec");
|
||||||
grunt.loadNpmTasks("grunt-accessibility");
|
grunt.loadNpmTasks("grunt-accessibility");
|
||||||
grunt.loadNpmTasks("grunt-concurrent");
|
grunt.loadNpmTasks("grunt-concurrent");
|
||||||
|
grunt.loadNpmTasks("grunt-contrib-connect");
|
||||||
|
|
||||||
|
|
||||||
// Project configuration
|
// Project configuration
|
||||||
@@ -143,11 +149,11 @@ module.exports = function (grunt) {
|
|||||||
options: {
|
options: {
|
||||||
configFile: "./.eslintrc.json"
|
configFile: "./.eslintrc.json"
|
||||||
},
|
},
|
||||||
configs: ["*.js"],
|
configs: ["*.{js,mjs}"],
|
||||||
core: ["src/core/**/*.{js,mjs}", "!src/core/vendor/**/*", "!src/core/operations/legacy/**/*"],
|
core: ["src/core/**/*.{js,mjs}", "!src/core/vendor/**/*", "!src/core/operations/legacy/**/*"],
|
||||||
web: ["src/web/**/*.{js,mjs}"],
|
web: ["src/web/**/*.{js,mjs}"],
|
||||||
node: ["src/node/**/*.{js,mjs}"],
|
node: ["src/node/**/*.{js,mjs}"],
|
||||||
tests: ["test/**/*.{js,mjs}"],
|
tests: ["tests/**/*.{js,mjs}"],
|
||||||
},
|
},
|
||||||
jsdoc: {
|
jsdoc: {
|
||||||
options: {
|
options: {
|
||||||
@@ -179,37 +185,44 @@ module.exports = function (grunt) {
|
|||||||
},
|
},
|
||||||
webpack: {
|
webpack: {
|
||||||
options: webpackConfig,
|
options: webpackConfig,
|
||||||
web: {
|
web: () => {
|
||||||
mode: "production",
|
return {
|
||||||
target: "web",
|
mode: "production",
|
||||||
entry: Object.assign({
|
target: "web",
|
||||||
main: "./src/web/index.js",
|
entry: Object.assign({
|
||||||
sitemap: "./src/web/static/sitemap.js"
|
main: "./src/web/index.js",
|
||||||
}, moduleEntryPoints),
|
sitemap: "./src/web/static/sitemap.js"
|
||||||
output: {
|
}, moduleEntryPoints),
|
||||||
path: __dirname + "/build/prod"
|
output: {
|
||||||
},
|
path: __dirname + "/build/prod"
|
||||||
resolve: {
|
},
|
||||||
alias: {
|
resolve: {
|
||||||
"./config/modules/OpModules": "./config/modules/Default"
|
alias: {
|
||||||
}
|
"./config/modules/OpModules": "./config/modules/Default"
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new webpack.DefinePlugin(BUILD_CONSTANTS),
|
|
||||||
new HtmlWebpackPlugin({
|
|
||||||
filename: "index.html",
|
|
||||||
template: "./src/web/html/index.html",
|
|
||||||
chunks: ["main"],
|
|
||||||
compileTime: compileTime,
|
|
||||||
version: pkg.version,
|
|
||||||
minify: {
|
|
||||||
removeComments: true,
|
|
||||||
collapseWhitespace: true,
|
|
||||||
minifyJS: true,
|
|
||||||
minifyCSS: true
|
|
||||||
}
|
}
|
||||||
}),
|
},
|
||||||
]
|
plugins: [
|
||||||
|
new webpack.DefinePlugin(BUILD_CONSTANTS),
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
filename: "index.html",
|
||||||
|
template: "./src/web/html/index.html",
|
||||||
|
chunks: ["main"],
|
||||||
|
compileTime: compileTime,
|
||||||
|
version: pkg.version,
|
||||||
|
minify: {
|
||||||
|
removeComments: true,
|
||||||
|
collapseWhitespace: true,
|
||||||
|
minifyJS: true,
|
||||||
|
minifyCSS: true
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
new BundleAnalyzerPlugin({
|
||||||
|
analyzerMode: "static",
|
||||||
|
reportFilename: "BundleAnalyzerReport.html",
|
||||||
|
openAnalyzer: false
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
};
|
||||||
},
|
},
|
||||||
webInline: {
|
webInline: {
|
||||||
mode: "production",
|
mode: "production",
|
||||||
@@ -238,19 +251,6 @@ module.exports = function (grunt) {
|
|||||||
}),
|
}),
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
tests: {
|
|
||||||
mode: "development",
|
|
||||||
target: "node",
|
|
||||||
entry: "./test/index.mjs",
|
|
||||||
externals: [NodeExternals()],
|
|
||||||
output: {
|
|
||||||
filename: "index.js",
|
|
||||||
path: __dirname + "/build/test"
|
|
||||||
},
|
|
||||||
plugins: [
|
|
||||||
new webpack.DefinePlugin(BUILD_CONSTANTS)
|
|
||||||
]
|
|
||||||
},
|
|
||||||
node: {
|
node: {
|
||||||
mode: "production",
|
mode: "production",
|
||||||
target: "node",
|
target: "node",
|
||||||
@@ -312,6 +312,14 @@ module.exports = function (grunt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
connect: {
|
||||||
|
prod: {
|
||||||
|
options: {
|
||||||
|
port: 8000,
|
||||||
|
base: "build/prod/"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
copy: {
|
copy: {
|
||||||
ghPages: {
|
ghPages: {
|
||||||
options: {
|
options: {
|
||||||
@@ -391,8 +399,11 @@ module.exports = function (grunt) {
|
|||||||
"echo '--- Config scripts finished. ---\n'"
|
"echo '--- Config scripts finished. ---\n'"
|
||||||
].join(";")
|
].join(";")
|
||||||
},
|
},
|
||||||
tests: {
|
opTests: {
|
||||||
command: "node --experimental-modules --no-warnings --no-deprecation test/index.mjs"
|
command: "node --experimental-modules --no-warnings --no-deprecation tests/operations/index.mjs"
|
||||||
|
},
|
||||||
|
browserTests: {
|
||||||
|
command: "./node_modules/.bin/nightwatch --env prod,inline"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
34
nightwatch.json
Normal file
34
nightwatch.json
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"src_folders": ["tests/browser"],
|
||||||
|
"output_folder": "tests/browser/output",
|
||||||
|
|
||||||
|
"test_settings": {
|
||||||
|
|
||||||
|
"default": {
|
||||||
|
"launch_url": "http://localhost:8080",
|
||||||
|
"webdriver": {
|
||||||
|
"start_process": true,
|
||||||
|
"server_path": "./node_modules/.bin/chromedriver",
|
||||||
|
"port": 9515,
|
||||||
|
"log_path": false
|
||||||
|
},
|
||||||
|
"desiredCapabilities": {
|
||||||
|
"browserName": "chrome"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"dev": {
|
||||||
|
"launch_url": "http://localhost:8080"
|
||||||
|
},
|
||||||
|
|
||||||
|
"prod": {
|
||||||
|
"launch_url": "http://localhost:8000/index.html"
|
||||||
|
},
|
||||||
|
|
||||||
|
"inline": {
|
||||||
|
"launch_url": "http://localhost:8000/cyberchef.htm"
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
2992
package-lock.json
generated
2992
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
59
package.json
59
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "cyberchef",
|
"name": "cyberchef",
|
||||||
"version": "8.15.1",
|
"version": "8.23.2",
|
||||||
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
|
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
|
||||||
"author": "n1474335 <n1474335@gmail.com>",
|
"author": "n1474335 <n1474335@gmail.com>",
|
||||||
"homepage": "https://gchq.github.io/CyberChef",
|
"homepage": "https://gchq.github.io/CyberChef",
|
||||||
@@ -30,22 +30,24 @@
|
|||||||
"main": "build/node/CyberChef.js",
|
"main": "build/node/CyberChef.js",
|
||||||
"bugs": "https://github.com/gchq/CyberChef/issues",
|
"bugs": "https://github.com/gchq/CyberChef/issues",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.1.5",
|
"@babel/core": "^7.2.2",
|
||||||
"@babel/preset-env": "^7.1.5",
|
"@babel/preset-env": "^7.2.3",
|
||||||
"autoprefixer": "^9.3.1",
|
"autoprefixer": "^9.4.3",
|
||||||
"babel-loader": "^8.0.4",
|
"babel-loader": "^8.0.4",
|
||||||
"bootstrap": "^4.1.3",
|
"bootstrap": "^4.2.1",
|
||||||
"colors": "^1.3.2",
|
"chromedriver": "^2.45.0",
|
||||||
"css-loader": "^1.0.1",
|
"colors": "^1.3.3",
|
||||||
"eslint": "^5.8.0",
|
"css-loader": "^2.1.0",
|
||||||
|
"eslint": "^5.11.1",
|
||||||
"exports-loader": "^0.7.0",
|
"exports-loader": "^0.7.0",
|
||||||
"extract-text-webpack-plugin": "^4.0.0-alpha0",
|
"extract-text-webpack-plugin": "^4.0.0-alpha0",
|
||||||
"file-loader": "^2.0.0",
|
"file-loader": "^3.0.1",
|
||||||
"grunt": "^1.0.3",
|
"grunt": "^1.0.3",
|
||||||
"grunt-accessibility": "~6.0.0",
|
"grunt-accessibility": "~6.0.0",
|
||||||
"grunt-chmod": "~1.1.1",
|
"grunt-chmod": "~1.1.1",
|
||||||
"grunt-concurrent": "^2.3.1",
|
"grunt-concurrent": "^2.3.1",
|
||||||
"grunt-contrib-clean": "~2.0.0",
|
"grunt-contrib-clean": "~2.0.0",
|
||||||
|
"grunt-contrib-connect": "^2.0.0",
|
||||||
"grunt-contrib-copy": "~1.0.0",
|
"grunt-contrib-copy": "~1.0.0",
|
||||||
"grunt-contrib-watch": "^1.1.0",
|
"grunt-contrib-watch": "^1.1.0",
|
||||||
"grunt-eslint": "^21.0.0",
|
"grunt-eslint": "^21.0.0",
|
||||||
@@ -56,7 +58,8 @@
|
|||||||
"imports-loader": "^0.8.0",
|
"imports-loader": "^0.8.0",
|
||||||
"ink-docstrap": "^1.3.2",
|
"ink-docstrap": "^1.3.2",
|
||||||
"jsdoc-babel": "^0.5.0",
|
"jsdoc-babel": "^0.5.0",
|
||||||
"node-sass": "^4.10.0",
|
"nightwatch": "^1.0.18",
|
||||||
|
"node-sass": "^4.11.0",
|
||||||
"postcss-css-variables": "^0.11.0",
|
"postcss-css-variables": "^0.11.0",
|
||||||
"postcss-import": "^12.0.1",
|
"postcss-import": "^12.0.1",
|
||||||
"postcss-loader": "^3.0.0",
|
"postcss-loader": "^3.0.0",
|
||||||
@@ -66,8 +69,9 @@
|
|||||||
"style-loader": "^0.23.1",
|
"style-loader": "^0.23.1",
|
||||||
"url-loader": "^1.1.2",
|
"url-loader": "^1.1.2",
|
||||||
"web-resource-inliner": "^4.2.1",
|
"web-resource-inliner": "^4.2.1",
|
||||||
"webpack": "^4.25.1",
|
"webpack": "^4.28.3",
|
||||||
"webpack-dev-server": "^3.1.10",
|
"webpack-bundle-analyzer": "^3.0.3",
|
||||||
|
"webpack-dev-server": "^3.1.14",
|
||||||
"webpack-node-externals": "^1.7.2",
|
"webpack-node-externals": "^1.7.2",
|
||||||
"worker-loader": "^2.0.0"
|
"worker-loader": "^2.0.0"
|
||||||
},
|
},
|
||||||
@@ -76,10 +80,10 @@
|
|||||||
"babel-plugin-transform-builtin-extend": "1.1.2",
|
"babel-plugin-transform-builtin-extend": "1.1.2",
|
||||||
"babel-polyfill": "^6.26.0",
|
"babel-polyfill": "^6.26.0",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"bignumber.js": "^8.0.1",
|
"bignumber.js": "^8.0.2",
|
||||||
"bootstrap-colorpicker": "^2.5.3",
|
"bootstrap-colorpicker": "^2.5.3",
|
||||||
"bootstrap-material-design": "^4.1.1",
|
"bootstrap-material-design": "^4.1.1",
|
||||||
"bson": "^3.0.2",
|
"bson": "^4.0.1",
|
||||||
"chi-squared": "^1.1.0",
|
"chi-squared": "^1.1.0",
|
||||||
"crypto-api": "^0.8.3",
|
"crypto-api": "^0.8.3",
|
||||||
"crypto-js": "^3.1.9-1",
|
"crypto-js": "^3.1.9-1",
|
||||||
@@ -90,46 +94,51 @@
|
|||||||
"esmangle": "^1.0.1",
|
"esmangle": "^1.0.1",
|
||||||
"esprima": "^4.0.1",
|
"esprima": "^4.0.1",
|
||||||
"exif-parser": "^0.1.12",
|
"exif-parser": "^0.1.12",
|
||||||
"file-saver": "^2.0.0-rc.4",
|
"file-saver": "^2.0.0",
|
||||||
|
"geodesy": "^1.1.3",
|
||||||
"highlight.js": "^9.13.1",
|
"highlight.js": "^9.13.1",
|
||||||
|
"jimp": "^0.6.0",
|
||||||
"jquery": "^3.3.1",
|
"jquery": "^3.3.1",
|
||||||
"js-crc": "^0.2.0",
|
"js-crc": "^0.2.0",
|
||||||
"js-sha3": "^0.8.0",
|
"js-sha3": "^0.8.0",
|
||||||
"jsbn": "^1.1.0",
|
"jsesc": "^2.5.2",
|
||||||
"jsesc": "^2.5.1",
|
|
||||||
"jsonpath": "^1.0.0",
|
"jsonpath": "^1.0.0",
|
||||||
"jsonwebtoken": "^8.3.0",
|
"jsonwebtoken": "^8.4.0",
|
||||||
|
"jsqr": "^1.1.1",
|
||||||
"jsrsasign": "8.0.12",
|
"jsrsasign": "8.0.12",
|
||||||
"kbpgp": "^2.0.82",
|
"kbpgp": "^2.0.82",
|
||||||
|
"libyara-wasm": "0.0.11",
|
||||||
"lodash": "^4.17.11",
|
"lodash": "^4.17.11",
|
||||||
"loglevel": "^1.6.1",
|
"loglevel": "^1.6.1",
|
||||||
"loglevel-message-prefix": "^3.0.0",
|
"loglevel-message-prefix": "^3.0.0",
|
||||||
"moment": "^2.22.2",
|
"moment": "^2.23.0",
|
||||||
"moment-timezone": "^0.5.23",
|
"moment-timezone": "^0.5.23",
|
||||||
"ngeohash": "^0.6.0",
|
"ngeohash": "^0.6.3",
|
||||||
"node-forge": "^0.7.6",
|
"node-forge": "^0.7.6",
|
||||||
"node-md6": "^0.1.0",
|
"node-md6": "^0.1.0",
|
||||||
"notepack.io": "^2.1.3",
|
"notepack.io": "^2.2.0",
|
||||||
"nwmatcher": "^1.4.4",
|
"nwmatcher": "^1.4.4",
|
||||||
"otp": "^0.1.3",
|
"otp": "^0.1.3",
|
||||||
"popper.js": "^1.14.4",
|
"popper.js": "^1.14.6",
|
||||||
|
"qr-image": "^3.2.0",
|
||||||
"scryptsy": "^2.0.0",
|
"scryptsy": "^2.0.0",
|
||||||
"snackbarjs": "^1.1.0",
|
"snackbarjs": "^1.1.0",
|
||||||
"sortablejs": "^1.7.0",
|
"sortablejs": "^1.8.0-rc1",
|
||||||
"split.js": "^1.5.9",
|
"split.js": "^1.5.10",
|
||||||
"ssdeep.js": "0.0.2",
|
"ssdeep.js": "0.0.2",
|
||||||
"ua-parser-js": "^0.7.19",
|
"ua-parser-js": "^0.7.19",
|
||||||
"utf8": "^3.0.0",
|
"utf8": "^3.0.0",
|
||||||
"vkbeautify": "^0.99.3",
|
"vkbeautify": "^0.99.3",
|
||||||
"xmldom": "^0.1.27",
|
"xmldom": "^0.1.27",
|
||||||
"xpath": "0.0.27",
|
"xpath": "0.0.27",
|
||||||
"xregexp": "^4.2.0",
|
"xregexp": "^4.2.4",
|
||||||
"zlibjs": "^0.3.1"
|
"zlibjs": "^0.3.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "grunt dev",
|
"start": "grunt dev",
|
||||||
"build": "grunt prod",
|
"build": "grunt prod",
|
||||||
"test": "grunt test",
|
"test": "grunt test",
|
||||||
|
"testui": "grunt testui",
|
||||||
"docs": "grunt docs",
|
"docs": "grunt docs",
|
||||||
"lint": "grunt lint",
|
"lint": "grunt lint",
|
||||||
"newop": "node --experimental-modules src/core/config/scripts/newOperation.mjs"
|
"newop": "node --experimental-modules src/core/config/scripts/newOperation.mjs"
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import Utils from "./Utils";
|
import Utils from "./Utils";
|
||||||
|
import DishError from "./errors/DishError";
|
||||||
import BigNumber from "bignumber.js";
|
import BigNumber from "bignumber.js";
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
|
|
||||||
@@ -61,7 +62,7 @@ class Dish {
|
|||||||
case "list<file>":
|
case "list<file>":
|
||||||
return Dish.LIST_FILE;
|
return Dish.LIST_FILE;
|
||||||
default:
|
default:
|
||||||
throw "Invalid data type string. No matching enum.";
|
throw new DishError("Invalid data type string. No matching enum.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -93,7 +94,7 @@ class Dish {
|
|||||||
case Dish.LIST_FILE:
|
case Dish.LIST_FILE:
|
||||||
return "List<File>";
|
return "List<File>";
|
||||||
default:
|
default:
|
||||||
throw "Invalid data type enum. No matching type.";
|
throw new DishError("Invalid data type enum. No matching type.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +118,7 @@ class Dish {
|
|||||||
|
|
||||||
if (!this.valid()) {
|
if (!this.valid()) {
|
||||||
const sample = Utils.truncate(JSON.stringify(this.value), 13);
|
const sample = Utils.truncate(JSON.stringify(this.value), 13);
|
||||||
throw "Data is not a valid " + Dish.enumLookup(type) + ": " + sample;
|
throw new DishError(`Data is not a valid ${Dish.enumLookup(type)}: ${sample}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -151,77 +152,85 @@ class Dish {
|
|||||||
const byteArrayToStr = notUTF8 ? Utils.byteArrayToChars : Utils.byteArrayToUtf8;
|
const byteArrayToStr = notUTF8 ? Utils.byteArrayToChars : Utils.byteArrayToUtf8;
|
||||||
|
|
||||||
// Convert data to intermediate byteArray type
|
// Convert data to intermediate byteArray type
|
||||||
switch (this.type) {
|
try {
|
||||||
case Dish.STRING:
|
switch (this.type) {
|
||||||
this.value = this.value ? Utils.strToByteArray(this.value) : [];
|
case Dish.STRING:
|
||||||
break;
|
this.value = this.value ? Utils.strToByteArray(this.value) : [];
|
||||||
case Dish.NUMBER:
|
break;
|
||||||
this.value = typeof this.value === "number" ? Utils.strToByteArray(this.value.toString()) : [];
|
case Dish.NUMBER:
|
||||||
break;
|
this.value = typeof this.value === "number" ? Utils.strToByteArray(this.value.toString()) : [];
|
||||||
case Dish.HTML:
|
break;
|
||||||
this.value = this.value ? Utils.strToByteArray(Utils.unescapeHtml(Utils.stripHtmlTags(this.value, true))) : [];
|
case Dish.HTML:
|
||||||
break;
|
this.value = this.value ? Utils.strToByteArray(Utils.unescapeHtml(Utils.stripHtmlTags(this.value, true))) : [];
|
||||||
case Dish.ARRAY_BUFFER:
|
break;
|
||||||
// Array.from() would be nicer here, but it's slightly slower
|
case Dish.ARRAY_BUFFER:
|
||||||
this.value = Array.prototype.slice.call(new Uint8Array(this.value));
|
// Array.from() would be nicer here, but it's slightly slower
|
||||||
break;
|
this.value = Array.prototype.slice.call(new Uint8Array(this.value));
|
||||||
case Dish.BIG_NUMBER:
|
break;
|
||||||
this.value = this.value instanceof BigNumber ? Utils.strToByteArray(this.value.toFixed()) : [];
|
case Dish.BIG_NUMBER:
|
||||||
break;
|
this.value = BigNumber.isBigNumber(this.value) ? Utils.strToByteArray(this.value.toFixed()) : [];
|
||||||
case Dish.JSON:
|
break;
|
||||||
this.value = this.value ? Utils.strToByteArray(JSON.stringify(this.value, null, 4)) : [];
|
case Dish.JSON:
|
||||||
break;
|
this.value = this.value ? Utils.strToByteArray(JSON.stringify(this.value, null, 4)) : [];
|
||||||
case Dish.FILE:
|
break;
|
||||||
this.value = await Utils.readFile(this.value);
|
case Dish.FILE:
|
||||||
this.value = Array.prototype.slice.call(this.value);
|
this.value = await Utils.readFile(this.value);
|
||||||
break;
|
this.value = Array.prototype.slice.call(this.value);
|
||||||
case Dish.LIST_FILE:
|
break;
|
||||||
this.value = await Promise.all(this.value.map(async f => Utils.readFile(f)));
|
case Dish.LIST_FILE:
|
||||||
this.value = this.value.map(b => Array.prototype.slice.call(b));
|
this.value = await Promise.all(this.value.map(async f => Utils.readFile(f)));
|
||||||
this.value = [].concat.apply([], this.value);
|
this.value = this.value.map(b => Array.prototype.slice.call(b));
|
||||||
break;
|
this.value = [].concat.apply([], this.value);
|
||||||
default:
|
break;
|
||||||
break;
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
throw new DishError(`Error translating from ${Dish.enumLookup(this.type)} to byteArray: ${err}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.type = Dish.BYTE_ARRAY;
|
this.type = Dish.BYTE_ARRAY;
|
||||||
|
|
||||||
// Convert from byteArray to toType
|
// Convert from byteArray to toType
|
||||||
switch (toType) {
|
try {
|
||||||
case Dish.STRING:
|
switch (toType) {
|
||||||
case Dish.HTML:
|
case Dish.STRING:
|
||||||
this.value = this.value ? byteArrayToStr(this.value) : "";
|
case Dish.HTML:
|
||||||
this.type = Dish.STRING;
|
this.value = this.value ? byteArrayToStr(this.value) : "";
|
||||||
break;
|
this.type = Dish.STRING;
|
||||||
case Dish.NUMBER:
|
break;
|
||||||
this.value = this.value ? parseFloat(byteArrayToStr(this.value)) : 0;
|
case Dish.NUMBER:
|
||||||
this.type = Dish.NUMBER;
|
this.value = this.value ? parseFloat(byteArrayToStr(this.value)) : 0;
|
||||||
break;
|
this.type = Dish.NUMBER;
|
||||||
case Dish.ARRAY_BUFFER:
|
break;
|
||||||
this.value = new Uint8Array(this.value).buffer;
|
case Dish.ARRAY_BUFFER:
|
||||||
this.type = Dish.ARRAY_BUFFER;
|
this.value = new Uint8Array(this.value).buffer;
|
||||||
break;
|
this.type = Dish.ARRAY_BUFFER;
|
||||||
case Dish.BIG_NUMBER:
|
break;
|
||||||
try {
|
case Dish.BIG_NUMBER:
|
||||||
this.value = new BigNumber(byteArrayToStr(this.value));
|
try {
|
||||||
} catch (err) {
|
this.value = new BigNumber(byteArrayToStr(this.value));
|
||||||
this.value = new BigNumber(NaN);
|
} catch (err) {
|
||||||
}
|
this.value = new BigNumber(NaN);
|
||||||
this.type = Dish.BIG_NUMBER;
|
}
|
||||||
break;
|
this.type = Dish.BIG_NUMBER;
|
||||||
case Dish.JSON:
|
break;
|
||||||
this.value = JSON.parse(byteArrayToStr(this.value));
|
case Dish.JSON:
|
||||||
this.type = Dish.JSON;
|
this.value = JSON.parse(byteArrayToStr(this.value));
|
||||||
break;
|
this.type = Dish.JSON;
|
||||||
case Dish.FILE:
|
break;
|
||||||
this.value = new File(this.value, "unknown");
|
case Dish.FILE:
|
||||||
break;
|
this.value = new File(this.value, "unknown");
|
||||||
case Dish.LIST_FILE:
|
break;
|
||||||
this.value = [new File(this.value, "unknown")];
|
case Dish.LIST_FILE:
|
||||||
this.type = Dish.LIST_FILE;
|
this.value = [new File(this.value, "unknown")];
|
||||||
break;
|
this.type = Dish.LIST_FILE;
|
||||||
default:
|
break;
|
||||||
break;
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
throw new DishError(`Error translating from byteArray to ${Dish.enumLookup(toType)}: ${err}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,7 +265,7 @@ class Dish {
|
|||||||
case Dish.ARRAY_BUFFER:
|
case Dish.ARRAY_BUFFER:
|
||||||
return this.value instanceof ArrayBuffer;
|
return this.value instanceof ArrayBuffer;
|
||||||
case Dish.BIG_NUMBER:
|
case Dish.BIG_NUMBER:
|
||||||
return this.value instanceof BigNumber;
|
return BigNumber.isBigNumber(this.value);
|
||||||
case Dish.JSON:
|
case Dish.JSON:
|
||||||
// All values can be serialised in some manner, so we return true in all cases
|
// All values can be serialised in some manner, so we return true in all cases
|
||||||
return true;
|
return true;
|
||||||
@@ -357,7 +366,7 @@ class Dish {
|
|||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new Error("Cannot clone Dish, unknown type");
|
throw new DishError("Cannot clone Dish, unknown type");
|
||||||
}
|
}
|
||||||
|
|
||||||
return newDish;
|
return newDish;
|
||||||
|
|||||||
@@ -23,8 +23,10 @@ class Ingredient {
|
|||||||
this._value = null;
|
this._value = null;
|
||||||
this.disabled = false;
|
this.disabled = false;
|
||||||
this.hint = "";
|
this.hint = "";
|
||||||
|
this.rows = 0;
|
||||||
this.toggleValues = [];
|
this.toggleValues = [];
|
||||||
this.target = null;
|
this.target = null;
|
||||||
|
this.defaultIndex = 0;
|
||||||
|
|
||||||
if (ingredientConfig) {
|
if (ingredientConfig) {
|
||||||
this._parseConfig(ingredientConfig);
|
this._parseConfig(ingredientConfig);
|
||||||
@@ -44,8 +46,10 @@ class Ingredient {
|
|||||||
this.defaultValue = ingredientConfig.value;
|
this.defaultValue = ingredientConfig.value;
|
||||||
this.disabled = !!ingredientConfig.disabled;
|
this.disabled = !!ingredientConfig.disabled;
|
||||||
this.hint = ingredientConfig.hint || false;
|
this.hint = ingredientConfig.hint || false;
|
||||||
|
this.rows = ingredientConfig.rows || false;
|
||||||
this.toggleValues = ingredientConfig.toggleValues;
|
this.toggleValues = ingredientConfig.toggleValues;
|
||||||
this.target = typeof ingredientConfig.target !== "undefined" ? ingredientConfig.target : null;
|
this.target = typeof ingredientConfig.target !== "undefined" ? ingredientConfig.target : null;
|
||||||
|
this.defaultIndex = typeof ingredientConfig.defaultIndex !== "undefined" ? ingredientConfig.defaultIndex : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -93,6 +97,7 @@ class Ingredient {
|
|||||||
case "binaryString":
|
case "binaryString":
|
||||||
case "binaryShortString":
|
case "binaryShortString":
|
||||||
case "editableOption":
|
case "editableOption":
|
||||||
|
case "editableOptionShort":
|
||||||
return Utils.parseEscapedChars(data);
|
return Utils.parseEscapedChars(data);
|
||||||
case "byteArray":
|
case "byteArray":
|
||||||
if (typeof data == "string") {
|
if (typeof data == "string") {
|
||||||
|
|||||||
@@ -179,8 +179,10 @@ class Operation {
|
|||||||
|
|
||||||
if (ing.toggleValues) conf.toggleValues = ing.toggleValues;
|
if (ing.toggleValues) conf.toggleValues = ing.toggleValues;
|
||||||
if (ing.hint) conf.hint = ing.hint;
|
if (ing.hint) conf.hint = ing.hint;
|
||||||
|
if (ing.rows) conf.rows = ing.rows;
|
||||||
if (ing.disabled) conf.disabled = ing.disabled;
|
if (ing.disabled) conf.disabled = ing.disabled;
|
||||||
if (ing.target) conf.target = ing.target;
|
if (ing.target) conf.target = ing.target;
|
||||||
|
if (ing.defaultIndex) conf.defaultIndex = ing.defaultIndex;
|
||||||
return conf;
|
return conf;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,10 +4,10 @@
|
|||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// import Operation from "./Operation.js";
|
|
||||||
import OpModules from "./config/modules/OpModules";
|
import OpModules from "./config/modules/OpModules";
|
||||||
import OperationConfig from "./config/OperationConfig.json";
|
import OperationConfig from "./config/OperationConfig.json";
|
||||||
import OperationError from "./errors/OperationError";
|
import OperationError from "./errors/OperationError";
|
||||||
|
import DishError from "./errors/DishError";
|
||||||
import log from "loglevel";
|
import log from "loglevel";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -183,6 +183,10 @@ class Recipe {
|
|||||||
// native types is not fully supported yet.
|
// native types is not fully supported yet.
|
||||||
dish.set(err.message, "string");
|
dish.set(err.message, "string");
|
||||||
return i;
|
return i;
|
||||||
|
} else if (err instanceof DishError ||
|
||||||
|
(err.type && err.type === "DishError")) {
|
||||||
|
dish.set(err.message, "string");
|
||||||
|
return i;
|
||||||
} else {
|
} else {
|
||||||
const e = typeof err == "string" ? { message: err } : err;
|
const e = typeof err == "string" ? { message: err } : err;
|
||||||
|
|
||||||
|
|||||||
@@ -5,8 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import utf8 from "utf8";
|
import utf8 from "utf8";
|
||||||
import moment from "moment-timezone";
|
import {fromBase64, toBase64} from "./lib/Base64";
|
||||||
import {fromBase64} from "./lib/Base64";
|
|
||||||
import {fromHex} from "./lib/Hex";
|
import {fromHex} from "./lib/Hex";
|
||||||
import {fromDecimal} from "./lib/Decimal";
|
import {fromDecimal} from "./lib/Decimal";
|
||||||
import {fromBinary} from "./lib/Binary";
|
import {fromBinary} from "./lib/Binary";
|
||||||
@@ -797,38 +796,6 @@ class Utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Expresses a number of milliseconds in a human readable format.
|
|
||||||
*
|
|
||||||
* Range | Sample Output
|
|
||||||
* -----------------------------|-------------------------------
|
|
||||||
* 0 to 45 seconds | a few seconds ago
|
|
||||||
* 45 to 90 seconds | a minute ago
|
|
||||||
* 90 seconds to 45 minutes | 2 minutes ago ... 45 minutes ago
|
|
||||||
* 45 to 90 minutes | an hour ago
|
|
||||||
* 90 minutes to 22 hours | 2 hours ago ... 22 hours ago
|
|
||||||
* 22 to 36 hours | a day ago
|
|
||||||
* 36 hours to 25 days | 2 days ago ... 25 days ago
|
|
||||||
* 25 to 45 days | a month ago
|
|
||||||
* 45 to 345 days | 2 months ago ... 11 months ago
|
|
||||||
* 345 to 545 days (1.5 years) | a year ago
|
|
||||||
* 546 days+ | 2 years ago ... 20 years ago
|
|
||||||
*
|
|
||||||
* @param {number} ms
|
|
||||||
* @returns {string}
|
|
||||||
*
|
|
||||||
* @example
|
|
||||||
* // returns "3 minutes"
|
|
||||||
* Utils.fuzzyTime(152435);
|
|
||||||
*
|
|
||||||
* // returns "5 days"
|
|
||||||
* Utils.fuzzyTime(456851321);
|
|
||||||
*/
|
|
||||||
static fuzzyTime(ms) {
|
|
||||||
return moment.duration(ms, "milliseconds").humanize();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats a list of files or directories.
|
* Formats a list of files or directories.
|
||||||
*
|
*
|
||||||
@@ -850,6 +817,17 @@ class Utils {
|
|||||||
return html;
|
return html;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const formatContent = function (buff, type) {
|
||||||
|
if (type.startsWith("image")) {
|
||||||
|
let dataURI = "data:";
|
||||||
|
dataURI += type + ";";
|
||||||
|
dataURI += "base64," + toBase64(buff);
|
||||||
|
return "<img style='max-width: 100%;' src='" + dataURI + "'>";
|
||||||
|
} else {
|
||||||
|
return `<pre>${Utils.escapeHtml(Utils.arrayBufferToStr(buff.buffer))}</pre>`;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const formatFile = async function(file, i) {
|
const formatFile = async function(file, i) {
|
||||||
const buff = await Utils.readFile(file);
|
const buff = await Utils.readFile(file);
|
||||||
const blob = new Blob(
|
const blob = new Blob(
|
||||||
@@ -879,7 +857,7 @@ class Utils {
|
|||||||
</div>
|
</div>
|
||||||
<div id='collapse${i}' class='collapse' aria-labelledby='heading${i}' data-parent="#files">
|
<div id='collapse${i}' class='collapse' aria-labelledby='heading${i}' data-parent="#files">
|
||||||
<div class='card-body'>
|
<div class='card-body'>
|
||||||
<pre>${Utils.escapeHtml(Utils.arrayBufferToStr(buff.buffer))}</pre>
|
${formatContent(buff, file.type)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|||||||
@@ -189,6 +189,8 @@
|
|||||||
"Remove null bytes",
|
"Remove null bytes",
|
||||||
"To Upper case",
|
"To Upper case",
|
||||||
"To Lower case",
|
"To Lower case",
|
||||||
|
"To Case Insensitive Regex",
|
||||||
|
"From Case Insensitive Regex",
|
||||||
"Add line numbers",
|
"Add line numbers",
|
||||||
"Remove line numbers",
|
"Remove line numbers",
|
||||||
"To Table",
|
"To Table",
|
||||||
@@ -213,6 +215,7 @@
|
|||||||
"Convert mass",
|
"Convert mass",
|
||||||
"Convert speed",
|
"Convert speed",
|
||||||
"Convert data units",
|
"Convert data units",
|
||||||
|
"Convert co-ordinate format",
|
||||||
"Parse UNIX file permissions",
|
"Parse UNIX file permissions",
|
||||||
"Swap endianness",
|
"Swap endianness",
|
||||||
"Parse colour code",
|
"Parse colour code",
|
||||||
@@ -304,9 +307,7 @@
|
|||||||
"Adler-32 Checksum",
|
"Adler-32 Checksum",
|
||||||
"CRC-16 Checksum",
|
"CRC-16 Checksum",
|
||||||
"CRC-32 Checksum",
|
"CRC-32 Checksum",
|
||||||
"TCP/IP Checksum",
|
"TCP/IP Checksum"
|
||||||
"To Geohash",
|
|
||||||
"From Geohash"
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -341,23 +342,40 @@
|
|||||||
"From MessagePack"
|
"From MessagePack"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"name": "Forensics",
|
||||||
|
"ops": [
|
||||||
|
"Detect File Type",
|
||||||
|
"Scan for Embedded Files",
|
||||||
|
"Remove EXIF",
|
||||||
|
"Extract EXIF"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Multimedia",
|
||||||
|
"ops": [
|
||||||
|
"Render Image",
|
||||||
|
"Play Media",
|
||||||
|
"Remove EXIF",
|
||||||
|
"Extract EXIF",
|
||||||
|
"Split Colour Channels"
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"name": "Other",
|
"name": "Other",
|
||||||
"ops": [
|
"ops": [
|
||||||
"Entropy",
|
"Entropy",
|
||||||
"Frequency distribution",
|
"Frequency distribution",
|
||||||
"Chi Square",
|
"Chi Square",
|
||||||
"Detect File Type",
|
|
||||||
"Scan for Embedded Files",
|
|
||||||
"Disassemble x86",
|
"Disassemble x86",
|
||||||
"Pseudo-Random Number Generator",
|
"Pseudo-Random Number Generator",
|
||||||
"Generate UUID",
|
"Generate UUID",
|
||||||
"Generate TOTP",
|
"Generate TOTP",
|
||||||
"Generate HOTP",
|
"Generate HOTP",
|
||||||
|
"Generate QR Code",
|
||||||
|
"Parse QR Code",
|
||||||
"Haversine distance",
|
"Haversine distance",
|
||||||
"Render Image",
|
"Generate Lorem Ipsum",
|
||||||
"Remove EXIF",
|
|
||||||
"Extract EXIF",
|
|
||||||
"Numberwang",
|
"Numberwang",
|
||||||
"XKCD Random Number"
|
"XKCD Random Number"
|
||||||
]
|
]
|
||||||
@@ -367,6 +385,7 @@
|
|||||||
"ops": [
|
"ops": [
|
||||||
"Magic",
|
"Magic",
|
||||||
"Fork",
|
"Fork",
|
||||||
|
"Subsection",
|
||||||
"Merge",
|
"Merge",
|
||||||
"Register",
|
"Register",
|
||||||
"Label",
|
"Label",
|
||||||
|
|||||||
@@ -222,7 +222,7 @@ export default ${moduleName};
|
|||||||
console.log(`\nNext steps:
|
console.log(`\nNext steps:
|
||||||
1. Add your operation to ${colors.green("src/core/config/Categories.json")}
|
1. Add your operation to ${colors.green("src/core/config/Categories.json")}
|
||||||
2. Write your operation code.
|
2. Write your operation code.
|
||||||
3. Write tests in ${colors.green("test/tests/operations/")}
|
3. Write tests in ${colors.green("tests/operations/tests/")}
|
||||||
4. Run ${colors.cyan("npm run lint")} and ${colors.cyan("npm run test")}
|
4. Run ${colors.cyan("npm run lint")} and ${colors.cyan("npm run test")}
|
||||||
5. Submit a Pull Request to get your operation added to the official CyberChef repository.`);
|
5. Submit a Pull Request to get your operation added to the official CyberChef repository.`);
|
||||||
|
|
||||||
|
|||||||
26
src/core/errors/DishError.mjs
Normal file
26
src/core/errors/DishError.mjs
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/**
|
||||||
|
* Custom error type for handling Dish type errors.
|
||||||
|
* i.e. where the Dish cannot be successfully translated between types
|
||||||
|
*
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2018
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
class DishError extends Error {
|
||||||
|
/**
|
||||||
|
* Standard error constructor. Adds no new behaviour.
|
||||||
|
*
|
||||||
|
* @param args - Standard error args
|
||||||
|
*/
|
||||||
|
constructor(...args) {
|
||||||
|
super(...args);
|
||||||
|
|
||||||
|
this.type = "DishError";
|
||||||
|
|
||||||
|
if (Error.captureStackTrace) {
|
||||||
|
Error.captureStackTrace(this, DishError);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default DishError;
|
||||||
655
src/core/lib/ConvertCoordinates.mjs
Normal file
655
src/core/lib/ConvertCoordinates.mjs
Normal file
@@ -0,0 +1,655 @@
|
|||||||
|
/**
|
||||||
|
* Co-ordinate conversion resources.
|
||||||
|
*
|
||||||
|
* @author j433866 [j433866@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2019
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import geohash from "ngeohash";
|
||||||
|
import geodesy from "geodesy";
|
||||||
|
import OperationError from "../errors/OperationError";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Co-ordinate formats
|
||||||
|
*/
|
||||||
|
export const FORMATS = [
|
||||||
|
"Degrees Minutes Seconds",
|
||||||
|
"Degrees Decimal Minutes",
|
||||||
|
"Decimal Degrees",
|
||||||
|
"Geohash",
|
||||||
|
"Military Grid Reference System",
|
||||||
|
"Ordnance Survey National Grid",
|
||||||
|
"Universal Transverse Mercator"
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats that should be passed to the conversion module as-is
|
||||||
|
*/
|
||||||
|
const NO_CHANGE = [
|
||||||
|
"Geohash",
|
||||||
|
"Military Grid Reference System",
|
||||||
|
"Ordnance Survey National Grid",
|
||||||
|
"Universal Transverse Mercator",
|
||||||
|
];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert a given latitude and longitude into a different format.
|
||||||
|
*
|
||||||
|
* @param {string} input - Input string to be converted
|
||||||
|
* @param {string} inFormat - Format of the input coordinates
|
||||||
|
* @param {string} inDelim - The delimiter splitting the lat/long of the input
|
||||||
|
* @param {string} outFormat - Format to convert to
|
||||||
|
* @param {string} outDelim - The delimiter to separate the output with
|
||||||
|
* @param {string} includeDir - Whether or not to include the compass direction in the output
|
||||||
|
* @param {number} precision - Precision of the result
|
||||||
|
* @returns {string} A formatted string of the converted co-ordinates
|
||||||
|
*/
|
||||||
|
export function convertCoordinates (input, inFormat, inDelim, outFormat, outDelim, includeDir, precision) {
|
||||||
|
let isPair = false,
|
||||||
|
split,
|
||||||
|
latlon,
|
||||||
|
convLat,
|
||||||
|
convLon,
|
||||||
|
conv,
|
||||||
|
hash,
|
||||||
|
utm,
|
||||||
|
mgrs,
|
||||||
|
osng,
|
||||||
|
splitLat,
|
||||||
|
splitLong,
|
||||||
|
lat,
|
||||||
|
lon;
|
||||||
|
|
||||||
|
// Can't have a precision less than 0!
|
||||||
|
if (precision < 0) {
|
||||||
|
precision = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inDelim === "Auto") {
|
||||||
|
// Try to detect a delimiter in the input.
|
||||||
|
inDelim = findDelim(input);
|
||||||
|
if (inDelim === null) {
|
||||||
|
throw new OperationError("Unable to detect the input delimiter automatically.");
|
||||||
|
}
|
||||||
|
} else if (!inDelim.includes("Direction")) {
|
||||||
|
// Convert the delimiter argument value to the actual character
|
||||||
|
inDelim = realDelim(inDelim);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inFormat === "Auto") {
|
||||||
|
// Try to detect the format of the input data
|
||||||
|
inFormat = findFormat(input, inDelim);
|
||||||
|
if (inFormat === null) {
|
||||||
|
throw new OperationError("Unable to detect the input format automatically.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert the output delimiter argument to the real character
|
||||||
|
outDelim = realDelim(outDelim);
|
||||||
|
|
||||||
|
if (!NO_CHANGE.includes(inFormat)) {
|
||||||
|
if (inDelim.includes("Direction")) {
|
||||||
|
// Split on directions
|
||||||
|
split = input.split(/[NnEeSsWw]/g);
|
||||||
|
if (split[0] === "") {
|
||||||
|
// Remove first element if direction preceding
|
||||||
|
split = split.slice(1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
split = input.split(inDelim);
|
||||||
|
}
|
||||||
|
// Replace any co-ordinate symbols with spaces so we can split on them later
|
||||||
|
for (let i = 0; i < split.length; i++) {
|
||||||
|
split[i] = split[i].replace(/[°˝´'"]/g, " ");
|
||||||
|
}
|
||||||
|
if (split.length > 1) {
|
||||||
|
isPair = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Remove any delimiters from the input
|
||||||
|
input = input.replace(inDelim, "");
|
||||||
|
isPair = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Conversions from the input format into a geodesy latlon object
|
||||||
|
switch (inFormat) {
|
||||||
|
case "Geohash":
|
||||||
|
hash = geohash.decode(input.replace(/[^A-Za-z0-9]/g, ""));
|
||||||
|
latlon = new geodesy.LatLonEllipsoidal(hash.latitude, hash.longitude);
|
||||||
|
break;
|
||||||
|
case "Military Grid Reference System":
|
||||||
|
utm = geodesy.Mgrs.parse(input.replace(/[^A-Za-z0-9]/g, "")).toUtm();
|
||||||
|
latlon = utm.toLatLonE();
|
||||||
|
break;
|
||||||
|
case "Ordnance Survey National Grid":
|
||||||
|
osng = geodesy.OsGridRef.parse(input.replace(/[^A-Za-z0-9]/g, ""));
|
||||||
|
latlon = geodesy.OsGridRef.osGridToLatLon(osng);
|
||||||
|
break;
|
||||||
|
case "Universal Transverse Mercator":
|
||||||
|
// Geodesy needs a space between the first 2 digits and the next letter
|
||||||
|
if (/^[\d]{2}[A-Za-z]/.test(input)) {
|
||||||
|
input = input.slice(0, 2) + " " + input.slice(2);
|
||||||
|
}
|
||||||
|
utm = geodesy.Utm.parse(input);
|
||||||
|
latlon = utm.toLatLonE();
|
||||||
|
break;
|
||||||
|
case "Degrees Minutes Seconds":
|
||||||
|
if (isPair) {
|
||||||
|
// Split up the lat/long into degrees / minutes / seconds values
|
||||||
|
splitLat = splitInput(split[0]);
|
||||||
|
splitLong = splitInput(split[1]);
|
||||||
|
|
||||||
|
if (splitLat.length >= 3 && splitLong.length >= 3) {
|
||||||
|
lat = convDMSToDD(splitLat[0], splitLat[1], splitLat[2], 10);
|
||||||
|
lon = convDMSToDD(splitLong[0], splitLong[1], splitLong[2], 10);
|
||||||
|
latlon = new geodesy.LatLonEllipsoidal(lat.degrees, lon.degrees);
|
||||||
|
} else {
|
||||||
|
throw new OperationError("Invalid co-ordinate format for Degrees Minutes Seconds");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Not a pair, so only try to convert one set of co-ordinates
|
||||||
|
splitLat = splitInput(split[0]);
|
||||||
|
if (splitLat.length >= 3) {
|
||||||
|
lat = convDMSToDD(splitLat[0], splitLat[1], splitLat[2]);
|
||||||
|
latlon = new geodesy.LatLonEllipsoidal(lat.degrees, lat.degrees);
|
||||||
|
} else {
|
||||||
|
throw new OperationError("Invalid co-ordinate format for Degrees Minutes Seconds");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "Degrees Decimal Minutes":
|
||||||
|
if (isPair) {
|
||||||
|
splitLat = splitInput(split[0]);
|
||||||
|
splitLong = splitInput(split[1]);
|
||||||
|
if (splitLat.length !== 2 || splitLong.length !== 2) {
|
||||||
|
throw new OperationError("Invalid co-ordinate format for Degrees Decimal Minutes.");
|
||||||
|
}
|
||||||
|
// Convert to decimal degrees, and then convert to a geodesy object
|
||||||
|
lat = convDDMToDD(splitLat[0], splitLat[1], 10);
|
||||||
|
lon = convDDMToDD(splitLong[0], splitLong[1], 10);
|
||||||
|
latlon = new geodesy.LatLonEllipsoidal(lat.degrees, lon.degrees);
|
||||||
|
} else {
|
||||||
|
// Not a pair, so only try to convert one set of co-ordinates
|
||||||
|
splitLat = splitInput(input);
|
||||||
|
if (splitLat.length !== 2) {
|
||||||
|
throw new OperationError("Invalid co-ordinate format for Degrees Decimal Minutes.");
|
||||||
|
}
|
||||||
|
lat = convDDMToDD(splitLat[0], splitLat[1], 10);
|
||||||
|
latlon = new geodesy.LatLonEllipsoidal(lat.degrees, lat.degrees);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case "Decimal Degrees":
|
||||||
|
if (isPair) {
|
||||||
|
splitLat = splitInput(split[0]);
|
||||||
|
splitLong = splitInput(split[1]);
|
||||||
|
if (splitLat.length !== 1 || splitLong.length !== 1) {
|
||||||
|
throw new OperationError("Invalid co-ordinate format for Decimal Degrees.");
|
||||||
|
}
|
||||||
|
latlon = new geodesy.LatLonEllipsoidal(splitLat[0], splitLong[0]);
|
||||||
|
} else {
|
||||||
|
// Not a pair, so only try to convert one set of co-ordinates
|
||||||
|
splitLat = splitInput(split[0]);
|
||||||
|
if (splitLat.length !== 1) {
|
||||||
|
throw new OperationError("Invalid co-ordinate format for Decimal Degrees.");
|
||||||
|
}
|
||||||
|
latlon = new geodesy.LatLonEllipsoidal(splitLat[0], splitLat[0]);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new OperationError(`Unknown input format '${inFormat}'`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Everything is now a geodesy latlon object
|
||||||
|
// These store the latitude and longitude as decimal
|
||||||
|
if (inFormat.includes("Degrees")) {
|
||||||
|
// If the input string contains directions, we need to check if they're S or W.
|
||||||
|
// If either of the directions are, we should make the decimal value negative
|
||||||
|
const dirs = input.toUpperCase().match(/[NESW]/g);
|
||||||
|
if (dirs && dirs.length >= 1) {
|
||||||
|
// Make positive lat/lon values with S/W directions into negative values
|
||||||
|
if (dirs[0] === "S" || dirs[0] === "W" && latlon.lat > 0) {
|
||||||
|
latlon.lat = -latlon.lat;
|
||||||
|
}
|
||||||
|
if (dirs.length >= 2) {
|
||||||
|
if (dirs[1] === "S" || dirs[1] === "W" && latlon.lon > 0) {
|
||||||
|
latlon.lon = -latlon.lon;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to find the compass directions of the lat and long
|
||||||
|
const [latDir, longDir] = findDirs(latlon.lat + "," + latlon.lon, ",");
|
||||||
|
|
||||||
|
// Output conversions for each output format
|
||||||
|
switch (outFormat) {
|
||||||
|
case "Decimal Degrees":
|
||||||
|
// We could use the built in latlon.toString(),
|
||||||
|
// but this makes adjusting the output harder
|
||||||
|
lat = convDDToDD(latlon.lat, precision);
|
||||||
|
lon = convDDToDD(latlon.lon, precision);
|
||||||
|
convLat = lat.string;
|
||||||
|
convLon = lon.string;
|
||||||
|
break;
|
||||||
|
case "Degrees Decimal Minutes":
|
||||||
|
lat = convDDToDDM(latlon.lat, precision);
|
||||||
|
lon = convDDToDDM(latlon.lon, precision);
|
||||||
|
convLat = lat.string;
|
||||||
|
convLon = lon.string;
|
||||||
|
break;
|
||||||
|
case "Degrees Minutes Seconds":
|
||||||
|
lat = convDDToDMS(latlon.lat, precision);
|
||||||
|
lon = convDDToDMS(latlon.lon, precision);
|
||||||
|
convLat = lat.string;
|
||||||
|
convLon = lon.string;
|
||||||
|
break;
|
||||||
|
case "Geohash":
|
||||||
|
convLat = geohash.encode(latlon.lat, latlon.lon, precision);
|
||||||
|
break;
|
||||||
|
case "Military Grid Reference System":
|
||||||
|
utm = latlon.toUtm();
|
||||||
|
mgrs = utm.toMgrs();
|
||||||
|
// MGRS wants a precision that's an even number between 2 and 10
|
||||||
|
if (precision % 2 !== 0) {
|
||||||
|
precision = precision + 1;
|
||||||
|
}
|
||||||
|
if (precision > 10) {
|
||||||
|
precision = 10;
|
||||||
|
}
|
||||||
|
convLat = mgrs.toString(precision);
|
||||||
|
break;
|
||||||
|
case "Ordnance Survey National Grid":
|
||||||
|
osng = geodesy.OsGridRef.latLonToOsGrid(latlon);
|
||||||
|
if (osng.toString() === "") {
|
||||||
|
throw new OperationError("Could not convert co-ordinates to OS National Grid. Are the co-ordinates in range?");
|
||||||
|
}
|
||||||
|
// OSNG wants a precision that's an even number between 2 and 10
|
||||||
|
if (precision % 2 !== 0) {
|
||||||
|
precision = precision + 1;
|
||||||
|
}
|
||||||
|
if (precision > 10) {
|
||||||
|
precision = 10;
|
||||||
|
}
|
||||||
|
convLat = osng.toString(precision);
|
||||||
|
break;
|
||||||
|
case "Universal Transverse Mercator":
|
||||||
|
utm = latlon.toUtm();
|
||||||
|
convLat = utm.toString(precision);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (convLat === undefined) {
|
||||||
|
throw new OperationError("Error converting co-ordinates.");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (outFormat.includes("Degrees")) {
|
||||||
|
// Format DD/DDM/DMS for output
|
||||||
|
// If we're outputting a compass direction, remove the negative sign
|
||||||
|
if (latDir === "S" && includeDir !== "None") {
|
||||||
|
convLat = convLat.replace("-", "");
|
||||||
|
}
|
||||||
|
if (longDir === "W" && includeDir !== "None") {
|
||||||
|
convLon = convLon.replace("-", "");
|
||||||
|
}
|
||||||
|
|
||||||
|
let outConv = "";
|
||||||
|
if (includeDir === "Before") {
|
||||||
|
outConv += latDir + " ";
|
||||||
|
}
|
||||||
|
|
||||||
|
outConv += convLat;
|
||||||
|
if (includeDir === "After") {
|
||||||
|
outConv += " " + latDir;
|
||||||
|
}
|
||||||
|
outConv += outDelim;
|
||||||
|
if (isPair) {
|
||||||
|
if (includeDir === "Before") {
|
||||||
|
outConv += longDir + " ";
|
||||||
|
}
|
||||||
|
outConv += convLon;
|
||||||
|
if (includeDir === "After") {
|
||||||
|
outConv += " " + longDir;
|
||||||
|
}
|
||||||
|
outConv += outDelim;
|
||||||
|
}
|
||||||
|
conv = outConv;
|
||||||
|
} else {
|
||||||
|
conv = convLat + outDelim;
|
||||||
|
}
|
||||||
|
|
||||||
|
return conv;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Split up the input using a space or degrees signs, and sanitise the result
|
||||||
|
*
|
||||||
|
* @param {string} input - The input data to be split
|
||||||
|
* @returns {number[]} An array of the different items in the string, stored as floats
|
||||||
|
*/
|
||||||
|
function splitInput (input){
|
||||||
|
const split = [];
|
||||||
|
|
||||||
|
input.split(/\s+/).forEach(item => {
|
||||||
|
// Remove any character that isn't a digit, decimal point or negative sign
|
||||||
|
item = item.replace(/[^0-9.-]/g, "");
|
||||||
|
if (item.length > 0){
|
||||||
|
// Turn the item into a float
|
||||||
|
split.push(parseFloat(item));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return split;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert Degrees Minutes Seconds to Decimal Degrees
|
||||||
|
*
|
||||||
|
* @param {number} degrees - The degrees of the input co-ordinates
|
||||||
|
* @param {number} minutes - The minutes of the input co-ordinates
|
||||||
|
* @param {number} seconds - The seconds of the input co-ordinates
|
||||||
|
* @param {number} precision - The precision the result should be rounded to
|
||||||
|
* @returns {{string: string, degrees: number}} An object containing the raw converted value (obj.degrees), and a formatted string version (obj.string)
|
||||||
|
*/
|
||||||
|
function convDMSToDD (degrees, minutes, seconds, precision){
|
||||||
|
const absDegrees = Math.abs(degrees);
|
||||||
|
let conv = absDegrees + (minutes / 60) + (seconds / 3600);
|
||||||
|
let outString = round(conv, precision) + "°";
|
||||||
|
if (isNegativeZero(degrees) || degrees < 0) {
|
||||||
|
conv = -conv;
|
||||||
|
outString = "-" + outString;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
"degrees": conv,
|
||||||
|
"string": outString
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert Decimal Degrees Minutes to Decimal Degrees
|
||||||
|
*
|
||||||
|
* @param {number} degrees - The input degrees to be converted
|
||||||
|
* @param {number} minutes - The input minutes to be converted
|
||||||
|
* @param {number} precision - The precision which the result should be rounded to
|
||||||
|
* @returns {{string: string, degrees: number}} An object containing the raw converted value (obj.degrees), and a formatted string version (obj.string)
|
||||||
|
*/
|
||||||
|
function convDDMToDD (degrees, minutes, precision) {
|
||||||
|
const absDegrees = Math.abs(degrees);
|
||||||
|
let conv = absDegrees + minutes / 60;
|
||||||
|
let outString = round(conv, precision) + "°";
|
||||||
|
if (isNegativeZero(degrees) || degrees < 0) {
|
||||||
|
conv = -conv;
|
||||||
|
outString = "-" + outString;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
"degrees": conv,
|
||||||
|
"string": outString
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert Decimal Degrees to Decimal Degrees
|
||||||
|
*
|
||||||
|
* Doesn't affect the input, just puts it into an object
|
||||||
|
* @param {number} degrees - The input degrees to be converted
|
||||||
|
* @param {number} precision - The precision which the result should be rounded to
|
||||||
|
* @returns {{string: string, degrees: number}} An object containing the raw converted value (obj.degrees), and a formatted string version (obj.string)
|
||||||
|
*/
|
||||||
|
function convDDToDD (degrees, precision) {
|
||||||
|
return {
|
||||||
|
"degrees": degrees,
|
||||||
|
"string": round(degrees, precision) + "°"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert Decimal Degrees to Degrees Minutes Seconds
|
||||||
|
*
|
||||||
|
* @param {number} decDegrees - The input data to be converted
|
||||||
|
* @param {number} precision - The precision which the result should be rounded to
|
||||||
|
* @returns {{string: string, degrees: number, minutes: number, seconds: number}} An object containing the raw converted value as separate numbers (.degrees, .minutes, .seconds), and a formatted string version (obj.string)
|
||||||
|
*/
|
||||||
|
function convDDToDMS (decDegrees, precision) {
|
||||||
|
const absDegrees = Math.abs(decDegrees);
|
||||||
|
let degrees = Math.floor(absDegrees);
|
||||||
|
const minutes = Math.floor(60 * (absDegrees - degrees)),
|
||||||
|
seconds = round(3600 * (absDegrees - degrees) - 60 * minutes, precision);
|
||||||
|
let outString = degrees + "° " + minutes + "' " + seconds + "\"";
|
||||||
|
if (isNegativeZero(decDegrees) || decDegrees < 0) {
|
||||||
|
degrees = -degrees;
|
||||||
|
outString = "-" + outString;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
"degrees": degrees,
|
||||||
|
"minutes": minutes,
|
||||||
|
"seconds": seconds,
|
||||||
|
"string": outString
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert Decimal Degrees to Degrees Decimal Minutes
|
||||||
|
*
|
||||||
|
* @param {number} decDegrees - The input degrees to be converted
|
||||||
|
* @param {number} precision - The precision the input data should be rounded to
|
||||||
|
* @returns {{string: string, degrees: number, minutes: number}} An object containing the raw converted value as separate numbers (.degrees, .minutes), and a formatted string version (obj.string)
|
||||||
|
*/
|
||||||
|
function convDDToDDM (decDegrees, precision) {
|
||||||
|
const absDegrees = Math.abs(decDegrees);
|
||||||
|
let degrees = Math.floor(absDegrees);
|
||||||
|
const minutes = absDegrees - degrees,
|
||||||
|
decMinutes = round(minutes * 60, precision);
|
||||||
|
let outString = degrees + "° " + decMinutes + "'";
|
||||||
|
if (decDegrees < 0 || isNegativeZero(decDegrees)) {
|
||||||
|
degrees = -degrees;
|
||||||
|
outString = "-" + outString;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
"degrees": degrees,
|
||||||
|
"minutes": decMinutes,
|
||||||
|
"string": outString,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds and returns the compass directions in an input string
|
||||||
|
*
|
||||||
|
* @param {string} input - The input co-ordinates containing the direction
|
||||||
|
* @param {string} delim - The delimiter separating latitide and longitude
|
||||||
|
* @returns {string[]} String array containing the latitude and longitude directions
|
||||||
|
*/
|
||||||
|
export function findDirs(input, delim) {
|
||||||
|
const upperInput = input.toUpperCase();
|
||||||
|
const dirExp = new RegExp(/[NESW]/g);
|
||||||
|
|
||||||
|
const dirs = upperInput.match(dirExp);
|
||||||
|
|
||||||
|
if (dirs) {
|
||||||
|
// If there's actually compass directions
|
||||||
|
// in the input, use these to work out the direction
|
||||||
|
if (dirs.length <= 2 && dirs.length >= 1) {
|
||||||
|
return dirs.length === 2 ? [dirs[0], dirs[1]] : [dirs[0], ""];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nothing was returned, so guess the directions
|
||||||
|
let lat = upperInput,
|
||||||
|
long,
|
||||||
|
latDir = "",
|
||||||
|
longDir = "";
|
||||||
|
if (!delim.includes("Direction")) {
|
||||||
|
if (upperInput.includes(delim)) {
|
||||||
|
const split = upperInput.split(delim);
|
||||||
|
if (split.length >= 1) {
|
||||||
|
if (split[0] !== "") {
|
||||||
|
lat = split[0];
|
||||||
|
}
|
||||||
|
if (split.length >= 2 && split[1] !== "") {
|
||||||
|
long = split[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const split = upperInput.split(dirExp);
|
||||||
|
if (split.length > 1) {
|
||||||
|
lat = split[0] === "" ? split[1] : split[0];
|
||||||
|
if (split.length > 2 && split[2] !== "") {
|
||||||
|
long = split[2];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lat) {
|
||||||
|
lat = parseFloat(lat);
|
||||||
|
latDir = lat < 0 ? "S" : "N";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (long) {
|
||||||
|
long = parseFloat(long);
|
||||||
|
longDir = long < 0 ? "W" : "E";
|
||||||
|
}
|
||||||
|
|
||||||
|
return [latDir, longDir];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Detects the co-ordinate format of the input data
|
||||||
|
*
|
||||||
|
* @param {string} input - The input data whose format we need to detect
|
||||||
|
* @param {string} delim - The delimiter separating the data in input
|
||||||
|
* @returns {string} The input format
|
||||||
|
*/
|
||||||
|
export function findFormat (input, delim) {
|
||||||
|
let testData;
|
||||||
|
const mgrsPattern = new RegExp(/^[0-9]{2}\s?[C-HJ-NP-X]{1}\s?[A-HJ-NP-Z][A-HJ-NP-V]\s?[0-9\s]+/),
|
||||||
|
osngPattern = new RegExp(/^[A-HJ-Z]{2}\s+[0-9\s]+$/),
|
||||||
|
geohashPattern = new RegExp(/^[0123456789BCDEFGHJKMNPQRSTUVWXYZ]+$/),
|
||||||
|
utmPattern = new RegExp(/^[0-9]{2}\s?[C-HJ-NP-X]\s[0-9.]+\s?[0-9.]+$/),
|
||||||
|
degPattern = new RegExp(/[°'"]/g);
|
||||||
|
|
||||||
|
input = input.trim();
|
||||||
|
|
||||||
|
if (delim !== null && delim.includes("Direction")) {
|
||||||
|
const split = input.split(/[NnEeSsWw]/);
|
||||||
|
if (split.length > 1) {
|
||||||
|
testData = split[0] === "" ? split[1] : split[0];
|
||||||
|
}
|
||||||
|
} else if (delim !== null && delim !== "") {
|
||||||
|
if (input.includes(delim)) {
|
||||||
|
const split = input.split(delim);
|
||||||
|
if (split.length > 1) {
|
||||||
|
testData = split[0] === "" ? split[1] : split[0];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
testData = input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test non-degrees formats
|
||||||
|
if (!degPattern.test(input)) {
|
||||||
|
const filteredInput = input.toUpperCase().replace(delim, "");
|
||||||
|
|
||||||
|
if (utmPattern.test(filteredInput)) {
|
||||||
|
return "Universal Transverse Mercator";
|
||||||
|
}
|
||||||
|
if (mgrsPattern.test(filteredInput)) {
|
||||||
|
return "Military Grid Reference System";
|
||||||
|
}
|
||||||
|
if (osngPattern.test(filteredInput)) {
|
||||||
|
return "Ordnance Survey National Grid";
|
||||||
|
}
|
||||||
|
if (geohashPattern.test(filteredInput)) {
|
||||||
|
return "Geohash";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test DMS/DDM/DD formats
|
||||||
|
if (testData !== undefined) {
|
||||||
|
const split = splitInput(testData);
|
||||||
|
switch (split.length){
|
||||||
|
case 3:
|
||||||
|
return "Degrees Minutes Seconds";
|
||||||
|
case 2:
|
||||||
|
return "Degrees Decimal Minutes";
|
||||||
|
case 1:
|
||||||
|
return "Decimal Degrees";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Automatically find the delimeter type from the given input
|
||||||
|
*
|
||||||
|
* @param {string} input
|
||||||
|
* @returns {string} Delimiter type
|
||||||
|
*/
|
||||||
|
export function findDelim (input) {
|
||||||
|
input = input.trim();
|
||||||
|
const delims = [",", ";", ":"];
|
||||||
|
const testDir = input.match(/[NnEeSsWw]/g);
|
||||||
|
if (testDir !== null && testDir.length > 0 && testDir.length < 3) {
|
||||||
|
// Possibly contains a direction
|
||||||
|
const splitInput = input.split(/[NnEeSsWw]/);
|
||||||
|
if (splitInput.length <= 3 && splitInput.length > 0) {
|
||||||
|
// If there's 3 splits (one should be empty), then assume we have directions
|
||||||
|
if (splitInput[0] === "") {
|
||||||
|
return "Direction Preceding";
|
||||||
|
} else if (splitInput[splitInput.length - 1] === "") {
|
||||||
|
return "Direction Following";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop through the standard delimiters, and try to find them in the input
|
||||||
|
for (let i = 0; i < delims.length; i++) {
|
||||||
|
const delim = delims[i];
|
||||||
|
if (input.includes(delim)) {
|
||||||
|
const splitInput = input.split(delim);
|
||||||
|
if (splitInput.length <= 3 && splitInput.length > 0) {
|
||||||
|
// Don't want to try and convert more than 2 co-ordinates
|
||||||
|
return delim;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the real string for a delimiter name.
|
||||||
|
*
|
||||||
|
* @param {string} delim The delimiter to be matched
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
export function realDelim (delim) {
|
||||||
|
return {
|
||||||
|
"Auto": "Auto",
|
||||||
|
"Space": " ",
|
||||||
|
"\\n": "\n",
|
||||||
|
"Comma": ",",
|
||||||
|
"Semi-colon": ";",
|
||||||
|
"Colon": ":"
|
||||||
|
}[delim];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if a zero is negative
|
||||||
|
*
|
||||||
|
* @param {number} zero
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
function isNegativeZero(zero) {
|
||||||
|
return zero === 0 && (1/zero < 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rounds a number to a specified number of decimal places
|
||||||
|
*
|
||||||
|
* @param {number} input - The number to be rounded
|
||||||
|
* @param {precision} precision - The number of decimal places the number should be rounded to
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
function round(input, precision) {
|
||||||
|
precision = Math.pow(10, precision);
|
||||||
|
return Math.round(input * precision) / precision;
|
||||||
|
}
|
||||||
230
src/core/lib/LoremIpsum.mjs
Normal file
230
src/core/lib/LoremIpsum.mjs
Normal file
@@ -0,0 +1,230 @@
|
|||||||
|
/**
|
||||||
|
* Lorem Ipsum generator.
|
||||||
|
*
|
||||||
|
* @author Klaxon [klaxon@veyr.com]
|
||||||
|
* @copyright Crown Copyright 2018
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate lorem ipsum paragraphs.
|
||||||
|
*
|
||||||
|
* @param {number} length
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
export function GenerateParagraphs(length=3) {
|
||||||
|
const paragraphs = [];
|
||||||
|
while (paragraphs.length < length) {
|
||||||
|
const paragraphLength = getRandomLength(PARAGRAPH_LENGTH_MEAN, PARAGRAPH_LENGTH_STD_DEV);
|
||||||
|
const sentences = [];
|
||||||
|
while (sentences.length < paragraphLength) {
|
||||||
|
const sentenceLength = getRandomLength(SENTENCE_LENGTH_MEAN, SENTENCE_LENGTH_STD_DEV);
|
||||||
|
const sentence = getWords(sentenceLength);
|
||||||
|
sentences.push(formatSentence(sentence));
|
||||||
|
}
|
||||||
|
paragraphs.push(formatParagraph(sentences));
|
||||||
|
}
|
||||||
|
paragraphs[paragraphs.length-1] = paragraphs[paragraphs.length-1].slice(0, -2);
|
||||||
|
paragraphs[0] = replaceStart(paragraphs[0]);
|
||||||
|
return paragraphs.join("");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate lorem ipsum sentences.
|
||||||
|
*
|
||||||
|
* @param {number} length
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
export function GenerateSentences(length=3) {
|
||||||
|
const sentences = [];
|
||||||
|
while (sentences.length < length) {
|
||||||
|
const sentenceLength = getRandomLength(SENTENCE_LENGTH_MEAN, SENTENCE_LENGTH_STD_DEV);
|
||||||
|
const sentence = getWords(sentenceLength);
|
||||||
|
sentences.push(formatSentence(sentence));
|
||||||
|
}
|
||||||
|
const paragraphs = sentencesToParagraphs(sentences);
|
||||||
|
return paragraphs.join("");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate lorem ipsum words.
|
||||||
|
*
|
||||||
|
* @param {number} length
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
export function GenerateWords(length=3) {
|
||||||
|
const words = getWords(length);
|
||||||
|
const sentences = wordsToSentences(words);
|
||||||
|
const paragraphs = sentencesToParagraphs(sentences);
|
||||||
|
return paragraphs.join("");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate lorem ipsum bytes.
|
||||||
|
*
|
||||||
|
* @param {number} length
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
export function GenerateBytes(length=3) {
|
||||||
|
const str = GenerateWords(length/3);
|
||||||
|
return str.slice(0, length);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get array of randomly selected words from the lorem ipsum wordList.
|
||||||
|
*
|
||||||
|
* @param {number} length
|
||||||
|
* @returns {string[]}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function getWords(length=3) {
|
||||||
|
const words = [];
|
||||||
|
let word;
|
||||||
|
let previousWord;
|
||||||
|
while (words.length < length){
|
||||||
|
do {
|
||||||
|
word = wordList[Math.floor(Math.random() * wordList.length)];
|
||||||
|
} while (previousWord === word);
|
||||||
|
words.push(word);
|
||||||
|
previousWord = word;
|
||||||
|
}
|
||||||
|
return words;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert an array of words into an array of sentences
|
||||||
|
*
|
||||||
|
* @param {string[]} words
|
||||||
|
* @returns {string[]}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function wordsToSentences(words) {
|
||||||
|
const sentences = [];
|
||||||
|
while (words.length > 0) {
|
||||||
|
const sentenceLength = getRandomLength(SENTENCE_LENGTH_MEAN, SENTENCE_LENGTH_STD_DEV);
|
||||||
|
if (sentenceLength <= words.length) {
|
||||||
|
sentences.push(formatSentence(words.splice(0, sentenceLength)));
|
||||||
|
} else {
|
||||||
|
sentences.push(formatSentence(words.splice(0, words.length)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sentences;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert an array of sentences into an array of paragraphs
|
||||||
|
*
|
||||||
|
* @param {string[]} sentences
|
||||||
|
* @returns {string[]}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function sentencesToParagraphs(sentences) {
|
||||||
|
const paragraphs = [];
|
||||||
|
while (sentences.length > 0) {
|
||||||
|
const paragraphLength = getRandomLength(PARAGRAPH_LENGTH_MEAN, PARAGRAPH_LENGTH_STD_DEV);
|
||||||
|
paragraphs.push(formatParagraph(sentences.splice(0, paragraphLength)));
|
||||||
|
}
|
||||||
|
paragraphs[paragraphs.length-1] = paragraphs[paragraphs.length-1].slice(0, -1);
|
||||||
|
paragraphs[0] = replaceStart(paragraphs[0]);
|
||||||
|
return paragraphs;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format an array of words into a sentence.
|
||||||
|
*
|
||||||
|
* @param {string[]} words
|
||||||
|
* @returns {string}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function formatSentence(words) {
|
||||||
|
// 0.35 chance of a comma being added randomly to the sentence.
|
||||||
|
if (Math.random() < PROBABILITY_OF_A_COMMA) {
|
||||||
|
const pos = Math.round(Math.random()*(words.length-1));
|
||||||
|
words[pos] +=",";
|
||||||
|
}
|
||||||
|
let sentence = words.join(" ");
|
||||||
|
sentence = sentence.charAt(0).toUpperCase() + sentence.slice(1);
|
||||||
|
sentence += ".";
|
||||||
|
return sentence;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Format an array of sentences into a paragraph.
|
||||||
|
*
|
||||||
|
* @param {string[]} sentences
|
||||||
|
* @returns {string}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function formatParagraph(sentences) {
|
||||||
|
let paragraph = sentences.join(" ");
|
||||||
|
paragraph += "\n\n";
|
||||||
|
return paragraph;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get a random number based on a mean and standard deviation.
|
||||||
|
*
|
||||||
|
* @param {number} mean
|
||||||
|
* @param {number} stdDev
|
||||||
|
* @returns {number}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function getRandomLength(mean, stdDev) {
|
||||||
|
let length;
|
||||||
|
do {
|
||||||
|
length = Math.round((Math.random()*2-1)+(Math.random()*2-1)+(Math.random()*2-1)*stdDev+mean);
|
||||||
|
} while (length <= 0);
|
||||||
|
return length;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replace first 5 words with "Lorem ipsum dolor sit amet"
|
||||||
|
*
|
||||||
|
* @param {string[]} str
|
||||||
|
* @returns {string[]}
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
function replaceStart(str) {
|
||||||
|
let words = str.split(" ");
|
||||||
|
if (words.length > 5) {
|
||||||
|
words.splice(0, 5, "Lorem", "ipsum", "dolor", "sit", "amet");
|
||||||
|
return words.join(" ");
|
||||||
|
} else {
|
||||||
|
const lorem = ["Lorem", "ipsum", "dolor", "sit", "amet"];
|
||||||
|
words = lorem.slice(0, words.length);
|
||||||
|
str = words.join(" ");
|
||||||
|
str += ".";
|
||||||
|
return str;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const SENTENCE_LENGTH_MEAN = 15;
|
||||||
|
const SENTENCE_LENGTH_STD_DEV = 9;
|
||||||
|
const PARAGRAPH_LENGTH_MEAN = 5;
|
||||||
|
const PARAGRAPH_LENGTH_STD_DEV = 2;
|
||||||
|
const PROBABILITY_OF_A_COMMA = 0.35;
|
||||||
|
|
||||||
|
const wordList = [
|
||||||
|
"ad", "adipisicing", "aliqua", "aliquip", "amet", "anim",
|
||||||
|
"aute", "cillum", "commodo", "consectetur", "consequat", "culpa",
|
||||||
|
"cupidatat", "deserunt", "do", "dolor", "dolore", "duis",
|
||||||
|
"ea", "eiusmod", "elit", "enim", "esse", "est",
|
||||||
|
"et", "eu", "ex", "excepteur", "exercitation", "fugiat",
|
||||||
|
"id", "in", "incididunt", "ipsum", "irure", "labore",
|
||||||
|
"laboris", "laborum", "Lorem", "magna", "minim", "mollit",
|
||||||
|
"nisi", "non", "nostrud", "nulla", "occaecat", "officia",
|
||||||
|
"pariatur", "proident", "qui", "quis", "reprehenderit", "sint",
|
||||||
|
"sit", "sunt", "tempor", "ullamco", "ut", "velit",
|
||||||
|
"veniam", "voluptate",
|
||||||
|
];
|
||||||
@@ -19,7 +19,7 @@ class Adler32Checksum extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "Adler-32 Checksum";
|
this.name = "Adler-32 Checksum";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "Adler-32 is a checksum algorithm which was invented by Mark Adler in 1995, and is a modification of the Fletcher checksum. Compared to a cyclic redundancy check of the same length, it trades reliability for speed (preferring the latter).<br><br>Adler-32 is more reliable than Fletcher-16, and slightly less reliable than Fletcher-32.";
|
this.description = "Adler-32 is a checksum algorithm which was invented by Mark Adler in 1995, and is a modification of the Fletcher checksum. Compared to a cyclic redundancy check of the same length, it trades reliability for speed (preferring the latter).<br><br>Adler-32 is more reliable than Fletcher-16, and slightly less reliable than Fletcher-32.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Adler-32";
|
this.infoURL = "https://wikipedia.org/wiki/Adler-32";
|
||||||
this.inputType = "byteArray";
|
this.inputType = "byteArray";
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class AnalyseHash extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "Analyse hash";
|
this.name = "Analyse hash";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "Tries to determine information about a given hash and suggests which algorithm may have been used to generate it based on its length.";
|
this.description = "Tries to determine information about a given hash and suggests which algorithm may have been used to generate it based on its length.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Comparison_of_cryptographic_hash_functions";
|
this.infoURL = "https://wikipedia.org/wiki/Comparison_of_cryptographic_hash_functions";
|
||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import Operation from "../Operation";
|
import Operation from "../Operation";
|
||||||
import bsonjs from "bson";
|
import bson from "bson";
|
||||||
import OperationError from "../errors/OperationError";
|
import OperationError from "../errors/OperationError";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -36,8 +36,6 @@ class BSONDeserialise extends Operation {
|
|||||||
run(input, args) {
|
run(input, args) {
|
||||||
if (!input.byteLength) return "";
|
if (!input.byteLength) return "";
|
||||||
|
|
||||||
const bson = new bsonjs();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = bson.deserialize(new Buffer(input));
|
const data = bson.deserialize(new Buffer(input));
|
||||||
return JSON.stringify(data, null, 2);
|
return JSON.stringify(data, null, 2);
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import Operation from "../Operation";
|
import Operation from "../Operation";
|
||||||
import bsonjs from "bson";
|
import bson from "bson";
|
||||||
import OperationError from "../errors/OperationError";
|
import OperationError from "../errors/OperationError";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -36,8 +36,6 @@ class BSONSerialise extends Operation {
|
|||||||
run(input, args) {
|
run(input, args) {
|
||||||
if (!input) return new ArrayBuffer();
|
if (!input) return new ArrayBuffer();
|
||||||
|
|
||||||
const bson = new bsonjs();
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const data = JSON.parse(input);
|
const data = JSON.parse(input);
|
||||||
return bson.serialize(data).buffer;
|
return bson.serialize(data).buffer;
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class Bcrypt extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "Bcrypt";
|
this.name = "Bcrypt";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "bcrypt is a password hashing function designed by Niels Provos and David Mazi\xe8res, based on the Blowfish cipher, and presented at USENIX in 1999. Besides incorporating a salt to protect against rainbow table attacks, bcrypt is an adaptive function: over time, the iteration count (rounds) can be increased to make it slower, so it remains resistant to brute-force search attacks even with increasing computation power.<br><br>Enter the password in the input to generate its hash.";
|
this.description = "bcrypt is a password hashing function designed by Niels Provos and David Mazi\xe8res, based on the Blowfish cipher, and presented at USENIX in 1999. Besides incorporating a salt to protect against rainbow table attacks, bcrypt is an adaptive function: over time, the iteration count (rounds) can be increased to make it slower, so it remains resistant to brute-force search attacks even with increasing computation power.<br><br>Enter the password in the input to generate its hash.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Bcrypt";
|
this.infoURL = "https://wikipedia.org/wiki/Bcrypt";
|
||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class BcryptCompare extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "Bcrypt compare";
|
this.name = "Bcrypt compare";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "Tests whether the input matches the given bcrypt hash. To test multiple possible passwords, use the 'Fork' operation.";
|
this.description = "Tests whether the input matches the given bcrypt hash. To test multiple possible passwords, use the 'Fork' operation.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Bcrypt";
|
this.infoURL = "https://wikipedia.org/wiki/Bcrypt";
|
||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class BcryptParse extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "Bcrypt parse";
|
this.name = "Bcrypt parse";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "Parses a bcrypt hash to determine the number of rounds used, the salt, and the password hash.";
|
this.description = "Parses a bcrypt hash to determine the number of rounds used, the salt, and the password hash.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Bcrypt";
|
this.infoURL = "https://wikipedia.org/wiki/Bcrypt";
|
||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class CRC16Checksum extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "CRC-16 Checksum";
|
this.name = "CRC-16 Checksum";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "A cyclic redundancy check (CRC) is an error-detecting code commonly used in digital networks and storage devices to detect accidental changes to raw data.<br><br>The CRC was invented by W. Wesley Peterson in 1961.";
|
this.description = "A cyclic redundancy check (CRC) is an error-detecting code commonly used in digital networks and storage devices to detect accidental changes to raw data.<br><br>The CRC was invented by W. Wesley Peterson in 1961.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Cyclic_redundancy_check";
|
this.infoURL = "https://wikipedia.org/wiki/Cyclic_redundancy_check";
|
||||||
this.inputType = "ArrayBuffer";
|
this.inputType = "ArrayBuffer";
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class CRC32Checksum extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "CRC-32 Checksum";
|
this.name = "CRC-32 Checksum";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "A cyclic redundancy check (CRC) is an error-detecting code commonly used in digital networks and storage devices to detect accidental changes to raw data.<br><br>The CRC was invented by W. Wesley Peterson in 1961; the 32-bit CRC function of Ethernet and many other standards is the work of several researchers and was published in 1975.";
|
this.description = "A cyclic redundancy check (CRC) is an error-detecting code commonly used in digital networks and storage devices to detect accidental changes to raw data.<br><br>The CRC was invented by W. Wesley Peterson in 1961; the 32-bit CRC function of Ethernet and many other standards is the work of several researchers and was published in 1975.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Cyclic_redundancy_check";
|
this.infoURL = "https://wikipedia.org/wiki/Cyclic_redundancy_check";
|
||||||
this.inputType = "ArrayBuffer";
|
this.inputType = "ArrayBuffer";
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class CTPH extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "CTPH";
|
this.name = "CTPH";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "Context Triggered Piecewise Hashing, also called Fuzzy Hashing, can match inputs that have homologies. Such inputs have sequences of identical bytes in the same order, although bytes in between these sequences may be different in both content and length.<br><br>CTPH was originally based on the work of Dr. Andrew Tridgell and a spam email detector called SpamSum. This method was adapted by Jesse Kornblum and published at the DFRWS conference in 2006 in a paper 'Identifying Almost Identical Files Using Context Triggered Piecewise Hashing'.";
|
this.description = "Context Triggered Piecewise Hashing, also called Fuzzy Hashing, can match inputs that have homologies. Such inputs have sequences of identical bytes in the same order, although bytes in between these sequences may be different in both content and length.<br><br>CTPH was originally based on the work of Dr. Andrew Tridgell and a spam email detector called SpamSum. This method was adapted by Jesse Kornblum and published at the DFRWS conference in 2006 in a paper 'Identifying Almost Identical Files Using Context Triggered Piecewise Hashing'.";
|
||||||
this.infoURL = "https://forensicswiki.org/wiki/Context_Triggered_Piecewise_Hashing";
|
this.infoURL = "https://forensicswiki.org/wiki/Context_Triggered_Piecewise_Hashing";
|
||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class CompareCTPHHashes extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "Compare CTPH hashes";
|
this.name = "Compare CTPH hashes";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "Compares two Context Triggered Piecewise Hashing (CTPH) fuzzy hashes to determine the similarity between them on a scale of 0 to 100.";
|
this.description = "Compares two Context Triggered Piecewise Hashing (CTPH) fuzzy hashes to determine the similarity between them on a scale of 0 to 100.";
|
||||||
this.infoURL = "https://forensicswiki.org/wiki/Context_Triggered_Piecewise_Hashing";
|
this.infoURL = "https://forensicswiki.org/wiki/Context_Triggered_Piecewise_Hashing";
|
||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class CompareSSDEEPHashes extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "Compare SSDEEP hashes";
|
this.name = "Compare SSDEEP hashes";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "Compares two SSDEEP fuzzy hashes to determine the similarity between them on a scale of 0 to 100.";
|
this.description = "Compares two SSDEEP fuzzy hashes to determine the similarity between them on a scale of 0 to 100.";
|
||||||
this.infoURL = "https://forensicswiki.org/wiki/Ssdeep";
|
this.infoURL = "https://forensicswiki.org/wiki/Ssdeep";
|
||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
|
|||||||
95
src/core/operations/ConvertCoordinateFormat.mjs
Normal file
95
src/core/operations/ConvertCoordinateFormat.mjs
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
/**
|
||||||
|
* @author j433866 [j433866@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2019
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation";
|
||||||
|
import {FORMATS, convertCoordinates} from "../lib/ConvertCoordinates";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert co-ordinate format operation
|
||||||
|
*/
|
||||||
|
class ConvertCoordinateFormat extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ConvertCoordinateFormat constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Convert co-ordinate format";
|
||||||
|
this.module = "Hashing";
|
||||||
|
this.description = "Converts geographical coordinates between different formats.<br><br>Supported formats:<ul><li>Degrees Minutes Seconds (DMS)</li><li>Degrees Decimal Minutes (DDM)</li><li>Decimal Degrees (DD)</li><li>Geohash</li><li>Military Grid Reference System (MGRS)</li><li>Ordnance Survey National Grid (OSNG)</li><li>Universal Transverse Mercator (UTM)</li></ul><br>The operation can try to detect the input co-ordinate format and delimiter automatically, but this may not always work correctly.";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/Geographic_coordinate_conversion";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
"name": "Input Format",
|
||||||
|
"type": "option",
|
||||||
|
"value": ["Auto"].concat(FORMATS)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Input Delimiter",
|
||||||
|
"type": "option",
|
||||||
|
"value": [
|
||||||
|
"Auto",
|
||||||
|
"Direction Preceding",
|
||||||
|
"Direction Following",
|
||||||
|
"\\n",
|
||||||
|
"Comma",
|
||||||
|
"Semi-colon",
|
||||||
|
"Colon"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Output Format",
|
||||||
|
"type": "option",
|
||||||
|
"value": FORMATS
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Output Delimiter",
|
||||||
|
"type": "option",
|
||||||
|
"value": [
|
||||||
|
"Space",
|
||||||
|
"\\n",
|
||||||
|
"Comma",
|
||||||
|
"Semi-colon",
|
||||||
|
"Colon"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Include Compass Directions",
|
||||||
|
"type": "option",
|
||||||
|
"value": [
|
||||||
|
"None",
|
||||||
|
"Before",
|
||||||
|
"After"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Precision",
|
||||||
|
"type": "number",
|
||||||
|
"value": 3
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
if (input.replace(/[\s+]/g, "") !== "") {
|
||||||
|
const [inFormat, inDelim, outFormat, outDelim, incDirection, precision] = args;
|
||||||
|
const result = convertCoordinates(input, inFormat, inDelim, outFormat, outDelim, incDirection, precision);
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ConvertCoordinateFormat;
|
||||||
@@ -20,7 +20,7 @@ class DecodeText extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "Decode text";
|
this.name = "Decode text";
|
||||||
this.module = "CharEnc";
|
this.module = "Encodings";
|
||||||
this.description = [
|
this.description = [
|
||||||
"Decodes text from the chosen character encoding.",
|
"Decodes text from the chosen character encoding.",
|
||||||
"<br><br>",
|
"<br><br>",
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ class Divide extends Operation {
|
|||||||
*/
|
*/
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
const val = div(createNumArray(input, args[0]));
|
const val = div(createNumArray(input, args[0]));
|
||||||
return val instanceof BigNumber ? val : new BigNumber(NaN);
|
return BigNumber.isBigNumber(val) ? val : new BigNumber(NaN);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class EncodeText extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "Encode text";
|
this.name = "Encode text";
|
||||||
this.module = "CharEnc";
|
this.module = "Encodings";
|
||||||
this.description = [
|
this.description = [
|
||||||
"Encodes text into the chosen character encoding.",
|
"Encodes text into the chosen character encoding.",
|
||||||
"<br><br>",
|
"<br><br>",
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class Fletcher16Checksum extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "Fletcher-16 Checksum";
|
this.name = "Fletcher-16 Checksum";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "The Fletcher checksum is an algorithm for computing a position-dependent checksum devised by John Gould Fletcher at Lawrence Livermore Labs in the late 1970s.<br><br>The objective of the Fletcher checksum was to provide error-detection properties approaching those of a cyclic redundancy check but with the lower computational effort associated with summation techniques.";
|
this.description = "The Fletcher checksum is an algorithm for computing a position-dependent checksum devised by John Gould Fletcher at Lawrence Livermore Labs in the late 1970s.<br><br>The objective of the Fletcher checksum was to provide error-detection properties approaching those of a cyclic redundancy check but with the lower computational effort associated with summation techniques.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Fletcher%27s_checksum#Fletcher-16";
|
this.infoURL = "https://wikipedia.org/wiki/Fletcher%27s_checksum#Fletcher-16";
|
||||||
this.inputType = "byteArray";
|
this.inputType = "byteArray";
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class Fletcher32Checksum extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "Fletcher-32 Checksum";
|
this.name = "Fletcher-32 Checksum";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "The Fletcher checksum is an algorithm for computing a position-dependent checksum devised by John Gould Fletcher at Lawrence Livermore Labs in the late 1970s.<br><br>The objective of the Fletcher checksum was to provide error-detection properties approaching those of a cyclic redundancy check but with the lower computational effort associated with summation techniques.";
|
this.description = "The Fletcher checksum is an algorithm for computing a position-dependent checksum devised by John Gould Fletcher at Lawrence Livermore Labs in the late 1970s.<br><br>The objective of the Fletcher checksum was to provide error-detection properties approaching those of a cyclic redundancy check but with the lower computational effort associated with summation techniques.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Fletcher%27s_checksum#Fletcher-32";
|
this.infoURL = "https://wikipedia.org/wiki/Fletcher%27s_checksum#Fletcher-32";
|
||||||
this.inputType = "byteArray";
|
this.inputType = "byteArray";
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class Fletcher64Checksum extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "Fletcher-64 Checksum";
|
this.name = "Fletcher-64 Checksum";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "The Fletcher checksum is an algorithm for computing a position-dependent checksum devised by John Gould Fletcher at Lawrence Livermore Labs in the late 1970s.<br><br>The objective of the Fletcher checksum was to provide error-detection properties approaching those of a cyclic redundancy check but with the lower computational effort associated with summation techniques.";
|
this.description = "The Fletcher checksum is an algorithm for computing a position-dependent checksum devised by John Gould Fletcher at Lawrence Livermore Labs in the late 1970s.<br><br>The objective of the Fletcher checksum was to provide error-detection properties approaching those of a cyclic redundancy check but with the lower computational effort associated with summation techniques.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Fletcher%27s_checksum#Fletcher-64";
|
this.infoURL = "https://wikipedia.org/wiki/Fletcher%27s_checksum#Fletcher-64";
|
||||||
this.inputType = "byteArray";
|
this.inputType = "byteArray";
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class Fletcher8Checksum extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "Fletcher-8 Checksum";
|
this.name = "Fletcher-8 Checksum";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "The Fletcher checksum is an algorithm for computing a position-dependent checksum devised by John Gould Fletcher at Lawrence Livermore Labs in the late 1970s.<br><br>The objective of the Fletcher checksum was to provide error-detection properties approaching those of a cyclic redundancy check but with the lower computational effort associated with summation techniques.";
|
this.description = "The Fletcher checksum is an algorithm for computing a position-dependent checksum devised by John Gould Fletcher at Lawrence Livermore Labs in the late 1970s.<br><br>The objective of the Fletcher checksum was to provide error-detection properties approaching those of a cyclic redundancy check but with the lower computational effort associated with summation techniques.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Fletcher%27s_checksum";
|
this.infoURL = "https://wikipedia.org/wiki/Fletcher%27s_checksum";
|
||||||
this.inputType = "byteArray";
|
this.inputType = "byteArray";
|
||||||
|
|||||||
39
src/core/operations/FromCaseInsensitiveRegex.mjs
Normal file
39
src/core/operations/FromCaseInsensitiveRegex.mjs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* @author masq [github.cyberchef@masq.cc]
|
||||||
|
* @copyright Crown Copyright 2018
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* From Case Insensitive Regex operation
|
||||||
|
*/
|
||||||
|
class FromCaseInsensitiveRegex extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* FromCaseInsensitiveRegex constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "From Case Insensitive Regex";
|
||||||
|
this.module = "Default";
|
||||||
|
this.description = "Converts a case-insensitive regex string to a case sensitive regex string (no guarantee on it being the proper original casing) in case the i flag wasn't available at the time but now is, or you need it to be case-sensitive again.<br><br>e.g. <code>[mM][oO][zZ][iI][lL][lL][aA]/[0-9].[0-9] .*</code> becomes <code>Mozilla/[0-9].[0-9] .*</code>";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/Regular_expression";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
return input.replace(/\[[a-z]{2}\]/ig, m => m[1].toUpperCase() === m[2].toUpperCase() ? m[1] : m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default FromCaseInsensitiveRegex;
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
/**
|
|
||||||
* @author gchq77703 []
|
|
||||||
* @copyright Crown Copyright 2018
|
|
||||||
* @license Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Operation from "../Operation";
|
|
||||||
import geohash from "ngeohash";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* From Geohash operation
|
|
||||||
*/
|
|
||||||
class FromGeohash extends Operation {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* FromGeohash constructor
|
|
||||||
*/
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.name = "From Geohash";
|
|
||||||
this.module = "Hashing";
|
|
||||||
this.description = "Converts Geohash strings into Lat/Long coordinates. For example, <code>ww8p1r4t8</code> becomes <code>37.8324,112.5584</code>.";
|
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Geohash";
|
|
||||||
this.inputType = "string";
|
|
||||||
this.outputType = "string";
|
|
||||||
this.args = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} input
|
|
||||||
* @param {Object[]} args
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
run(input, args) {
|
|
||||||
return input.split("\n").map(line => {
|
|
||||||
const coords = geohash.decode(line);
|
|
||||||
return [coords.latitude, coords.longitude].join(",");
|
|
||||||
}).join("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export default FromGeohash;
|
|
||||||
@@ -41,7 +41,7 @@ class GenerateAllHashes extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "Generate all hashes";
|
this.name = "Generate all hashes";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "Generates all available hashes and checksums for the input.";
|
this.description = "Generates all available hashes and checksums for the input.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Comparison_of_cryptographic_hash_functions";
|
this.infoURL = "https://wikipedia.org/wiki/Comparison_of_cryptographic_hash_functions";
|
||||||
this.inputType = "ArrayBuffer";
|
this.inputType = "ArrayBuffer";
|
||||||
|
|||||||
70
src/core/operations/GenerateLoremIpsum.mjs
Normal file
70
src/core/operations/GenerateLoremIpsum.mjs
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/**
|
||||||
|
* @author klaxon [klaxon@veyr.com]
|
||||||
|
* @copyright Crown Copyright 2018
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation";
|
||||||
|
import OperationError from "../errors/OperationError";
|
||||||
|
import { GenerateParagraphs, GenerateSentences, GenerateWords, GenerateBytes } from "../lib/LoremIpsum";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate Lorem Ipsum operation
|
||||||
|
*/
|
||||||
|
class GenerateLoremIpsum extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GenerateLoremIpsum constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Generate Lorem Ipsum";
|
||||||
|
this.module = "Default";
|
||||||
|
this.description = "Generate varying length lorem ipsum placeholder text.";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/Lorem_ipsum";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
"name": "Length",
|
||||||
|
"type": "number",
|
||||||
|
"value": "3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Length in",
|
||||||
|
"type": "option",
|
||||||
|
"value": ["Paragraphs", "Sentences", "Words", "Bytes"]
|
||||||
|
}
|
||||||
|
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const [length, lengthType] = args;
|
||||||
|
if (length < 1){
|
||||||
|
throw new OperationError("Length must be greater than 0");
|
||||||
|
}
|
||||||
|
switch (lengthType) {
|
||||||
|
case "Paragraphs":
|
||||||
|
return GenerateParagraphs(length);
|
||||||
|
case "Sentences":
|
||||||
|
return GenerateSentences(length);
|
||||||
|
case "Words":
|
||||||
|
return GenerateWords(length);
|
||||||
|
case "Bytes":
|
||||||
|
return GenerateBytes(length);
|
||||||
|
default:
|
||||||
|
throw new OperationError("Invalid length type");
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GenerateLoremIpsum;
|
||||||
119
src/core/operations/GenerateQRCode.mjs
Normal file
119
src/core/operations/GenerateQRCode.mjs
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
/**
|
||||||
|
* @author j433866 [j433866@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2018
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation";
|
||||||
|
import OperationError from "../errors/OperationError";
|
||||||
|
import qr from "qr-image";
|
||||||
|
import { toBase64 } from "../lib/Base64";
|
||||||
|
import Magic from "../lib/Magic";
|
||||||
|
import Utils from "../Utils";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate QR Code operation
|
||||||
|
*/
|
||||||
|
class GenerateQRCode extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GenerateQRCode constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Generate QR Code";
|
||||||
|
this.module = "Image";
|
||||||
|
this.description = "Generates a Quick Response (QR) code from the input text.<br><br>A QR code is a type of matrix barcode (or two-dimensional barcode) first designed in 1994 for the automotive industry in Japan. A barcode is a machine-readable optical label that contains information about the item to which it is attached.";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/QR_code";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "byteArray";
|
||||||
|
this.presentType = "html";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
"name": "Image Format",
|
||||||
|
"type": "option",
|
||||||
|
"value": ["PNG", "SVG", "EPS", "PDF"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Module size (px)",
|
||||||
|
"type": "number",
|
||||||
|
"value": 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Margin (num modules)",
|
||||||
|
"type": "number",
|
||||||
|
"value": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Error correction",
|
||||||
|
"type": "option",
|
||||||
|
"value": ["Low", "Medium", "Quartile", "High"],
|
||||||
|
"defaultIndex": 1
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {byteArray}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const [format, size, margin, errorCorrection] = args;
|
||||||
|
|
||||||
|
// Create new QR image from the input data, and convert it to a buffer
|
||||||
|
const qrImage = qr.imageSync(input, {
|
||||||
|
type: format,
|
||||||
|
size: size,
|
||||||
|
margin: margin,
|
||||||
|
"ec_level": errorCorrection.charAt(0).toUpperCase()
|
||||||
|
});
|
||||||
|
|
||||||
|
if (qrImage == null) {
|
||||||
|
throw new OperationError("Error generating QR code.");
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (format) {
|
||||||
|
case "SVG":
|
||||||
|
case "EPS":
|
||||||
|
case "PDF":
|
||||||
|
return [...Buffer.from(qrImage)];
|
||||||
|
case "PNG":
|
||||||
|
// Return the QR image buffer as a byte array
|
||||||
|
return [...qrImage];
|
||||||
|
default:
|
||||||
|
throw new OperationError("Unsupported QR code format.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays the QR image using HTML for web apps
|
||||||
|
*
|
||||||
|
* @param {byteArray} data
|
||||||
|
* @returns {html}
|
||||||
|
*/
|
||||||
|
present(data, args) {
|
||||||
|
if (!data.length) return "";
|
||||||
|
|
||||||
|
const [format] = args;
|
||||||
|
|
||||||
|
if (format === "PNG") {
|
||||||
|
let dataURI = "data:";
|
||||||
|
const type = Magic.magicFileType(data);
|
||||||
|
if (type && type.mime.indexOf("image") === 0){
|
||||||
|
dataURI += type.mime + ";";
|
||||||
|
} else {
|
||||||
|
throw new OperationError("Invalid PNG file generated by QR image");
|
||||||
|
}
|
||||||
|
dataURI += "base64," + toBase64(data);
|
||||||
|
|
||||||
|
return `<img src="${dataURI}">`;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Utils.byteArrayToChars(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GenerateQRCode;
|
||||||
@@ -22,7 +22,7 @@ class GroupIPAddresses extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "Group IP addresses";
|
this.name = "Group IP addresses";
|
||||||
this.module = "JSBN";
|
this.module = "Default";
|
||||||
this.description = "Groups a list of IP addresses into subnets. Supports both IPv4 and IPv6 addresses.";
|
this.description = "Groups a list of IP addresses into subnets. Supports both IPv4 and IPv6 addresses.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Subnetwork";
|
this.infoURL = "https://wikipedia.org/wiki/Subnetwork";
|
||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class HAS160 extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "HAS-160";
|
this.name = "HAS-160";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "HAS-160 is a cryptographic hash function designed for use with the Korean KCDSA digital signature algorithm. It is derived from SHA-1, with assorted changes intended to increase its security. It produces a 160-bit output.<br><br>HAS-160 is used in the same way as SHA-1. First it divides input in blocks of 512 bits each and pads the final block. A digest function updates the intermediate hash value by processing the input blocks in turn.<br><br>The message digest algorithm consists of 80 rounds.";
|
this.description = "HAS-160 is a cryptographic hash function designed for use with the Korean KCDSA digital signature algorithm. It is derived from SHA-1, with assorted changes intended to increase its security. It produces a 160-bit output.<br><br>HAS-160 is used in the same way as SHA-1. First it divides input in blocks of 512 bits each and pads the final block. A digest function updates the intermediate hash value by processing the input blocks in turn.<br><br>The message digest algorithm consists of 80 rounds.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/HAS-160";
|
this.infoURL = "https://wikipedia.org/wiki/HAS-160";
|
||||||
this.inputType = "ArrayBuffer";
|
this.inputType = "ArrayBuffer";
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class HMAC extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "HMAC";
|
this.name = "HMAC";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "Keyed-Hash Message Authentication Codes (HMAC) are a mechanism for message authentication using cryptographic hash functions.";
|
this.description = "Keyed-Hash Message Authentication Codes (HMAC) are a mechanism for message authentication using cryptographic hash functions.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/HMAC";
|
this.infoURL = "https://wikipedia.org/wiki/HMAC";
|
||||||
this.inputType = "ArrayBuffer";
|
this.inputType = "ArrayBuffer";
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class Keccak extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "Keccak";
|
this.name = "Keccak";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "The Keccak hash algorithm was designed by Guido Bertoni, Joan Daemen, Micha\xebl Peeters, and Gilles Van Assche, building upon RadioGat\xfan. It was selected as the winner of the SHA-3 design competition.<br><br>This version of the algorithm is Keccak[c=2d] and differs from the SHA-3 specification.";
|
this.description = "The Keccak hash algorithm was designed by Guido Bertoni, Joan Daemen, Micha\xebl Peeters, and Gilles Van Assche, building upon RadioGat\xfan. It was selected as the winner of the SHA-3 design competition.<br><br>This version of the algorithm is Keccak[c=2d] and differs from the SHA-3 specification.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/SHA-3";
|
this.infoURL = "https://wikipedia.org/wiki/SHA-3";
|
||||||
this.inputType = "ArrayBuffer";
|
this.inputType = "ArrayBuffer";
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class MD2 extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "MD2";
|
this.name = "MD2";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "The MD2 (Message-Digest 2) algorithm is a cryptographic hash function developed by Ronald Rivest in 1989. The algorithm is optimized for 8-bit computers.<br><br>Although MD2 is no longer considered secure, even as of 2014, it remains in use in public key infrastructures as part of certificates generated with MD2 and RSA.";
|
this.description = "The MD2 (Message-Digest 2) algorithm is a cryptographic hash function developed by Ronald Rivest in 1989. The algorithm is optimized for 8-bit computers.<br><br>Although MD2 is no longer considered secure, even as of 2014, it remains in use in public key infrastructures as part of certificates generated with MD2 and RSA.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/MD2_(cryptography)";
|
this.infoURL = "https://wikipedia.org/wiki/MD2_(cryptography)";
|
||||||
this.inputType = "ArrayBuffer";
|
this.inputType = "ArrayBuffer";
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class MD4 extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "MD4";
|
this.name = "MD4";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "The MD4 (Message-Digest 4) algorithm is a cryptographic hash function developed by Ronald Rivest in 1990. The digest length is 128 bits. The algorithm has influenced later designs, such as the MD5, SHA-1 and RIPEMD algorithms.<br><br>The security of MD4 has been severely compromised.";
|
this.description = "The MD4 (Message-Digest 4) algorithm is a cryptographic hash function developed by Ronald Rivest in 1990. The digest length is 128 bits. The algorithm has influenced later designs, such as the MD5, SHA-1 and RIPEMD algorithms.<br><br>The security of MD4 has been severely compromised.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/MD4";
|
this.infoURL = "https://wikipedia.org/wiki/MD4";
|
||||||
this.inputType = "ArrayBuffer";
|
this.inputType = "ArrayBuffer";
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class MD5 extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "MD5";
|
this.name = "MD5";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "MD5 (Message-Digest 5) is a widely used hash function. It has been used in a variety of security applications and is also commonly used to check the integrity of files.<br><br>However, MD5 is not collision resistant and it isn't suitable for applications like SSL/TLS certificates or digital signatures that rely on this property.";
|
this.description = "MD5 (Message-Digest 5) is a widely used hash function. It has been used in a variety of security applications and is also commonly used to check the integrity of files.<br><br>However, MD5 is not collision resistant and it isn't suitable for applications like SSL/TLS certificates or digital signatures that rely on this property.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/MD5";
|
this.infoURL = "https://wikipedia.org/wiki/MD5";
|
||||||
this.inputType = "ArrayBuffer";
|
this.inputType = "ArrayBuffer";
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class MD6 extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "MD6";
|
this.name = "MD6";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "The MD6 (Message-Digest 6) algorithm is a cryptographic hash function. It uses a Merkle tree-like structure to allow for immense parallel computation of hashes for very long inputs.";
|
this.description = "The MD6 (Message-Digest 6) algorithm is a cryptographic hash function. It uses a Merkle tree-like structure to allow for immense parallel computation of hashes for very long inputs.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/MD6";
|
this.infoURL = "https://wikipedia.org/wiki/MD6";
|
||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ class Mean extends Operation {
|
|||||||
*/
|
*/
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
const val = mean(createNumArray(input, args[0]));
|
const val = mean(createNumArray(input, args[0]));
|
||||||
return val instanceof BigNumber ? val : new BigNumber(NaN);
|
return BigNumber.isBigNumber(val) ? val : new BigNumber(NaN);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ class Median extends Operation {
|
|||||||
*/
|
*/
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
const val = median(createNumArray(input, args[0]));
|
const val = median(createNumArray(input, args[0]));
|
||||||
return val instanceof BigNumber ? val : new BigNumber(NaN);
|
return BigNumber.isBigNumber(val) ? val : new BigNumber(NaN);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class Multiply extends Operation {
|
|||||||
*/
|
*/
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
const val = multi(createNumArray(input, args[0]));
|
const val = multi(createNumArray(input, args[0]));
|
||||||
return val instanceof BigNumber ? val : new BigNumber(NaN);
|
return BigNumber.isBigNumber(val) ? val : new BigNumber(NaN);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class ParseIPRange extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "Parse IP range";
|
this.name = "Parse IP range";
|
||||||
this.module = "JSBN";
|
this.module = "Default";
|
||||||
this.description = "Given a CIDR range (e.g. <code>10.0.0.0/24</code>), hyphenated range (e.g. <code>10.0.0.0 - 10.0.1.0</code>), or a list of IPs and/or CIDR ranges (separated by a new line), this operation provides network information and enumerates all IP addresses in the range.<br><br>IPv6 is supported but will not be enumerated.";
|
this.description = "Given a CIDR range (e.g. <code>10.0.0.0/24</code>), hyphenated range (e.g. <code>10.0.0.0 - 10.0.1.0</code>), or a list of IPs and/or CIDR ranges (separated by a new line), this operation provides network information and enumerates all IP addresses in the range.<br><br>IPv6 is supported but will not be enumerated.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Subnetwork";
|
this.infoURL = "https://wikipedia.org/wiki/Subnetwork";
|
||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class ParseIPv4Header extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "Parse IPv4 header";
|
this.name = "Parse IPv4 header";
|
||||||
this.module = "JSBN";
|
this.module = "Default";
|
||||||
this.description = "Given an IPv4 header, this operations parses and displays each field in an easily readable format.";
|
this.description = "Given an IPv4 header, this operations parses and displays each field in an easily readable format.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/IPv4#Header";
|
this.infoURL = "https://wikipedia.org/wiki/IPv4#Header";
|
||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import Operation from "../Operation";
|
|||||||
import Utils from "../Utils";
|
import Utils from "../Utils";
|
||||||
import OperationError from "../errors/OperationError";
|
import OperationError from "../errors/OperationError";
|
||||||
import {strToIpv6, ipv6ToStr, ipv4ToStr, IPV6_REGEX} from "../lib/IP";
|
import {strToIpv6, ipv6ToStr, ipv4ToStr, IPV6_REGEX} from "../lib/IP";
|
||||||
import BigInteger from "jsbn";
|
import BigNumber from "bignumber.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse IPv6 address operation
|
* Parse IPv6 address operation
|
||||||
@@ -22,7 +22,7 @@ class ParseIPv6Address extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "Parse IPv6 address";
|
this.name = "Parse IPv6 address";
|
||||||
this.module = "JSBN";
|
this.module = "Default";
|
||||||
this.description = "Displays the longhand and shorthand versions of a valid IPv6 address.<br><br>Recognises all reserved ranges and parses encapsulated or tunnelled addresses including Teredo and 6to4.";
|
this.description = "Displays the longhand and shorthand versions of a valid IPv6 address.<br><br>Recognises all reserved ranges and parses encapsulated or tunnelled addresses including Teredo and 6to4.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/IPv6_address";
|
this.infoURL = "https://wikipedia.org/wiki/IPv6_address";
|
||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
@@ -147,7 +147,7 @@ class ParseIPv6Address extends Operation {
|
|||||||
const v4Addr = ipv4ToStr((ipv6[1] << 16) + ipv6[2]),
|
const v4Addr = ipv4ToStr((ipv6[1] << 16) + ipv6[2]),
|
||||||
slaId = ipv6[3],
|
slaId = ipv6[3],
|
||||||
interfaceIdStr = ipv6[4].toString(16) + ipv6[5].toString(16) + ipv6[6].toString(16) + ipv6[7].toString(16),
|
interfaceIdStr = ipv6[4].toString(16) + ipv6[5].toString(16) + ipv6[6].toString(16) + ipv6[7].toString(16),
|
||||||
interfaceId = new BigInteger(interfaceIdStr, 16);
|
interfaceId = new BigNumber(interfaceIdStr, 16);
|
||||||
|
|
||||||
output += "\n\nEncapsulated IPv4 address: " + v4Addr +
|
output += "\n\nEncapsulated IPv4 address: " + v4Addr +
|
||||||
"\nSLA ID: " + slaId +
|
"\nSLA ID: " + slaId +
|
||||||
|
|||||||
107
src/core/operations/ParseQRCode.mjs
Normal file
107
src/core/operations/ParseQRCode.mjs
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
/**
|
||||||
|
* @author j433866 [j433866@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2018
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation";
|
||||||
|
import OperationError from "../errors/OperationError";
|
||||||
|
import Magic from "../lib/Magic";
|
||||||
|
import jsqr from "jsqr";
|
||||||
|
import jimp from "jimp";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse QR Code operation
|
||||||
|
*/
|
||||||
|
class ParseQRCode extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ParseQRCode constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Parse QR Code";
|
||||||
|
this.module = "Image";
|
||||||
|
this.description = "Reads an image file and attempts to detect and read a Quick Response (QR) code from the image.<br><br><u>Normalise Image</u><br>Attempts to normalise the image before parsing it to improve detection of a QR code.";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/QR_code";
|
||||||
|
this.inputType = "byteArray";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
"name": "Normalise image",
|
||||||
|
"type": "boolean",
|
||||||
|
"value": false
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {byteArray} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
async run(input, args) {
|
||||||
|
const type = Magic.magicFileType(input);
|
||||||
|
const [normalise] = args;
|
||||||
|
|
||||||
|
// Make sure that the input is an image
|
||||||
|
if (type && type.mime.indexOf("image") === 0) {
|
||||||
|
let image = input;
|
||||||
|
|
||||||
|
if (normalise) {
|
||||||
|
// Process the image to be easier to read by jsqr
|
||||||
|
// Disables the alpha channel
|
||||||
|
// Sets the image default background to white
|
||||||
|
// Normalises the image colours
|
||||||
|
// Makes the image greyscale
|
||||||
|
// Converts image to a JPEG
|
||||||
|
image = await new Promise((resolve, reject) => {
|
||||||
|
jimp.read(Buffer.from(input))
|
||||||
|
.then(image => {
|
||||||
|
image
|
||||||
|
.rgba(false)
|
||||||
|
.background(0xFFFFFFFF)
|
||||||
|
.normalize()
|
||||||
|
.greyscale()
|
||||||
|
.getBuffer(jimp.MIME_JPEG, (error, result) => {
|
||||||
|
resolve(result);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
reject(new OperationError("Error reading the image file."));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (image instanceof OperationError) {
|
||||||
|
throw image;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
jimp.read(Buffer.from(image))
|
||||||
|
.then(image => {
|
||||||
|
if (image.bitmap != null) {
|
||||||
|
const qrData = jsqr(image.bitmap.data, image.getWidth(), image.getHeight());
|
||||||
|
if (qrData != null) {
|
||||||
|
resolve(qrData.data);
|
||||||
|
} else {
|
||||||
|
reject(new OperationError("Couldn't read a QR code from the image."));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
reject(new OperationError("Error reading the image file."));
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
reject(new OperationError("Error reading the image file."));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
throw new OperationError("Invalid file type.");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ParseQRCode;
|
||||||
@@ -181,8 +181,8 @@ class ParseX509Certificate extends Operation {
|
|||||||
Serial number: ${new r.BigInteger(sn, 16).toString()} (0x${sn})
|
Serial number: ${new r.BigInteger(sn, 16).toString()} (0x${sn})
|
||||||
Algorithm ID: ${cert.getSignatureAlgorithmField()}
|
Algorithm ID: ${cert.getSignatureAlgorithmField()}
|
||||||
Validity
|
Validity
|
||||||
Not Before: ${nbDate} (dd-mm-yy hh:mm:ss) (${cert.getNotBefore()})
|
Not Before: ${nbDate} (dd-mm-yyyy hh:mm:ss) (${cert.getNotBefore()})
|
||||||
Not After: ${naDate} (dd-mm-yy hh:mm:ss) (${cert.getNotAfter()})
|
Not After: ${naDate} (dd-mm-yyyy hh:mm:ss) (${cert.getNotAfter()})
|
||||||
Issuer
|
Issuer
|
||||||
${issuerStr}
|
${issuerStr}
|
||||||
Subject
|
Subject
|
||||||
@@ -206,12 +206,15 @@ ${extensions}`;
|
|||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
function formatDate (dateStr) {
|
function formatDate (dateStr) {
|
||||||
return dateStr[4] + dateStr[5] + "/" +
|
if (dateStr.length === 13) { // UTC Time
|
||||||
dateStr[2] + dateStr[3] + "/" +
|
dateStr = (dateStr[0] < "5" ? "20" : "19") + dateStr;
|
||||||
dateStr[0] + dateStr[1] + " " +
|
}
|
||||||
dateStr[6] + dateStr[7] + ":" +
|
return dateStr[6] + dateStr[7] + "/" +
|
||||||
|
dateStr[4] + dateStr[5] + "/" +
|
||||||
|
dateStr[0] + dateStr[1] + dateStr[2] + dateStr[3] + " " +
|
||||||
dateStr[8] + dateStr[9] + ":" +
|
dateStr[8] + dateStr[9] + ":" +
|
||||||
dateStr[10] + dateStr[11];
|
dateStr[10] + dateStr[11] + ":" +
|
||||||
|
dateStr[12] + dateStr[13];
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ParseX509Certificate;
|
export default ParseX509Certificate;
|
||||||
|
|||||||
102
src/core/operations/PlayMedia.mjs
Normal file
102
src/core/operations/PlayMedia.mjs
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
/**
|
||||||
|
* @author anthony-arnold [anthony.arnold@uqconnect.edu.au]
|
||||||
|
* @copyright Crown Copyright 2018
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { fromBase64, toBase64 } from "../lib/Base64";
|
||||||
|
import { fromHex } from "../lib/Hex";
|
||||||
|
import Operation from "../Operation";
|
||||||
|
import OperationError from "../errors/OperationError";
|
||||||
|
import Utils from "../Utils";
|
||||||
|
import Magic from "../lib/Magic";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PlayMedia operation
|
||||||
|
*/
|
||||||
|
class PlayMedia extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PlayMedia constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Play Media";
|
||||||
|
this.module = "Default";
|
||||||
|
this.description = "Plays the input as audio or video depending on the type.<br><br>Tags: sound, movie, mp3, mp4, mov, webm, wav, ogg";
|
||||||
|
this.infoURL = "";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "byteArray";
|
||||||
|
this.presentType = "html";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
"name": "Input format",
|
||||||
|
"type": "option",
|
||||||
|
"value": ["Raw", "Base64", "Hex"]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {byteArray} The multimedia data as bytes.
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const [inputFormat] = args;
|
||||||
|
|
||||||
|
if (!input.length) return [];
|
||||||
|
|
||||||
|
// Convert input to raw bytes
|
||||||
|
switch (inputFormat) {
|
||||||
|
case "Hex":
|
||||||
|
input = fromHex(input);
|
||||||
|
break;
|
||||||
|
case "Base64":
|
||||||
|
// Don't trust the Base64 entered by the user.
|
||||||
|
// Unwrap it first, then re-encode later.
|
||||||
|
input = fromBase64(input, undefined, "byteArray");
|
||||||
|
break;
|
||||||
|
case "Raw":
|
||||||
|
default:
|
||||||
|
input = Utils.strToByteArray(input);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Determine file type
|
||||||
|
const type = Magic.magicFileType(input);
|
||||||
|
if (!(type && /^audio|video/.test(type.mime))) {
|
||||||
|
throw new OperationError("Invalid or unrecognised file type");
|
||||||
|
}
|
||||||
|
|
||||||
|
return input;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays an audio or video element that may be able to play the media
|
||||||
|
* file.
|
||||||
|
*
|
||||||
|
* @param data {byteArray} Data containing an audio or video file.
|
||||||
|
* @returns {string} Markup to display a media player.
|
||||||
|
*/
|
||||||
|
async present(data) {
|
||||||
|
if (!data.length) return "";
|
||||||
|
|
||||||
|
const type = Magic.magicFileType(data);
|
||||||
|
const matches = /^audio|video/.exec(type.mime);
|
||||||
|
if (!matches) {
|
||||||
|
throw new OperationError("Invalid file type");
|
||||||
|
}
|
||||||
|
const dataURI = `data:${type.mime};base64,${toBase64(data)}`;
|
||||||
|
const element = matches[0];
|
||||||
|
|
||||||
|
let html = `<${element} src='${dataURI}' type='${type.mime}' controls>`;
|
||||||
|
html += "<p>Unsupported media type.</p>";
|
||||||
|
html += `</${element}>`;
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PlayMedia;
|
||||||
@@ -19,7 +19,7 @@ class RIPEMD extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "RIPEMD";
|
this.name = "RIPEMD";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "RIPEMD (RACE Integrity Primitives Evaluation Message Digest) is a family of cryptographic hash functions developed in Leuven, Belgium, by Hans Dobbertin, Antoon Bosselaers and Bart Preneel at the COSIC research group at the Katholieke Universiteit Leuven, and first published in 1996.<br><br>RIPEMD was based upon the design principles used in MD4, and is similar in performance to the more popular SHA-1.<br><br>";
|
this.description = "RIPEMD (RACE Integrity Primitives Evaluation Message Digest) is a family of cryptographic hash functions developed in Leuven, Belgium, by Hans Dobbertin, Antoon Bosselaers and Bart Preneel at the COSIC research group at the Katholieke Universiteit Leuven, and first published in 1996.<br><br>RIPEMD was based upon the design principles used in MD4, and is similar in performance to the more popular SHA-1.<br><br>";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/RIPEMD";
|
this.infoURL = "https://wikipedia.org/wiki/RIPEMD";
|
||||||
this.inputType = "ArrayBuffer";
|
this.inputType = "ArrayBuffer";
|
||||||
|
|||||||
@@ -228,40 +228,29 @@ function regexList (input, regex, displayTotal, matches, captureGroups) {
|
|||||||
function regexHighlight (input, regex, displayTotal) {
|
function regexHighlight (input, regex, displayTotal) {
|
||||||
let output = "",
|
let output = "",
|
||||||
title = "",
|
title = "",
|
||||||
m,
|
|
||||||
hl = 1,
|
hl = 1,
|
||||||
i = 0,
|
|
||||||
total = 0;
|
total = 0;
|
||||||
|
|
||||||
while ((m = regex.exec(input))) {
|
output = input.replace(regex, (match, ...args) => {
|
||||||
// Moves pointer when an empty string is matched (prevents infinite loop)
|
args.pop(); // Throw away full string
|
||||||
if (m.index === regex.lastIndex) {
|
const offset = args.pop(),
|
||||||
regex.lastIndex++;
|
groups = args;
|
||||||
}
|
|
||||||
|
|
||||||
// Add up to match
|
title = `Offset: ${offset}\n`;
|
||||||
output += Utils.escapeHtml(input.slice(i, m.index));
|
if (groups.length) {
|
||||||
|
|
||||||
title = `Offset: ${m.index}\n`;
|
|
||||||
if (m.length > 1) {
|
|
||||||
title += "Groups:\n";
|
title += "Groups:\n";
|
||||||
for (let n = 1; n < m.length; ++n) {
|
for (let i = 0; i < groups.length; i++) {
|
||||||
title += `\t${n}: ${m[n]}\n`;
|
title += `\t${i+1}: ${Utils.escapeHtml(groups[i])}\n`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add match with highlighting
|
|
||||||
output += "<span class='hl"+hl+"' title='"+title+"'>" + Utils.escapeHtml(m[0]) + "</span>";
|
|
||||||
|
|
||||||
// Switch highlight
|
// Switch highlight
|
||||||
hl = hl === 1 ? 2 : 1;
|
hl = hl === 1 ? 2 : 1;
|
||||||
|
|
||||||
i = regex.lastIndex;
|
|
||||||
total++;
|
total++;
|
||||||
}
|
|
||||||
|
|
||||||
// Add all after final match
|
return `<span class='hl${hl}' title='${title}'>${Utils.escapeHtml(match)}</span>`;
|
||||||
output += Utils.escapeHtml(input.slice(i, input.length));
|
});
|
||||||
|
|
||||||
if (displayTotal)
|
if (displayTotal)
|
||||||
output = "Total found: " + total + "\n\n" + output;
|
output = "Total found: " + total + "\n\n" + output;
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class SHA0 extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "SHA0";
|
this.name = "SHA0";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "SHA-0 is a retronym applied to the original version of the 160-bit hash function published in 1993 under the name 'SHA'. It was withdrawn shortly after publication due to an undisclosed 'significant flaw' and replaced by the slightly revised version SHA-1.";
|
this.description = "SHA-0 is a retronym applied to the original version of the 160-bit hash function published in 1993 under the name 'SHA'. It was withdrawn shortly after publication due to an undisclosed 'significant flaw' and replaced by the slightly revised version SHA-1.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/SHA-1#SHA-0";
|
this.infoURL = "https://wikipedia.org/wiki/SHA-1#SHA-0";
|
||||||
this.inputType = "ArrayBuffer";
|
this.inputType = "ArrayBuffer";
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class SHA1 extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "SHA1";
|
this.name = "SHA1";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "The SHA (Secure Hash Algorithm) hash functions were designed by the NSA. SHA-1 is the most established of the existing SHA hash functions and it is used in a variety of security applications and protocols.<br><br>However, SHA-1's collision resistance has been weakening as new attacks are discovered or improved.";
|
this.description = "The SHA (Secure Hash Algorithm) hash functions were designed by the NSA. SHA-1 is the most established of the existing SHA hash functions and it is used in a variety of security applications and protocols.<br><br>However, SHA-1's collision resistance has been weakening as new attacks are discovered or improved.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/SHA-1";
|
this.infoURL = "https://wikipedia.org/wiki/SHA-1";
|
||||||
this.inputType = "ArrayBuffer";
|
this.inputType = "ArrayBuffer";
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class SHA2 extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "SHA2";
|
this.name = "SHA2";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "The SHA-2 (Secure Hash Algorithm 2) hash functions were designed by the NSA. SHA-2 includes significant changes from its predecessor, SHA-1. The SHA-2 family consists of hash functions with digests (hash values) that are 224, 256, 384 or 512 bits: SHA224, SHA256, SHA384, SHA512.<br><br><ul><li>SHA-512 operates on 64-bit words.</li><li>SHA-256 operates on 32-bit words.</li><li>SHA-384 is largely identical to SHA-512 but is truncated to 384 bytes.</li><li>SHA-224 is largely identical to SHA-256 but is truncated to 224 bytes.</li><li>SHA-512/224 and SHA-512/256 are truncated versions of SHA-512, but the initial values are generated using the method described in Federal Information Processing Standards (FIPS) PUB 180-4.</li></ul>";
|
this.description = "The SHA-2 (Secure Hash Algorithm 2) hash functions were designed by the NSA. SHA-2 includes significant changes from its predecessor, SHA-1. The SHA-2 family consists of hash functions with digests (hash values) that are 224, 256, 384 or 512 bits: SHA224, SHA256, SHA384, SHA512.<br><br><ul><li>SHA-512 operates on 64-bit words.</li><li>SHA-256 operates on 32-bit words.</li><li>SHA-384 is largely identical to SHA-512 but is truncated to 384 bytes.</li><li>SHA-224 is largely identical to SHA-256 but is truncated to 224 bytes.</li><li>SHA-512/224 and SHA-512/256 are truncated versions of SHA-512, but the initial values are generated using the method described in Federal Information Processing Standards (FIPS) PUB 180-4.</li></ul>";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/SHA-2";
|
this.infoURL = "https://wikipedia.org/wiki/SHA-2";
|
||||||
this.inputType = "ArrayBuffer";
|
this.inputType = "ArrayBuffer";
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class SHA3 extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "SHA3";
|
this.name = "SHA3";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "The SHA-3 (Secure Hash Algorithm 3) hash functions were released by NIST on August 5, 2015. Although part of the same series of standards, SHA-3 is internally quite different from the MD5-like structure of SHA-1 and SHA-2.<br><br>SHA-3 is a subset of the broader cryptographic primitive family Keccak designed by Guido Bertoni, Joan Daemen, Micha\xebl Peeters, and Gilles Van Assche, building upon RadioGat\xfan.";
|
this.description = "The SHA-3 (Secure Hash Algorithm 3) hash functions were released by NIST on August 5, 2015. Although part of the same series of standards, SHA-3 is internally quite different from the MD5-like structure of SHA-1 and SHA-2.<br><br>SHA-3 is a subset of the broader cryptographic primitive family Keccak designed by Guido Bertoni, Joan Daemen, Micha\xebl Peeters, and Gilles Van Assche, building upon RadioGat\xfan.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/SHA-3";
|
this.infoURL = "https://wikipedia.org/wiki/SHA-3";
|
||||||
this.inputType = "ArrayBuffer";
|
this.inputType = "ArrayBuffer";
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class SSDEEP extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "SSDEEP";
|
this.name = "SSDEEP";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "SSDEEP is a program for computing context triggered piecewise hashes (CTPH). Also called fuzzy hashes, CTPH can match inputs that have homologies. Such inputs have sequences of identical bytes in the same order, although bytes in between these sequences may be different in both content and length.<br><br>SSDEEP hashes are now widely used for simple identification purposes (e.g. the 'Basic Properties' section in VirusTotal). Although 'better' fuzzy hashes are available, SSDEEP is still one of the primary choices because of its speed and being a de facto standard.<br><br>This operation is fundamentally the same as the CTPH operation, however their outputs differ in format.";
|
this.description = "SSDEEP is a program for computing context triggered piecewise hashes (CTPH). Also called fuzzy hashes, CTPH can match inputs that have homologies. Such inputs have sequences of identical bytes in the same order, although bytes in between these sequences may be different in both content and length.<br><br>SSDEEP hashes are now widely used for simple identification purposes (e.g. the 'Basic Properties' section in VirusTotal). Although 'better' fuzzy hashes are available, SSDEEP is still one of the primary choices because of its speed and being a de facto standard.<br><br>This operation is fundamentally the same as the CTPH operation, however their outputs differ in format.";
|
||||||
this.infoURL = "https://forensicswiki.org/wiki/Ssdeep";
|
this.infoURL = "https://forensicswiki.org/wiki/Ssdeep";
|
||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class Scrypt extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "Scrypt";
|
this.name = "Scrypt";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "scrypt is a password-based key derivation function (PBKDF) created by Colin Percival. The algorithm was specifically designed to make it costly to perform large-scale custom hardware attacks by requiring large amounts of memory. In 2016, the scrypt algorithm was published by IETF as RFC 7914.<br><br>Enter the password in the input to generate its hash.";
|
this.description = "scrypt is a password-based key derivation function (PBKDF) created by Colin Percival. The algorithm was specifically designed to make it costly to perform large-scale custom hardware attacks by requiring large amounts of memory. In 2016, the scrypt algorithm was published by IETF as RFC 7914.<br><br>Enter the password in the input to generate its hash.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Scrypt";
|
this.infoURL = "https://wikipedia.org/wiki/Scrypt";
|
||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class Shake extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "Shake";
|
this.name = "Shake";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "Shake is an Extendable Output Function (XOF) of the SHA-3 hash algorithm, part of the Keccak family, allowing for variable output length/size.";
|
this.description = "Shake is an Extendable Output Function (XOF) of the SHA-3 hash algorithm, part of the Keccak family, allowing for variable output length/size.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/SHA-3#Instances";
|
this.infoURL = "https://wikipedia.org/wiki/SHA-3#Instances";
|
||||||
this.inputType = "ArrayBuffer";
|
this.inputType = "ArrayBuffer";
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class Snefru extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "Snefru";
|
this.name = "Snefru";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "Snefru is a cryptographic hash function invented by Ralph Merkle in 1990 while working at Xerox PARC. The function supports 128-bit and 256-bit output. It was named after the Egyptian Pharaoh Sneferu, continuing the tradition of the Khufu and Khafre block ciphers.<br><br>The original design of Snefru was shown to be insecure by Eli Biham and Adi Shamir who were able to use differential cryptanalysis to find hash collisions. The design was then modified by increasing the number of iterations of the main pass of the algorithm from two to eight.";
|
this.description = "Snefru is a cryptographic hash function invented by Ralph Merkle in 1990 while working at Xerox PARC. The function supports 128-bit and 256-bit output. It was named after the Egyptian Pharaoh Sneferu, continuing the tradition of the Khufu and Khafre block ciphers.<br><br>The original design of Snefru was shown to be insecure by Eli Biham and Adi Shamir who were able to use differential cryptanalysis to find hash collisions. The design was then modified by increasing the number of iterations of the main pass of the algorithm from two to eight.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Snefru";
|
this.infoURL = "https://wikipedia.org/wiki/Snefru";
|
||||||
this.inputType = "ArrayBuffer";
|
this.inputType = "ArrayBuffer";
|
||||||
|
|||||||
@@ -26,12 +26,12 @@ class Split extends Operation {
|
|||||||
this.args = [
|
this.args = [
|
||||||
{
|
{
|
||||||
"name": "Split delimiter",
|
"name": "Split delimiter",
|
||||||
"type": "editableOption",
|
"type": "editableOptionShort",
|
||||||
"value": SPLIT_DELIM_OPTIONS
|
"value": SPLIT_DELIM_OPTIONS
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Join delimiter",
|
"name": "Join delimiter",
|
||||||
"type": "editableOption",
|
"type": "editableOptionShort",
|
||||||
"value": JOIN_DELIM_OPTIONS
|
"value": JOIN_DELIM_OPTIONS
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|||||||
105
src/core/operations/SplitColourChannels.mjs
Normal file
105
src/core/operations/SplitColourChannels.mjs
Normal file
@@ -0,0 +1,105 @@
|
|||||||
|
/**
|
||||||
|
* @author Matt C [matt@artemisbot.uk]
|
||||||
|
* @copyright Crown Copyright 2018
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation";
|
||||||
|
import OperationError from "../errors/OperationError";
|
||||||
|
import Utils from "../Utils";
|
||||||
|
import Magic from "../lib/Magic";
|
||||||
|
|
||||||
|
import jimp from "jimp";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Split Colour Channels operation
|
||||||
|
*/
|
||||||
|
class SplitColourChannels extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SplitColourChannels constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Split Colour Channels";
|
||||||
|
this.module = "Image";
|
||||||
|
this.description = "Splits the given image into its red, green and blue colour channels.";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/Channel_(digital_image)";
|
||||||
|
this.inputType = "byteArray";
|
||||||
|
this.outputType = "List<File>";
|
||||||
|
this.presentType = "html";
|
||||||
|
this.args = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {byteArray} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {List<File>}
|
||||||
|
*/
|
||||||
|
async run(input, args) {
|
||||||
|
const type = Magic.magicFileType(input);
|
||||||
|
// Make sure that the input is an image
|
||||||
|
if (type && type.mime.indexOf("image") === 0) {
|
||||||
|
const parsedImage = await jimp.read(Buffer.from(input));
|
||||||
|
|
||||||
|
const red = new Promise(async (resolve, reject) => {
|
||||||
|
try {
|
||||||
|
const split = parsedImage
|
||||||
|
.clone()
|
||||||
|
.color([
|
||||||
|
{apply: "blue", params: [-255]},
|
||||||
|
{apply: "green", params: [-255]}
|
||||||
|
])
|
||||||
|
.getBufferAsync(jimp.MIME_PNG);
|
||||||
|
resolve(new File([new Uint8Array((await split).values())], "red.png", {type: "image/png"}));
|
||||||
|
} catch (err) {
|
||||||
|
reject(new OperationError(`Could not split red channel: ${err}`));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const green = new Promise(async (resolve, reject) => {
|
||||||
|
try {
|
||||||
|
const split = parsedImage.clone()
|
||||||
|
.color([
|
||||||
|
{apply: "red", params: [-255]},
|
||||||
|
{apply: "blue", params: [-255]},
|
||||||
|
]).getBufferAsync(jimp.MIME_PNG);
|
||||||
|
resolve(new File([new Uint8Array((await split).values())], "green.png", {type: "image/png"}));
|
||||||
|
} catch (err) {
|
||||||
|
reject(new OperationError(`Could not split green channel: ${err}`));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const blue = new Promise(async (resolve, reject) => {
|
||||||
|
try {
|
||||||
|
const split = parsedImage
|
||||||
|
.color([
|
||||||
|
{apply: "red", params: [-255]},
|
||||||
|
{apply: "green", params: [-255]},
|
||||||
|
]).getBufferAsync(jimp.MIME_PNG);
|
||||||
|
resolve(new File([new Uint8Array((await split).values())], "blue.png", {type: "image/png"}));
|
||||||
|
} catch (err) {
|
||||||
|
reject(new OperationError(`Could not split blue channel: ${err}`));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return await Promise.all([red, green, blue]);
|
||||||
|
} else {
|
||||||
|
throw new OperationError("Invalid file type.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays the files in HTML for web apps.
|
||||||
|
*
|
||||||
|
* @param {File[]} files
|
||||||
|
* @returns {html}
|
||||||
|
*/
|
||||||
|
async present(files) {
|
||||||
|
return await Utils.displayFilesAsHTML(files);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SplitColourChannels;
|
||||||
@@ -44,7 +44,7 @@ class StandardDeviation extends Operation {
|
|||||||
*/
|
*/
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
const val = stdDev(createNumArray(input, args[0]));
|
const val = stdDev(createNumArray(input, args[0]));
|
||||||
return val instanceof BigNumber ? val : new BigNumber(NaN);
|
return BigNumber.isBigNumber(val) ? val : new BigNumber(NaN);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
153
src/core/operations/Subsection.mjs
Normal file
153
src/core/operations/Subsection.mjs
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
/**
|
||||||
|
* @author j433866 [j433866@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2019
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import XRegExp from "xregexp";
|
||||||
|
import Operation from "../Operation";
|
||||||
|
import Recipe from "../Recipe";
|
||||||
|
import Dish from "../Dish";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subsection operation
|
||||||
|
*/
|
||||||
|
class Subsection extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subsection constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Subsection";
|
||||||
|
this.flowControl = true;
|
||||||
|
this.module = "Regex";
|
||||||
|
this.description = "Select a part of the input data using a regular expression (regex), and run all subsequent operations on each match separately.<br><br>You can use up to one capture group, where the recipe will only be run on the data in the capture group. If there's more than one capture group, only the first one will be operated on.";
|
||||||
|
this.infoURL = "";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
"name": "Section (regex)",
|
||||||
|
"type": "string",
|
||||||
|
"value": ""
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Case sensitive matching",
|
||||||
|
"type": "boolean",
|
||||||
|
"value": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Global matching",
|
||||||
|
"type": "boolean",
|
||||||
|
"value": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Ignore errors",
|
||||||
|
"type": "boolean",
|
||||||
|
"value": false
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Object} state - The current state of the recipe.
|
||||||
|
* @param {number} state.progress - The current position in the recipe.
|
||||||
|
* @param {Dish} state.dish - The Dish being operated on
|
||||||
|
* @param {Operation[]} state.opList - The list of operations in the recipe
|
||||||
|
* @returns {Object} - The updated state of the recipe
|
||||||
|
*/
|
||||||
|
async run(state) {
|
||||||
|
const opList = state.opList,
|
||||||
|
inputType = opList[state.progress].inputType,
|
||||||
|
outputType = opList[state.progress].outputType,
|
||||||
|
input = await state.dish.get(inputType),
|
||||||
|
ings = opList[state.progress].ingValues,
|
||||||
|
[section, caseSensitive, global, ignoreErrors] = ings,
|
||||||
|
subOpList = [];
|
||||||
|
|
||||||
|
if (input && section !== "") {
|
||||||
|
// Create subOpList for each tranche to operate on
|
||||||
|
// all remaining operations unless we encounter a Merge
|
||||||
|
for (let i = state.progress + 1; i < opList.length; i++) {
|
||||||
|
if (opList[i].name === "Merge" && !opList[i].disabled) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
subOpList.push(opList[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let flags = "",
|
||||||
|
inOffset = 0,
|
||||||
|
output = "",
|
||||||
|
m,
|
||||||
|
progress = 0;
|
||||||
|
|
||||||
|
if (!caseSensitive) flags += "i";
|
||||||
|
if (global) flags += "g";
|
||||||
|
|
||||||
|
const regex = new XRegExp(section, flags),
|
||||||
|
recipe = new Recipe();
|
||||||
|
|
||||||
|
recipe.addOperations(subOpList);
|
||||||
|
state.forkOffset += state.progress + 1;
|
||||||
|
|
||||||
|
// Take a deep(ish) copy of the ingredient values
|
||||||
|
const ingValues = subOpList.map(op => JSON.parse(JSON.stringify(op.ingValues)));
|
||||||
|
let matched = false;
|
||||||
|
|
||||||
|
// Run recipe over each match
|
||||||
|
while ((m = regex.exec(input))) {
|
||||||
|
matched = true;
|
||||||
|
// Add up to match
|
||||||
|
let matchStr = m[0];
|
||||||
|
|
||||||
|
if (m.length === 1) { // No capture groups
|
||||||
|
output += input.slice(inOffset, m.index);
|
||||||
|
inOffset = m.index + m[0].length;
|
||||||
|
} else if (m.length >= 2) {
|
||||||
|
matchStr = m[1];
|
||||||
|
|
||||||
|
// Need to add some of the matched string that isn't in the capture group
|
||||||
|
output += input.slice(inOffset, m.index + m[0].indexOf(m[1]));
|
||||||
|
// Set i to be after the end of the first capture group
|
||||||
|
inOffset = m.index + m[0].indexOf(m[1]) + m[1].length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Baseline ing values for each tranche so that registers are reset
|
||||||
|
subOpList.forEach((op, i) => {
|
||||||
|
op.ingValues = JSON.parse(JSON.stringify(ingValues[i]));
|
||||||
|
});
|
||||||
|
|
||||||
|
const dish = new Dish();
|
||||||
|
dish.set(matchStr, inputType);
|
||||||
|
|
||||||
|
try {
|
||||||
|
progress = await recipe.execute(dish, 0, state);
|
||||||
|
} catch (err) {
|
||||||
|
if (!ignoreErrors) {
|
||||||
|
throw err;
|
||||||
|
}
|
||||||
|
progress = err.progress + 1;
|
||||||
|
}
|
||||||
|
output += await dish.get(outputType);
|
||||||
|
if (!regex.global) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no matches were found, advance progress to after a Merge op
|
||||||
|
// Otherwise, the operations below Subsection will be run on all the input data
|
||||||
|
if (!matched) {
|
||||||
|
state.progress += subOpList.length + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
output += input.slice(inOffset);
|
||||||
|
state.progress += progress;
|
||||||
|
state.dish.set(output, outputType);
|
||||||
|
}
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Subsection;
|
||||||
@@ -44,7 +44,7 @@ class Subtract extends Operation {
|
|||||||
*/
|
*/
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
const val = sub(createNumArray(input, args[0]));
|
const val = sub(createNumArray(input, args[0]));
|
||||||
return val instanceof BigNumber ? val : new BigNumber(NaN);
|
return BigNumber.isBigNumber(val) ? val : new BigNumber(NaN);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ class Sum extends Operation {
|
|||||||
*/
|
*/
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
const val = sum(createNumArray(input, args[0]));
|
const val = sum(createNumArray(input, args[0]));
|
||||||
return val instanceof BigNumber ? val : new BigNumber(NaN);
|
return BigNumber.isBigNumber(val) ? val : new BigNumber(NaN);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class TCPIPChecksum extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "TCP/IP Checksum";
|
this.name = "TCP/IP Checksum";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "Calculates the checksum for a TCP (Transport Control Protocol) or IP (Internet Protocol) header from an input of raw bytes.";
|
this.description = "Calculates the checksum for a TCP (Transport Control Protocol) or IP (Internet Protocol) header from an input of raw bytes.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/IPv4_header_checksum";
|
this.infoURL = "https://wikipedia.org/wiki/IPv4_header_checksum";
|
||||||
this.inputType = "byteArray";
|
this.inputType = "byteArray";
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class TextEncodingBruteForce extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "Text Encoding Brute Force";
|
this.name = "Text Encoding Brute Force";
|
||||||
this.module = "CharEnc";
|
this.module = "Encodings";
|
||||||
this.description = [
|
this.description = [
|
||||||
"Enumerates all supported text encodings for the input, allowing you to quickly spot the correct one.",
|
"Enumerates all supported text encodings for the input, allowing you to quickly spot the correct one.",
|
||||||
"<br><br>",
|
"<br><br>",
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ class ToBase64 extends Operation {
|
|||||||
|
|
||||||
this.name = "To Base64";
|
this.name = "To Base64";
|
||||||
this.module = "Default";
|
this.module = "Default";
|
||||||
this.description = "Base64 is a notation for encoding arbitrary byte data using a restricted set of symbols that can be conveniently used by humans and processed by computers.<br><br>This operation decodes data from an ASCII Base64 string back into its raw format.<br><br>e.g. <code>aGVsbG8=</code> becomes <code>hello</code>";
|
this.description = "Base64 is a notation for encoding arbitrary byte data using a restricted set of symbols that can be conveniently used by humans and processed by computers.<br><br>This operation encodes raw data into an ASCII Base64 string.<br><br>e.g. <code>hello</code> becomes <code>aGVsbG8=</code>";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Base64";
|
this.infoURL = "https://wikipedia.org/wiki/Base64";
|
||||||
this.inputType = "ArrayBuffer";
|
this.inputType = "ArrayBuffer";
|
||||||
this.outputType = "string";
|
this.outputType = "string";
|
||||||
|
|||||||
39
src/core/operations/ToCaseInsensitiveRegex.mjs
Normal file
39
src/core/operations/ToCaseInsensitiveRegex.mjs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* @author masq [github.cyberchef@masq.cc]
|
||||||
|
* @copyright Crown Copyright 2018
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* To Case Insensitive Regex operation
|
||||||
|
*/
|
||||||
|
class ToCaseInsensitiveRegex extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ToCaseInsensitiveRegex constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "To Case Insensitive Regex";
|
||||||
|
this.module = "Default";
|
||||||
|
this.description = "Converts a case-sensitive regex string into a case-insensitive regex string in case the i flag is unavailable to you.<br><br>e.g. <code>Mozilla/[0-9].[0-9] .*</code> becomes <code>[mM][oO][zZ][iI][lL][lL][aA]/[0-9].[0-9] .*</code>";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/Regular_expression";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
return input.replace(/[a-z]/ig, m => `[${m.toLowerCase()}${m.toUpperCase()}]`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ToCaseInsensitiveRegex;
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
/**
|
|
||||||
* @author gchq77703 []
|
|
||||||
* @copyright Crown Copyright 2018
|
|
||||||
* @license Apache-2.0
|
|
||||||
*/
|
|
||||||
|
|
||||||
import Operation from "../Operation";
|
|
||||||
import geohash from "ngeohash";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* To Geohash operation
|
|
||||||
*/
|
|
||||||
class ToGeohash extends Operation {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* ToGeohash constructor
|
|
||||||
*/
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
|
|
||||||
this.name = "To Geohash";
|
|
||||||
this.module = "Hashing";
|
|
||||||
this.description = "Converts Lat/Long coordinates into a Geohash string. For example, <code>37.8324,112.5584</code> becomes <code>ww8p1r4t8</code>.";
|
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Geohash";
|
|
||||||
this.inputType = "string";
|
|
||||||
this.outputType = "string";
|
|
||||||
this.args = [
|
|
||||||
{
|
|
||||||
name: "Precision",
|
|
||||||
type: "number",
|
|
||||||
value: 9
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} input
|
|
||||||
* @param {Object[]} args
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
run(input, args) {
|
|
||||||
const [precision] = args;
|
|
||||||
|
|
||||||
return input.split("\n").map(line => {
|
|
||||||
line = line.replace(/ /g, "");
|
|
||||||
if (line === "") return "";
|
|
||||||
return geohash.encode(...line.split(",").map(num => parseFloat(num)), precision);
|
|
||||||
}).join("\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
export default ToGeohash;
|
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import Operation from "../Operation";
|
import Operation from "../Operation";
|
||||||
import OperationError from "../errors/OperationError.mjs";
|
import OperationError from "../errors/OperationError";
|
||||||
import notepack from "notepack.io";
|
import notepack from "notepack.io";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -38,7 +38,9 @@ class ToMessagePack extends Operation {
|
|||||||
if (ENVIRONMENT_IS_WORKER()) {
|
if (ENVIRONMENT_IS_WORKER()) {
|
||||||
return notepack.encode(input);
|
return notepack.encode(input);
|
||||||
} else {
|
} else {
|
||||||
return notepack.encode(input).buffer;
|
const res = notepack.encode(input);
|
||||||
|
// Safely convert from Node Buffer to ArrayBuffer using the correct view of the data
|
||||||
|
return (new Uint8Array(res)).buffer;
|
||||||
}
|
}
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
throw new OperationError(`Could not encode JSON to MessagePack: ${err}`);
|
throw new OperationError(`Could not encode JSON to MessagePack: ${err}`);
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ class Whirlpool extends Operation {
|
|||||||
super();
|
super();
|
||||||
|
|
||||||
this.name = "Whirlpool";
|
this.name = "Whirlpool";
|
||||||
this.module = "Hashing";
|
this.module = "Crypto";
|
||||||
this.description = "Whirlpool is a cryptographic hash function designed by Vincent Rijmen (co-creator of AES) and Paulo S. L. M. Barreto, who first described it in 2000.<br><br>Several variants exist:<ul><li>Whirlpool-0 is the original version released in 2000.</li><li>Whirlpool-T is the first revision, released in 2001, improving the generation of the s-box.</li><li>Whirlpool is the latest revision, released in 2003, fixing a flaw in the difusion matrix.</li></ul>";
|
this.description = "Whirlpool is a cryptographic hash function designed by Vincent Rijmen (co-creator of AES) and Paulo S. L. M. Barreto, who first described it in 2000.<br><br>Several variants exist:<ul><li>Whirlpool-0 is the original version released in 2000.</li><li>Whirlpool-T is the first revision, released in 2001, improving the generation of the s-box.</li><li>Whirlpool is the latest revision, released in 2003, fixing a flaw in the difusion matrix.</li></ul>";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Whirlpool_(cryptography)";
|
this.infoURL = "https://wikipedia.org/wiki/Whirlpool_(cryptography)";
|
||||||
this.inputType = "ArrayBuffer";
|
this.inputType = "ArrayBuffer";
|
||||||
|
|||||||
122
src/core/operations/YARARules.mjs
Normal file
122
src/core/operations/YARARules.mjs
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
/**
|
||||||
|
* @author Matt C [matt@artemisbot.uk]
|
||||||
|
* @copyright Crown Copyright 2019
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation";
|
||||||
|
import OperationError from "../errors/OperationError";
|
||||||
|
import Yara from "libyara-wasm";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* YARA Rules operation
|
||||||
|
*/
|
||||||
|
class YARARules extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* YARARules constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "YARA Rules";
|
||||||
|
this.module = "Yara";
|
||||||
|
this.description = "YARA is a tool developed at VirusTotal, primarily aimed at helping malware researchers to identify and classify malware samples. It matches based on rules specified by the user containing textual or binary patterns and a boolean expression. For help on writing rules, see the <a href='https://yara.readthedocs.io/en/latest/writingrules.html'>YARA documentation.</a>";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/YARA";
|
||||||
|
this.inputType = "ArrayBuffer";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
name: "Rules",
|
||||||
|
type: "text",
|
||||||
|
value: "",
|
||||||
|
rows: 5
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Show strings",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Show string lengths",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Show metadata",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Show counts",
|
||||||
|
type: "boolean",
|
||||||
|
value: true
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
if (ENVIRONMENT_IS_WORKER())
|
||||||
|
self.sendStatusMessage("Instantiating YARA...");
|
||||||
|
const [rules, showStrings, showLengths, showMeta, showCounts] = args;
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
Yara().then(yara => {
|
||||||
|
if (ENVIRONMENT_IS_WORKER()) self.sendStatusMessage("Converting data for YARA.");
|
||||||
|
let matchString = "";
|
||||||
|
|
||||||
|
const inpArr = new Uint8Array(input); // Turns out embind knows that JS uint8array <==> C++ std::string
|
||||||
|
|
||||||
|
if (ENVIRONMENT_IS_WORKER()) self.sendStatusMessage("Running YARA matching.");
|
||||||
|
|
||||||
|
const resp = yara.run(inpArr, rules);
|
||||||
|
|
||||||
|
if (ENVIRONMENT_IS_WORKER()) self.sendStatusMessage("Processing data.");
|
||||||
|
|
||||||
|
if (resp.compileErrors.size() > 0) {
|
||||||
|
for (let i = 0; i < resp.compileErrors.size(); i++) {
|
||||||
|
const compileError = resp.compileErrors.get(i);
|
||||||
|
if (!compileError.warning) {
|
||||||
|
reject(new OperationError(`Error on line ${compileError.lineNumber}: ${compileError.message}`));
|
||||||
|
} else {
|
||||||
|
matchString += `Warning on line ${compileError.lineNumber}: ${compileError.message}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const matchedRules = resp.matchedRules;
|
||||||
|
for (let i = 0; i < matchedRules.size(); i++) {
|
||||||
|
const rule = matchedRules.get(i);
|
||||||
|
const matches = rule.resolvedMatches;
|
||||||
|
let meta = "";
|
||||||
|
if (showMeta && rule.metadata.size() > 0) {
|
||||||
|
meta += " [";
|
||||||
|
for (let j = 0; j < rule.metadata.size(); j++) {
|
||||||
|
meta += `${rule.metadata.get(j).identifier}: ${rule.metadata.get(j).data}, `;
|
||||||
|
}
|
||||||
|
meta = meta.slice(0, -2) + "]";
|
||||||
|
}
|
||||||
|
const countString = showCounts ? `${matches.size()} time${matches.size() > 1 ? "s" : ""}` : "";
|
||||||
|
if (matches.size() === 0 || !(showStrings || showLengths)) {
|
||||||
|
matchString += `Input matches rule "${rule.ruleName}"${meta}${countString.length > 0 ? ` ${countString}`: ""}.\n`;
|
||||||
|
} else {
|
||||||
|
matchString += `Rule "${rule.ruleName}"${meta} matches (${countString}):\n`;
|
||||||
|
for (let j = 0; j < matches.size(); j++) {
|
||||||
|
const match = matches.get(j);
|
||||||
|
if (showStrings || showLengths) {
|
||||||
|
matchString += `Pos ${match.location}, ${showLengths ? `length ${match.matchLength}, ` : ""}identifier ${match.stringIdentifier}${showStrings ? `, data: "${match.data}"` : ""}\n`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
resolve(matchString);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default YARARules;
|
||||||
2
src/core/vendor/remove-exif.mjs
vendored
2
src/core/vendor/remove-exif.mjs
vendored
@@ -18,7 +18,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|||||||
SOFTWARE.
|
SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import Utils from "../Utils.mjs";
|
import Utils from "../Utils";
|
||||||
|
|
||||||
// Param jpeg should be a binaryArray
|
// Param jpeg should be a binaryArray
|
||||||
export function removeEXIF(jpeg) {
|
export function removeEXIF(jpeg) {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import Manager from "./Manager";
|
|||||||
import HTMLCategory from "./HTMLCategory";
|
import HTMLCategory from "./HTMLCategory";
|
||||||
import HTMLOperation from "./HTMLOperation";
|
import HTMLOperation from "./HTMLOperation";
|
||||||
import Split from "split.js";
|
import Split from "split.js";
|
||||||
|
import moment from "moment-timezone";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -237,12 +238,18 @@ class App {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets up the adjustable splitter to allow the user to resize areas of the page.
|
* Sets up the adjustable splitter to allow the user to resize areas of the page.
|
||||||
|
*
|
||||||
|
* @param {boolean} [minimise=false] - Set this flag if attempting to minimuse frames to 0 width
|
||||||
*/
|
*/
|
||||||
initialiseSplitter() {
|
initialiseSplitter(minimise=false) {
|
||||||
|
if (this.columnSplitter) this.columnSplitter.destroy();
|
||||||
|
if (this.ioSplitter) this.ioSplitter.destroy();
|
||||||
|
|
||||||
this.columnSplitter = Split(["#operations", "#recipe", "#IO"], {
|
this.columnSplitter = Split(["#operations", "#recipe", "#IO"], {
|
||||||
sizes: [20, 30, 50],
|
sizes: [20, 30, 50],
|
||||||
minSize: [240, 370, 450],
|
minSize: minimise ? [0, 0, 0] : [240, 370, 450],
|
||||||
gutterSize: 4,
|
gutterSize: 4,
|
||||||
|
expandToMin: false,
|
||||||
onDrag: function() {
|
onDrag: function() {
|
||||||
this.manager.recipe.adjustWidth();
|
this.manager.recipe.adjustWidth();
|
||||||
}.bind(this)
|
}.bind(this)
|
||||||
@@ -250,7 +257,8 @@ class App {
|
|||||||
|
|
||||||
this.ioSplitter = Split(["#input", "#output"], {
|
this.ioSplitter = Split(["#input", "#output"], {
|
||||||
direction: "vertical",
|
direction: "vertical",
|
||||||
gutterSize: 4
|
gutterSize: 4,
|
||||||
|
minSize: minimise ? [0, 0] : [100, 100]
|
||||||
});
|
});
|
||||||
|
|
||||||
this.resetLayout();
|
this.resetLayout();
|
||||||
@@ -515,7 +523,8 @@ class App {
|
|||||||
setCompileMessage() {
|
setCompileMessage() {
|
||||||
// Display time since last build and compile message
|
// Display time since last build and compile message
|
||||||
const now = new Date(),
|
const now = new Date(),
|
||||||
timeSinceCompile = Utils.fuzzyTime(now.getTime() - window.compileTime);
|
msSinceCompile = now.getTime() - window.compileTime,
|
||||||
|
timeSinceCompile = moment.duration(msSinceCompile, "milliseconds").humanize();
|
||||||
|
|
||||||
// Calculate previous version to compare to
|
// Calculate previous version to compare to
|
||||||
const prev = PKG_VERSION.split(".").map(n => {
|
const prev = PKG_VERSION.split(".").map(n => {
|
||||||
|
|||||||
@@ -25,7 +25,9 @@ class HTMLIngredient {
|
|||||||
this.value = config.value;
|
this.value = config.value;
|
||||||
this.disabled = config.disabled || false;
|
this.disabled = config.disabled || false;
|
||||||
this.hint = config.hint || false;
|
this.hint = config.hint || false;
|
||||||
|
this.rows = config.rows || false;
|
||||||
this.target = config.target;
|
this.target = config.target;
|
||||||
|
this.defaultIndex = config.defaultIndex || 0;
|
||||||
this.toggleValues = config.toggleValues;
|
this.toggleValues = config.toggleValues;
|
||||||
this.id = "ing-" + this.app.nextIngId();
|
this.id = "ing-" + this.app.nextIngId();
|
||||||
}
|
}
|
||||||
@@ -133,7 +135,7 @@ class HTMLIngredient {
|
|||||||
} else if ((m = this.value[i].match(/\[\/([a-z0-9 -()^]+)\]/i))) {
|
} else if ((m = this.value[i].match(/\[\/([a-z0-9 -()^]+)\]/i))) {
|
||||||
html += "</optgroup>";
|
html += "</optgroup>";
|
||||||
} else {
|
} else {
|
||||||
html += `<option>${this.value[i]}</option>`;
|
html += `<option ${this.defaultIndex === i ? "selected" : ""}>${this.value[i]}</option>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
html += `</select>
|
html += `</select>
|
||||||
@@ -154,7 +156,7 @@ class HTMLIngredient {
|
|||||||
} else if ((m = this.value[i].name.match(/\[\/([a-z0-9 -()^]+)\]/i))) {
|
} else if ((m = this.value[i].name.match(/\[\/([a-z0-9 -()^]+)\]/i))) {
|
||||||
html += "</optgroup>";
|
html += "</optgroup>";
|
||||||
} else {
|
} else {
|
||||||
html += `<option populate-value='${this.value[i].value}'>${this.value[i].name}</option>`;
|
html += `<option populate-value="${this.value[i].value}">${this.value[i].name}</option>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
html += `</select>
|
html += `</select>
|
||||||
@@ -164,13 +166,42 @@ class HTMLIngredient {
|
|||||||
this.manager.addDynamicListener("#" + this.id, "change", this.populateOptionChange, this);
|
this.manager.addDynamicListener("#" + this.id, "change", this.populateOptionChange, this);
|
||||||
break;
|
break;
|
||||||
case "editableOption":
|
case "editableOption":
|
||||||
|
html += `<div class="form-group input-group">
|
||||||
|
<label for="${this.id}" class="bmd-label-floating">${this.name}</label>
|
||||||
|
<input type="text"
|
||||||
|
class="form-control arg"
|
||||||
|
id="${this.id}"
|
||||||
|
arg-name="${this.name}"
|
||||||
|
value="${this.value[this.defaultIndex].value}"
|
||||||
|
${this.disabled ? "disabled" : ""}>
|
||||||
|
${this.hint ? "<span class='bmd-help'>" + this.hint + "</span>" : ""}
|
||||||
|
<div class="input-group-append">
|
||||||
|
<button type="button"
|
||||||
|
class="btn btn-secondary dropdown-toggle dropdown-toggle-split"
|
||||||
|
data-toggle="dropdown"
|
||||||
|
data-boundary="scrollParent"
|
||||||
|
aria-haspopup="true"
|
||||||
|
aria-expanded="false">
|
||||||
|
<span class="sr-only">Toggle Dropdown</span>
|
||||||
|
</button>
|
||||||
|
<div class="dropdown-menu editable-option-menu">`;
|
||||||
|
for (i = 0; i < this.value.length; i++) {
|
||||||
|
html += `<a class="dropdown-item" href="#" value="${this.value[i].value}">${this.value[i].name}</a>`;
|
||||||
|
}
|
||||||
|
html += `</div>
|
||||||
|
</div>
|
||||||
|
</div>`;
|
||||||
|
|
||||||
|
this.manager.addDynamicListener(".editable-option-menu a", "click", this.editableOptionClick, this);
|
||||||
|
break;
|
||||||
|
case "editableOptionShort":
|
||||||
html += `<div class="form-group input-group inline">
|
html += `<div class="form-group input-group inline">
|
||||||
<label for="${this.id}" class="bmd-label-floating inline">${this.name}</label>
|
<label for="${this.id}" class="bmd-label-floating inline">${this.name}</label>
|
||||||
<input type="text"
|
<input type="text"
|
||||||
class="form-control arg inline"
|
class="form-control arg inline"
|
||||||
id="${this.id}"
|
id="${this.id}"
|
||||||
arg-name="${this.name}"
|
arg-name="${this.name}"
|
||||||
value="${this.value[0].value}"
|
value="${this.value[this.defaultIndex].value}"
|
||||||
${this.disabled ? "disabled" : ""}>
|
${this.disabled ? "disabled" : ""}>
|
||||||
${this.hint ? "<span class='bmd-help'>" + this.hint + "</span>" : ""}
|
${this.hint ? "<span class='bmd-help'>" + this.hint + "</span>" : ""}
|
||||||
<div class="input-group-append inline">
|
<div class="input-group-append inline">
|
||||||
@@ -199,6 +230,7 @@ class HTMLIngredient {
|
|||||||
class="form-control arg"
|
class="form-control arg"
|
||||||
id="${this.id}"
|
id="${this.id}"
|
||||||
arg-name="${this.name}"
|
arg-name="${this.name}"
|
||||||
|
rows="${this.rows ? this.rows : 3}"
|
||||||
${this.disabled ? "disabled" : ""}>${this.value}</textarea>
|
${this.disabled ? "disabled" : ""}>${this.value}</textarea>
|
||||||
${this.hint ? "<span class='bmd-help'>" + this.hint + "</span>" : ""}
|
${this.hint ? "<span class='bmd-help'>" + this.hint + "</span>" : ""}
|
||||||
</div>`;
|
</div>`;
|
||||||
|
|||||||
@@ -137,6 +137,9 @@ class Manager {
|
|||||||
this.addDynamicListener("#rec-list li.operation > div", "dblclick", this.recipe.operationChildDblclick, this.recipe);
|
this.addDynamicListener("#rec-list li.operation > div", "dblclick", this.recipe.operationChildDblclick, this.recipe);
|
||||||
this.addDynamicListener("#rec-list .dropdown-menu.toggle-dropdown a", "click", this.recipe.dropdownToggleClick, this.recipe);
|
this.addDynamicListener("#rec-list .dropdown-menu.toggle-dropdown a", "click", this.recipe.dropdownToggleClick, this.recipe);
|
||||||
this.addDynamicListener("#rec-list", "operationremove", this.recipe.opRemove.bind(this.recipe));
|
this.addDynamicListener("#rec-list", "operationremove", this.recipe.opRemove.bind(this.recipe));
|
||||||
|
this.addDynamicListener("textarea.arg", "dragover", this.recipe.textArgDragover, this.recipe);
|
||||||
|
this.addDynamicListener("textarea.arg", "dragleave", this.recipe.textArgDragLeave, this.recipe);
|
||||||
|
this.addDynamicListener("textarea.arg", "drop", this.recipe.textArgDrop, this.recipe);
|
||||||
|
|
||||||
// Input
|
// Input
|
||||||
this.addMultiEventListener("#input-text", "keyup", this.input.inputChange, this.input);
|
this.addMultiEventListener("#input-text", "keyup", this.input.inputChange, this.input);
|
||||||
|
|||||||
@@ -319,6 +319,7 @@ class OutputWaiter {
|
|||||||
const el = e.target.id === "maximise-output" ? e.target : e.target.parentNode;
|
const el = e.target.id === "maximise-output" ? e.target : e.target.parentNode;
|
||||||
|
|
||||||
if (el.getAttribute("data-original-title").indexOf("Maximise") === 0) {
|
if (el.getAttribute("data-original-title").indexOf("Maximise") === 0) {
|
||||||
|
this.app.initialiseSplitter(true);
|
||||||
this.app.columnSplitter.collapse(0);
|
this.app.columnSplitter.collapse(0);
|
||||||
this.app.columnSplitter.collapse(1);
|
this.app.columnSplitter.collapse(1);
|
||||||
this.app.ioSplitter.collapse(0);
|
this.app.ioSplitter.collapse(0);
|
||||||
@@ -328,6 +329,7 @@ class OutputWaiter {
|
|||||||
} else {
|
} else {
|
||||||
$(el).attr("data-original-title", "Maximise output pane");
|
$(el).attr("data-original-title", "Maximise output pane");
|
||||||
el.querySelector("i").innerHTML = "fullscreen";
|
el.querySelector("i").innerHTML = "fullscreen";
|
||||||
|
this.app.initialiseSplitter(false);
|
||||||
this.app.resetLayout();
|
this.app.resetLayout();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -376,6 +376,7 @@ class RecipeWaiter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds the specified operation to the recipe.
|
* Adds the specified operation to the recipe.
|
||||||
*
|
*
|
||||||
@@ -454,6 +455,75 @@ class RecipeWaiter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for text argument dragover events.
|
||||||
|
* Gives the user a visual cue to show that items can be dropped here.
|
||||||
|
*
|
||||||
|
* @param {event} e
|
||||||
|
*/
|
||||||
|
textArgDragover (e) {
|
||||||
|
// This will be set if we're dragging an operation
|
||||||
|
if (e.dataTransfer.effectAllowed === "move")
|
||||||
|
return false;
|
||||||
|
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
e.target.closest("textarea.arg").classList.add("dropping-file");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for text argument dragleave events.
|
||||||
|
* Removes the visual cue.
|
||||||
|
*
|
||||||
|
* @param {event} e
|
||||||
|
*/
|
||||||
|
textArgDragLeave (e) {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
e.target.classList.remove("dropping-file");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for text argument drop events.
|
||||||
|
* Loads the dragged data into the argument textarea.
|
||||||
|
*
|
||||||
|
* @param {event} e
|
||||||
|
*/
|
||||||
|
textArgDrop(e) {
|
||||||
|
// This will be set if we're dragging an operation
|
||||||
|
if (e.dataTransfer.effectAllowed === "move")
|
||||||
|
return false;
|
||||||
|
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
const targ = e.target;
|
||||||
|
const file = e.dataTransfer.files[0];
|
||||||
|
const text = e.dataTransfer.getData("Text");
|
||||||
|
|
||||||
|
targ.classList.remove("dropping-file");
|
||||||
|
|
||||||
|
if (text) {
|
||||||
|
targ.value = text;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file) {
|
||||||
|
const reader = new FileReader();
|
||||||
|
const self = this;
|
||||||
|
reader.onload = function (e) {
|
||||||
|
targ.value = e.target.result;
|
||||||
|
// Trigger floating label move
|
||||||
|
const changeEvent = new Event("change");
|
||||||
|
targ.dispatchEvent(changeEvent);
|
||||||
|
window.dispatchEvent(self.manager.statechange);
|
||||||
|
};
|
||||||
|
reader.readAsText(file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets register values.
|
* Sets register values.
|
||||||
*
|
*
|
||||||
@@ -479,6 +549,7 @@ class RecipeWaiter {
|
|||||||
op.insertAdjacentHTML("beforeend", registerListEl);
|
op.insertAdjacentHTML("beforeend", registerListEl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adjusts the number of ingredient columns as the width of the recipe changes.
|
* Adjusts the number of ingredient columns as the width of the recipe changes.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -15,7 +15,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: var(--controls-height);
|
height: var(--controls-height);
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
padding: 10px;
|
padding: 0;
|
||||||
padding-top: 12px;
|
padding-top: 12px;
|
||||||
border-top: 1px solid var(--primary-border-colour);
|
border-top: 1px solid var(--primary-border-colour);
|
||||||
background-color: var(--secondary-background-colour);
|
background-color: var(--secondary-background-colour);
|
||||||
|
|||||||
@@ -123,6 +123,7 @@
|
|||||||
|
|
||||||
.dropping-file {
|
.dropping-file {
|
||||||
border: 5px dashed var(--drop-file-border-colour) !important;
|
border: 5px dashed var(--drop-file-border-colour) !important;
|
||||||
|
margin: -5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#stale-indicator {
|
#stale-indicator {
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
/**
|
|
||||||
* To Geohash tests
|
|
||||||
*
|
|
||||||
* @author gchq77703
|
|
||||||
* @copyright Crown Copyright 2018
|
|
||||||
* @license Apache-2.0
|
|
||||||
*/
|
|
||||||
import TestRegister from "../../TestRegister";
|
|
||||||
|
|
||||||
TestRegister.addTests([
|
|
||||||
{
|
|
||||||
name: "From Geohash",
|
|
||||||
input: "ww8p1r4t8",
|
|
||||||
expectedOutput: "37.83238649368286,112.55838632583618",
|
|
||||||
recipeConfig: [
|
|
||||||
{
|
|
||||||
op: "From Geohash",
|
|
||||||
args: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "From Geohash",
|
|
||||||
input: "ww8p1r",
|
|
||||||
expectedOutput: "37.83416748046875,112.5604248046875",
|
|
||||||
recipeConfig: [
|
|
||||||
{
|
|
||||||
op: "From Geohash",
|
|
||||||
args: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "From Geohash",
|
|
||||||
input: "ww8",
|
|
||||||
expectedOutput: "37.265625,113.203125",
|
|
||||||
recipeConfig: [
|
|
||||||
{
|
|
||||||
op: "From Geohash",
|
|
||||||
args: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "From Geohash",
|
|
||||||
input: "w",
|
|
||||||
expectedOutput: "22.5,112.5",
|
|
||||||
recipeConfig: [
|
|
||||||
{
|
|
||||||
op: "From Geohash",
|
|
||||||
args: [],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
@@ -1,55 +0,0 @@
|
|||||||
/**
|
|
||||||
* To Geohash tests
|
|
||||||
*
|
|
||||||
* @author gchq77703
|
|
||||||
* @copyright Crown Copyright 2018
|
|
||||||
* @license Apache-2.0
|
|
||||||
*/
|
|
||||||
import TestRegister from "../../TestRegister";
|
|
||||||
|
|
||||||
TestRegister.addTests([
|
|
||||||
{
|
|
||||||
name: "To Geohash",
|
|
||||||
input: "37.8324,112.5584",
|
|
||||||
expectedOutput: "ww8p1r4t8",
|
|
||||||
recipeConfig: [
|
|
||||||
{
|
|
||||||
op: "To Geohash",
|
|
||||||
args: [9],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "To Geohash",
|
|
||||||
input: "37.9324,-112.2584",
|
|
||||||
expectedOutput: "9w8pv3ruj",
|
|
||||||
recipeConfig: [
|
|
||||||
{
|
|
||||||
op: "To Geohash",
|
|
||||||
args: [9],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "To Geohash",
|
|
||||||
input: "37.8324,112.5584",
|
|
||||||
expectedOutput: "ww8",
|
|
||||||
recipeConfig: [
|
|
||||||
{
|
|
||||||
op: "To Geohash",
|
|
||||||
args: [3],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
{
|
|
||||||
name: "To Geohash",
|
|
||||||
input: "37.9324,-112.2584",
|
|
||||||
expectedOutput: "9w8pv3rujxy5b99",
|
|
||||||
recipeConfig: [
|
|
||||||
{
|
|
||||||
op: "To Geohash",
|
|
||||||
args: [15],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
},
|
|
||||||
]);
|
|
||||||
182
tests/browser/nightwatch.js
Normal file
182
tests/browser/nightwatch.js
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
/**
|
||||||
|
* Tests to ensure that the app loads correctly in a reasonable time and that operations can be run.
|
||||||
|
*
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2018
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
before: browser => {
|
||||||
|
browser
|
||||||
|
.resizeWindow(1280, 800)
|
||||||
|
.url(browser.launchUrl);
|
||||||
|
},
|
||||||
|
|
||||||
|
"Loading screen": browser => {
|
||||||
|
// Check that the loading screen appears and then disappears within a reasonable time
|
||||||
|
browser
|
||||||
|
.waitForElementVisible("#preloader", 300)
|
||||||
|
.waitForElementNotPresent("#preloader", 10000);
|
||||||
|
},
|
||||||
|
|
||||||
|
"App loaded": browser => {
|
||||||
|
browser.useCss();
|
||||||
|
// Check that various important elements are loaded
|
||||||
|
browser.expect.element("#operations").to.be.visible;
|
||||||
|
browser.expect.element("#recipe").to.be.visible;
|
||||||
|
browser.expect.element("#input").to.be.present;
|
||||||
|
browser.expect.element("#output").to.be.present;
|
||||||
|
browser.expect.element(".op-list").to.be.present;
|
||||||
|
browser.expect.element("#rec-list").to.be.visible;
|
||||||
|
browser.expect.element("#controls").to.be.visible;
|
||||||
|
browser.expect.element("#input-text").to.be.visible;
|
||||||
|
browser.expect.element("#output-text").to.be.visible;
|
||||||
|
},
|
||||||
|
|
||||||
|
"Operations loaded": browser => {
|
||||||
|
browser.useXpath();
|
||||||
|
// Check that an operation in every category has been populated
|
||||||
|
browser.expect.element("//li[contains(@class, 'operation') and text()='To Base64']").to.be.present;
|
||||||
|
browser.expect.element("//li[contains(@class, 'operation') and text()='To Binary']").to.be.present;
|
||||||
|
browser.expect.element("//li[contains(@class, 'operation') and text()='AES Decrypt']").to.be.present;
|
||||||
|
browser.expect.element("//li[contains(@class, 'operation') and text()='PEM to Hex']").to.be.present;
|
||||||
|
browser.expect.element("//li[contains(@class, 'operation') and text()='Power Set']").to.be.present;
|
||||||
|
browser.expect.element("//li[contains(@class, 'operation') and text()='Parse IP range']").to.be.present;
|
||||||
|
browser.expect.element("//li[contains(@class, 'operation') and text()='Remove Diacritics']").to.be.present;
|
||||||
|
browser.expect.element("//li[contains(@class, 'operation') and text()='Sort']").to.be.present;
|
||||||
|
browser.expect.element("//li[contains(@class, 'operation') and text()='To UNIX Timestamp']").to.be.present;
|
||||||
|
browser.expect.element("//li[contains(@class, 'operation') and text()='Extract dates']").to.be.present;
|
||||||
|
browser.expect.element("//li[contains(@class, 'operation') and text()='Gzip']").to.be.present;
|
||||||
|
browser.expect.element("//li[contains(@class, 'operation') and text()='Keccak']").to.be.present;
|
||||||
|
browser.expect.element("//li[contains(@class, 'operation') and text()='JSON Beautify']").to.be.present;
|
||||||
|
browser.expect.element("//li[contains(@class, 'operation') and text()='Detect File Type']").to.be.present;
|
||||||
|
browser.expect.element("//li[contains(@class, 'operation') and text()='Play Media']").to.be.present;
|
||||||
|
browser.expect.element("//li[contains(@class, 'operation') and text()='Disassemble x86']").to.be.present;
|
||||||
|
browser.expect.element("//li[contains(@class, 'operation') and text()='Register']").to.be.present;
|
||||||
|
},
|
||||||
|
|
||||||
|
"Recipe can be run": browser => {
|
||||||
|
const toHex = "//li[contains(@class, 'operation') and text()='To Hex']";
|
||||||
|
const op = "#rec-list .operation .op-title";
|
||||||
|
|
||||||
|
// Check that operation is visible
|
||||||
|
browser
|
||||||
|
.useXpath()
|
||||||
|
.expect.element(toHex).to.be.visible;
|
||||||
|
|
||||||
|
// Add it to the recipe by double clicking
|
||||||
|
browser
|
||||||
|
.useXpath()
|
||||||
|
.moveToElement(toHex, 10, 10)
|
||||||
|
.useCss()
|
||||||
|
.waitForElementVisible(".popover-body", 1000)
|
||||||
|
.doubleClick();
|
||||||
|
|
||||||
|
// Confirm that it has been added to the recipe
|
||||||
|
browser
|
||||||
|
.useCss()
|
||||||
|
.waitForElementVisible(op)
|
||||||
|
.expect.element(op).text.to.contain("To Hex");
|
||||||
|
|
||||||
|
// Enter input
|
||||||
|
browser
|
||||||
|
.useCss()
|
||||||
|
.setValue("#input-text", "Don't Panic.")
|
||||||
|
.click("#bake");
|
||||||
|
|
||||||
|
// Check output
|
||||||
|
browser
|
||||||
|
.useCss()
|
||||||
|
.waitForElementNotVisible("#stale-indicator", 500)
|
||||||
|
.expect.element("#output-text").to.have.value.that.equals("44 6f 6e 27 74 20 50 61 6e 69 63 2e");
|
||||||
|
|
||||||
|
// Clear recipe
|
||||||
|
browser
|
||||||
|
.useCss()
|
||||||
|
.moveToElement(op, 10, 10)
|
||||||
|
.waitForElementNotPresent(".popover-body", 1000)
|
||||||
|
.click("#clr-recipe")
|
||||||
|
.waitForElementNotPresent(op);
|
||||||
|
},
|
||||||
|
|
||||||
|
"Test every module": browser => {
|
||||||
|
browser.useCss();
|
||||||
|
|
||||||
|
// BSON
|
||||||
|
loadOp("BSON deserialise", browser)
|
||||||
|
.waitForElementNotVisible("#output-loader", 5000);
|
||||||
|
|
||||||
|
// Ciphers
|
||||||
|
loadOp("AES Encrypt", browser)
|
||||||
|
.waitForElementNotVisible("#output-loader", 5000);
|
||||||
|
|
||||||
|
// Code
|
||||||
|
loadOp("XPath expression", browser)
|
||||||
|
.waitForElementNotVisible("#output-loader", 5000);
|
||||||
|
|
||||||
|
// Compression
|
||||||
|
loadOp("Gzip", browser)
|
||||||
|
.waitForElementNotVisible("#output-loader", 5000);
|
||||||
|
|
||||||
|
// Crypto
|
||||||
|
loadOp("MD5", browser)
|
||||||
|
.waitForElementNotVisible("#output-loader", 5000);
|
||||||
|
|
||||||
|
// Default
|
||||||
|
loadOp("Fork", browser)
|
||||||
|
.waitForElementNotVisible("#output-loader", 5000);
|
||||||
|
|
||||||
|
// Diff
|
||||||
|
loadOp("Diff", browser)
|
||||||
|
.waitForElementNotVisible("#output-loader", 5000);
|
||||||
|
|
||||||
|
// Encodings
|
||||||
|
loadOp("Encode text", browser)
|
||||||
|
.waitForElementNotVisible("#output-loader", 5000);
|
||||||
|
|
||||||
|
// Image
|
||||||
|
loadOp("Extract EXIF", browser)
|
||||||
|
.waitForElementNotVisible("#output-loader", 5000);
|
||||||
|
|
||||||
|
// PGP
|
||||||
|
loadOp("PGP Encrypt", browser)
|
||||||
|
.waitForElementNotVisible("#output-loader", 5000);
|
||||||
|
|
||||||
|
// PublicKey
|
||||||
|
loadOp("Hex to PEM", browser)
|
||||||
|
.waitForElementNotVisible("#output-loader", 5000);
|
||||||
|
|
||||||
|
// Regex
|
||||||
|
loadOp("Strings", browser)
|
||||||
|
.waitForElementNotVisible("#output-loader", 5000);
|
||||||
|
|
||||||
|
// Shellcode
|
||||||
|
loadOp("Disassemble x86", browser)
|
||||||
|
.waitForElementNotVisible("#output-loader", 5000);
|
||||||
|
|
||||||
|
// URL
|
||||||
|
loadOp("URL Encode", browser)
|
||||||
|
.waitForElementNotVisible("#output-loader", 5000);
|
||||||
|
|
||||||
|
// UserAgent
|
||||||
|
loadOp("Parse User Agent", browser)
|
||||||
|
.waitForElementNotVisible("#output-loader", 5000);
|
||||||
|
},
|
||||||
|
|
||||||
|
after: browser => {
|
||||||
|
browser.end();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clears the current recipe and loads a new operation.
|
||||||
|
*
|
||||||
|
* @param {string} opName
|
||||||
|
* @param {Browser} browser
|
||||||
|
*/
|
||||||
|
function loadOp(opName, browser) {
|
||||||
|
return browser
|
||||||
|
.useCss()
|
||||||
|
.click("#clr-recipe")
|
||||||
|
.urlHash("op=" + opName);
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@
|
|||||||
* @copyright Crown Copyright 2017
|
* @copyright Crown Copyright 2017
|
||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
*/
|
*/
|
||||||
import Chef from "../src/core/Chef";
|
import Chef from "../../src/core/Chef";
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
/**
|
/**
|
||||||
@@ -24,62 +24,68 @@ global.ENVIRONMENT_IS_WEB = function() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
import TestRegister from "./TestRegister";
|
import TestRegister from "./TestRegister";
|
||||||
import "./tests/operations/BCD";
|
import "./tests/BCD";
|
||||||
import "./tests/operations/BSON";
|
import "./tests/BSON";
|
||||||
import "./tests/operations/Base58";
|
import "./tests/Base58";
|
||||||
import "./tests/operations/Base64";
|
import "./tests/Base64";
|
||||||
import "./tests/operations/Base62";
|
import "./tests/Base62";
|
||||||
import "./tests/operations/BitwiseOp";
|
import "./tests/BitwiseOp";
|
||||||
import "./tests/operations/ByteRepr";
|
import "./tests/ByteRepr";
|
||||||
import "./tests/operations/CartesianProduct";
|
import "./tests/CartesianProduct";
|
||||||
import "./tests/operations/CharEnc";
|
import "./tests/CharEnc";
|
||||||
import "./tests/operations/Checksum";
|
import "./tests/Checksum";
|
||||||
import "./tests/operations/Ciphers";
|
import "./tests/Ciphers";
|
||||||
import "./tests/operations/Code";
|
import "./tests/Code";
|
||||||
import "./tests/operations/Comment";
|
import "./tests/Comment";
|
||||||
import "./tests/operations/Compress";
|
import "./tests/Compress";
|
||||||
import "./tests/operations/ConditionalJump";
|
import "./tests/ConditionalJump";
|
||||||
import "./tests/operations/Crypt";
|
import "./tests/Crypt";
|
||||||
import "./tests/operations/CSV";
|
import "./tests/CSV";
|
||||||
import "./tests/operations/DateTime";
|
import "./tests/DateTime";
|
||||||
import "./tests/operations/ExtractEmailAddresses";
|
import "./tests/ExtractEmailAddresses";
|
||||||
import "./tests/operations/Fork";
|
import "./tests/Fork";
|
||||||
import "./tests/operations/FromDecimal";
|
import "./tests/FromDecimal";
|
||||||
import "./tests/operations/FromGeohash";
|
import "./tests/Hash";
|
||||||
import "./tests/operations/Hash";
|
import "./tests/HaversineDistance";
|
||||||
import "./tests/operations/HaversineDistance";
|
import "./tests/Hexdump";
|
||||||
import "./tests/operations/Hexdump";
|
import "./tests/Image";
|
||||||
import "./tests/operations/Image";
|
import "./tests/Jump";
|
||||||
import "./tests/operations/Jump";
|
import "./tests/JSONBeautify";
|
||||||
import "./tests/operations/JSONBeautify";
|
import "./tests/JSONMinify";
|
||||||
import "./tests/operations/JSONMinify";
|
import "./tests/JWTDecode";
|
||||||
import "./tests/operations/JWTDecode";
|
import "./tests/JWTSign";
|
||||||
import "./tests/operations/JWTSign";
|
import "./tests/JWTVerify";
|
||||||
import "./tests/operations/JWTVerify";
|
import "./tests/MS";
|
||||||
import "./tests/operations/MS";
|
import "./tests/Magic";
|
||||||
import "./tests/operations/Magic";
|
import "./tests/MorseCode";
|
||||||
import "./tests/operations/MorseCode";
|
import "./tests/NetBIOS";
|
||||||
import "./tests/operations/NetBIOS";
|
import "./tests/OTP";
|
||||||
import "./tests/operations/OTP";
|
import "./tests/PGP";
|
||||||
import "./tests/operations/PGP";
|
import "./tests/PHP";
|
||||||
import "./tests/operations/PHP";
|
import "./tests/ParseIPRange";
|
||||||
import "./tests/operations/ParseIPRange";
|
import "./tests/ParseQRCode";
|
||||||
import "./tests/operations/PowerSet";
|
import "./tests/PowerSet";
|
||||||
import "./tests/operations/Regex";
|
import "./tests/Regex";
|
||||||
import "./tests/operations/Register";
|
import "./tests/Register";
|
||||||
import "./tests/operations/RemoveDiacritics";
|
import "./tests/RemoveDiacritics";
|
||||||
import "./tests/operations/Rotate";
|
import "./tests/Rotate";
|
||||||
import "./tests/operations/SeqUtils";
|
import "./tests/SeqUtils";
|
||||||
import "./tests/operations/SetDifference";
|
import "./tests/SetDifference";
|
||||||
import "./tests/operations/SetIntersection";
|
import "./tests/SetIntersection";
|
||||||
import "./tests/operations/SetUnion";
|
import "./tests/SetUnion";
|
||||||
import "./tests/operations/StrUtils";
|
import "./tests/StrUtils";
|
||||||
import "./tests/operations/SymmetricDifference";
|
import "./tests/SymmetricDifference";
|
||||||
import "./tests/operations/TextEncodingBruteForce";
|
import "./tests/TextEncodingBruteForce";
|
||||||
import "./tests/operations/ToGeohash.mjs";
|
import "./tests/TranslateDateTimeFormat";
|
||||||
import "./tests/operations/TranslateDateTimeFormat";
|
import "./tests/Magic";
|
||||||
import "./tests/operations/Magic";
|
import "./tests/ParseTLV";
|
||||||
import "./tests/operations/ParseTLV";
|
import "./tests/Media";
|
||||||
|
import "./tests/ToFromInsensitiveRegex";
|
||||||
|
import "./tests/YARA.mjs";
|
||||||
|
import "./tests/ConvertCoordinateFormat";
|
||||||
|
|
||||||
|
// Cannot test operations that use the File type yet
|
||||||
|
//import "./tests/SplitColourChannels";
|
||||||
|
|
||||||
let allTestsPassing = true;
|
let allTestsPassing = true;
|
||||||
const testStatusCounts = {
|
const testStatusCounts = {
|
||||||
@@ -153,7 +159,8 @@ TestRegister.runTests()
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!allTestsPassing) {
|
if (!allTestsPassing) {
|
||||||
console.log("\nNot all tests are passing");
|
console.log("\nFailing tests:\n");
|
||||||
|
results.filter(r => r.status !== "passing").forEach(handleTestResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
process.exit(allTestsPassing ? 0 : 1);
|
process.exit(allTestsPassing ? 0 : 1);
|
||||||
@@ -5,7 +5,7 @@
|
|||||||
* @copyright Crown Copyright 2017
|
* @copyright Crown Copyright 2017
|
||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
*/
|
*/
|
||||||
import TestRegister from "../../TestRegister";
|
import TestRegister from "../TestRegister";
|
||||||
|
|
||||||
TestRegister.addTests([
|
TestRegister.addTests([
|
||||||
{
|
{
|
||||||
@@ -6,7 +6,7 @@
|
|||||||
* @copyright Crown Copyright 2018
|
* @copyright Crown Copyright 2018
|
||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
*/
|
*/
|
||||||
import TestRegister from "../../TestRegister";
|
import TestRegister from "../TestRegister";
|
||||||
|
|
||||||
TestRegister.addTests([
|
TestRegister.addTests([
|
||||||
{
|
{
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user