2
0
mirror of https://github.com/gchq/CyberChef synced 2025-12-28 14:13:51 +00:00

Compare commits

...

51 Commits

Author SHA1 Message Date
n1474335
e080c5d72e 9.34.2 2022-03-28 15:57:00 +01:00
n1474335
9cc177a9ad Code quality improvements 2022-03-28 15:56:15 +01:00
n1474335
60b5fe0e76 9.34.1 2022-03-28 15:42:16 +01:00
n1474335
9273f97d88 Updated dependencies 2022-03-28 15:42:11 +01:00
n1474335
98a6baf55a 9.34.0 2022-03-28 11:40:04 +01:00
n1474335
b5677387f5 Updated CHANGELOG 2022-03-28 11:39:57 +01:00
n1474335
cd3eaa4762 Merge branch 'n1073645-variationsOfString' 2022-03-28 11:37:42 +01:00
n1474335
9733bf65de Merge branch 'nodejs16' of https://github.com/john19696/CyberChef into john19696-nodejs16 2022-03-28 11:37:23 +01:00
n1474335
bc433f0234 9.33.1 2022-03-28 11:23:19 +01:00
n1474335
ad7283ee6f Merge branch 'Gitoffthelawn-patch-1' 2022-03-28 11:21:49 +01:00
n1474335
5b941358a9 Merge branch 'patch-1' of https://github.com/Gitoffthelawn/CyberChef into Gitoffthelawn-patch-1 2022-03-28 11:21:22 +01:00
n1474335
f19e898c57 Merge branch 'Wingless-Archangel-patch-1' 2022-03-28 11:20:29 +01:00
n1474335
590ffa184d Merge branch 'patch-1' of https://github.com/Wingless-Archangel/CyberChef into Wingless-Archangel-patch-1 2022-03-28 11:20:10 +01:00
n1474335
46de51512f Merge branch 'adamkdean-patch-1' 2022-03-28 11:15:48 +01:00
n1474335
a13f2f26e4 Merge branch 'patch-1' of https://github.com/adamkdean/CyberChef into adamkdean-patch-1 2022-03-28 11:15:28 +01:00
n1474335
c9c26f6f9f Merge branch 'eljeffeg-patch-1' 2022-03-28 11:13:44 +01:00
n1474335
787c29e42b Merge branch 'patch-1' of https://github.com/eljeffeg/CyberChef into eljeffeg-patch-1 2022-03-28 11:13:26 +01:00
n1474335
1c0b83d833 9.33.0 2022-03-28 10:58:30 +01:00
n1474335
5c767d09b0 Updated CHANGELOG 2022-03-28 10:58:25 +01:00
n1474335
75dba51f56 Improve CJS and ESM module support #1037 2022-03-28 10:52:28 +01:00
n1474335
78a1827af8 Merge branch 'john19696-nodejs16' 2022-03-25 18:33:22 +00:00
n1474335
9e3733b33b Fixed Node imports 2022-03-25 18:28:01 +00:00
n1474335
4ef65589e8 Actions can now be triggered manually 2022-03-25 15:24:21 +00:00
n1474335
cf9e670309 Updated eslint 2022-03-25 15:17:00 +00:00
n1474335
b09f98fbb4 Updated to Node 17 2022-03-25 14:59:54 +00:00
n1474335
e43e010163 Merge branch 'nodejs16' of https://github.com/john19696/CyberChef into john19696-nodejs16 2022-03-25 13:26:31 +00:00
n1073645
2a5cee0bd3 9.32.4 2022-03-23 09:31:17 +00:00
n1073645
c962bb79f5 Updated Dependencies 2022-03-23 09:28:32 +00:00
John L
2e23a33dfc Merge branch 'nodejs16' of https://github.com/john19696/CyberChef into nodejs16 2022-02-04 11:03:05 +00:00
John L
bca296ee37 GitHub actions update 2022-02-04 11:02:52 +00:00
John L
2dbd647868 nodeFlags needs quote change 2022-01-31 11:39:17 +00:00
john19696
2991e7d1fe Update Gruntfile.js
add nodeFlags
2022-01-31 10:31:19 +00:00
John L
f6f12fc193 chromedriver update 2022-01-27 17:18:31 +00:00
john19696
1fac8c1cea Merge pull request #1 from t-8ch/nodejs16
Node 16 compatibility
2022-01-21 15:05:16 +00:00
Adam K Dean
590462e2e4 Fixed Crown Copyright link
Closes #1310
2022-01-18 22:07:59 +00:00
ElJeffe
291c55befd Spelling
Someone noticed this in another project that includes CyberChef
2021-12-14 08:47:55 -05:00
Wingless-Archangel
f630c499d5 Update .gitignore
add .node-version file for supporting [nodeenv](https://github.com/ekalinin/nodeenv)
2021-10-29 14:41:35 +02:00
Thomas Weißschuh
cfc29ef821 Always use mjs imports
This is needed for Node/NPM 16 compat
2021-09-17 08:48:04 +02:00
Thomas Weißschuh
83c6775038 Support json modules
This is need for builds on Node/NPM 16
2021-09-17 08:45:56 +02:00
n1474335
ae1b12c120 9.32.3 2021-09-03 14:58:53 +01:00
n1474335
c423de545f Switch XOR input and output differential logic. Fixes #1155 2021-09-03 14:58:48 +01:00
n1474335
84011371b7 9.32.2 2021-08-26 16:51:50 +01:00
n1474335
f831ec6b7e Fixed issues in Protobuf parsing 2021-08-26 16:51:42 +01:00
n1474335
05bfa9158d 9.32.1 2021-08-19 12:06:30 +01:00
n1474335
649016bc85 Updated dependencies 2021-08-19 12:06:26 +01:00
n1474335
7492b874cf 9.32.0 2021-08-18 17:23:43 +01:00
n1474335
9ea21af61f Updated CHANGELOG 2021-08-18 17:23:38 +01:00
n1474335
dd18e52993 Protobuf operations improved to enable full and partial schema support 2021-08-18 17:22:09 +01:00
Gitoffthelawn
7712ee7f35 Improved consistency
Changed "or" to "and" because all the other sentence sections use "and".
2021-08-11 01:55:47 -07:00
n1073645
c01ce90e06 Tests Added 2020-07-06 11:20:54 +01:00
n1073645
d68c8cb845 Casing Variations 2020-07-06 10:44:05 +01:00
47 changed files with 21356 additions and 8556 deletions

View File

@@ -1,5 +1,5 @@
{
"parser": "babel-eslint",
"parser": "@babel/eslint-parser",
"parserOptions": {
"ecmaVersion": 9,
"ecmaFeatures": {

View File

@@ -1,6 +1,7 @@
name: "CodeQL Analysis"
on:
workflow_dispatch:
push:
branches: [ master ]
pull_request:

View File

@@ -1,6 +1,7 @@
name: "Master Build, Test & Deploy"
on:
workflow_dispatch:
push:
branches:
- master
@@ -14,7 +15,7 @@ jobs:
- name: Set node version
uses: actions/setup-node@v1
with:
node-version: '10.x'
node-version: '17.x'
- name: Install
run: |
@@ -27,7 +28,7 @@ jobs:
- name: Unit Tests
run: |
npm test
npx grunt testnodeconsumer
npm run testnodeconsumer
- name: Production Build
if: success()

View File

@@ -1,6 +1,7 @@
name: "Pull Requests"
on:
workflow_dispatch:
pull_request:
types: [synchronize, opened, reopened]
@@ -13,7 +14,7 @@ jobs:
- name: Set node version
uses: actions/setup-node@v1
with:
node-version: '10.x'
node-version: '17.x'
- name: Install
run: |
@@ -26,7 +27,7 @@ jobs:
- name: Unit Tests
run: |
npm test
npx grunt testnodeconsumer
npm run testnodeconsumer
- name: Production Build
if: success()

View File

@@ -1,6 +1,7 @@
name: "Releases"
on:
workflow_dispatch:
push:
tags:
- 'v*'
@@ -14,7 +15,7 @@ jobs:
- name: Set node version
uses: actions/setup-node@v1
with:
node-version: '10.x'
node-version: '17.x'
- name: Install
run: |
@@ -27,7 +28,7 @@ jobs:
- name: Unit Tests
run: |
npm test
npx grunt testnodeconsumer
npm run testnodeconsumer
- name: Production Build
if: success()

2
.gitignore vendored
View File

@@ -11,4 +11,4 @@ src/node/config/OperationConfig.json
src/node/index.mjs
**/*.DS_Store
tests/browser/output/*
.node-version

2
.nvmrc
View File

@@ -1 +1 @@
lts/dubnium
17

View File

@@ -13,6 +13,16 @@ All major and minor version changes will be documented in this file. Details of
## Details
### [9.34.0] - 2022-03-28
- 'Get All Casings' operation added [@n1073645] | [#1065]
### [9.33.0] - 2022-03-25
- Updated to support Node 17 [@n1474335] [@john19696] [@t-8ch] | [[#1326] [#1313] [#1244]
- Improved CJS and ESM module support [@d98762625] | [#1037]
### [9.32.0] - 2021-08-18
- 'Protobuf Encode' operation added and decode operation modified to allow decoding with full and partial schemas [@n1474335] | [dd18e52]
### [9.31.0] - 2021-08-10
- 'HASSH Client Fingerprint' and 'HASSH Server Fingerprint' operations added [@n1474335] | [e9ca4dc]
@@ -268,6 +278,9 @@ All major and minor version changes will be documented in this file. Details of
[9.34.0]: https://github.com/gchq/CyberChef/releases/tag/v9.34.0
[9.33.0]: https://github.com/gchq/CyberChef/releases/tag/v9.33.0
[9.32.0]: https://github.com/gchq/CyberChef/releases/tag/v9.32.0
[9.31.0]: https://github.com/gchq/CyberChef/releases/tag/v9.31.0
[9.30.0]: https://github.com/gchq/CyberChef/releases/tag/v9.30.0
[9.29.0]: https://github.com/gchq/CyberChef/releases/tag/v9.29.0
@@ -380,11 +393,14 @@ All major and minor version changes will be documented in this file. Details of
[@dmfj]: https://github.com/dmfj
[@mattnotmitt]: https://github.com/mattnotmitt
[@Danh4]: https://github.com/Danh4
[@john19696]: https://github.com/john19696
[@t-8ch]: https://github.com/t-8ch
[8ad18b]: https://github.com/gchq/CyberChef/commit/8ad18bc7db6d9ff184ba3518686293a7685bf7b7
[9a33498]: https://github.com/gchq/CyberChef/commit/9a33498fed26a8df9c9f35f39a78a174bf50a513
[289a417]: https://github.com/gchq/CyberChef/commit/289a417dfb5923de5e1694354ec42a08d9395bfe
[e9ca4dc]: https://github.com/gchq/CyberChef/commit/e9ca4dc9caf98f33fd986431cd400c88082a42b8
[dd18e52]: https://github.com/gchq/CyberChef/commit/dd18e529939078b89867297b181a584e8b2cc7da
[#95]: https://github.com/gchq/CyberChef/pull/299
[#173]: https://github.com/gchq/CyberChef/pull/173
@@ -461,6 +477,11 @@ All major and minor version changes will be documented in this file. Details of
[#999]: https://github.com/gchq/CyberChef/pull/999
[#1006]: https://github.com/gchq/CyberChef/pull/1006
[#1022]: https://github.com/gchq/CyberChef/pull/1022
[#1037]: https://github.com/gchq/CyberChef/pull/1037
[#1045]: https://github.com/gchq/CyberChef/pull/1045
[#1049]: https://github.com/gchq/CyberChef/pull/1049
[#1083]: https://github.com/gchq/CyberChef/pull/1083
[#1065]: https://github.com/gchq/CyberChef/pull/1065
[#1083]: https://github.com/gchq/CyberChef/pull/1083
[#1244]: https://github.com/gchq/CyberChef/pull/1244
[#1313]: https://github.com/gchq/CyberChef/pull/1313
[#1326]: https://github.com/gchq/CyberChef/pull/1326

View File

@@ -6,6 +6,8 @@ const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPl
const glob = require("glob");
const path = require("path");
const nodeFlags = "--experimental-modules --experimental-json-modules --experimental-specifier-resolution=node --no-warnings --no-deprecation";
/**
* Grunt configuration for building the app in various formats.
*
@@ -48,7 +50,7 @@ module.exports = function (grunt) {
grunt.registerTask("testnodeconsumer",
"A task which checks whether consuming CJS and ESM apps work with the CyberChef build",
["exec:setupNodeConsumers", "exec:testCJSNodeConsumer", "exec:testESMNodeConsumer", "exec:testESMDeepImportNodeConsumer", "exec:teardownNodeConsumers"]);
["exec:setupNodeConsumers", "exec:testCJSNodeConsumer", "exec:testESMNodeConsumer", "exec:teardownNodeConsumers"]);
grunt.registerTask("default",
"Lints the code base",
@@ -187,9 +189,6 @@ module.exports = function (grunt) {
standalone: ["build/prod/CyberChef*.html"]
},
eslint: {
options: {
configFile: "./.eslintrc.json"
},
configs: ["*.{js,mjs}"],
core: ["src/core/**/*.{js,mjs}", "!src/core/vendor/**/*", "!src/core/operations/legacy/**/*"],
web: ["src/web/**/*.{js,mjs}", "!src/web/static/**/*"],
@@ -201,50 +200,35 @@ module.exports = function (grunt) {
web: webpackProdConf(),
},
"webpack-dev-server": {
options: {
webpack: webpackConfig,
host: "0.0.0.0",
port: grunt.option("port") || 8080,
disableHostCheck: true,
overlay: true,
inline: false,
clientLogLevel: "error",
stats: {
children: false,
chunks: false,
modules: false,
entrypoints: false,
warningsFilter: [
/source-map/,
/dependency is an expression/,
/export 'default'/,
/Can't resolve 'sodium'/
],
}
},
options: webpackConfig,
start: {
webpack: {
mode: "development",
target: "web",
entry: Object.assign({
main: "./src/web/index.js"
}, moduleEntryPoints),
resolve: {
alias: {
"./config/modules/OpModules.mjs": "./config/modules/Default.mjs"
}
},
plugins: [
new webpack.DefinePlugin(BUILD_CONSTANTS),
new HtmlWebpackPlugin({
filename: "index.html",
template: "./src/web/html/index.html",
chunks: ["main"],
compileTime: compileTime,
version: pkg.version,
})
]
}
mode: "development",
target: "web",
entry: Object.assign({
main: "./src/web/index.js"
}, moduleEntryPoints),
resolve: {
alias: {
"./config/modules/OpModules.mjs": "./config/modules/Default.mjs"
}
},
devServer: {
port: grunt.option("port") || 8080,
client: {
logging: "error",
overlay: 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,
})
]
}
},
zip: {
@@ -349,15 +333,15 @@ module.exports = function (grunt) {
command: "git gc --prune=now --aggressive"
},
sitemap: {
command: "node --experimental-modules --no-warnings --no-deprecation src/web/static/sitemap.mjs > build/prod/sitemap.xml",
command: `node ${nodeFlags} src/web/static/sitemap.mjs > build/prod/sitemap.xml`,
sync: true
},
generateConfig: {
command: chainCommands([
"echo '\n--- Regenerating config files. ---'",
"echo [] > src/core/config/OperationConfig.json",
"node --experimental-modules --no-warnings --no-deprecation src/core/config/scripts/generateOpsIndex.mjs",
"node --experimental-modules --no-warnings --no-deprecation src/core/config/scripts/generateConfig.mjs",
`node ${nodeFlags} src/core/config/scripts/generateOpsIndex.mjs`,
`node ${nodeFlags} src/core/config/scripts/generateConfig.mjs`,
"echo '--- Config scripts finished. ---\n'"
]),
sync: true
@@ -365,7 +349,7 @@ module.exports = function (grunt) {
generateNodeIndex: {
command: chainCommands([
"echo '\n--- Regenerating node index ---'",
"node --experimental-modules --no-warnings --no-deprecation src/node/config/scripts/generateNodeIndex.mjs",
`node ${nodeFlags} src/node/config/scripts/generateNodeIndex.mjs`,
"echo '--- Node index generated. ---\n'"
]),
sync: true
@@ -393,21 +377,14 @@ module.exports = function (grunt) {
testCJSNodeConsumer: {
command: chainCommands([
`cd ${nodeConsumerTestPath}`,
"node --no-warnings cjs-consumer.js",
`node ${nodeFlags} cjs-consumer.js`,
]),
stdout: false,
},
testESMNodeConsumer: {
command: chainCommands([
`cd ${nodeConsumerTestPath}`,
"node --no-warnings --experimental-modules esm-consumer.mjs",
]),
stdout: false,
},
testESMDeepImportNodeConsumer: {
command: chainCommands([
`cd ${nodeConsumerTestPath}`,
"node --no-warnings --experimental-modules esm-deep-import-consumer.mjs",
`node ${nodeFlags} esm-consumer.mjs`,
]),
stdout: false,
},

View File

@@ -2,7 +2,6 @@
[![](https://github.com/gchq/CyberChef/workflows/Master%20Build,%20Test%20&%20Deploy/badge.svg)](https://github.com/gchq/CyberChef/actions?query=workflow%3A%22Master+Build%2C+Test+%26+Deploy%22)
[![Language grade: JavaScript](https://img.shields.io/lgtm/grade/javascript/g/gchq/CyberChef.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/gchq/CyberChef/context:javascript)
[![dependencies Status](https://david-dm.org/gchq/CyberChef/status.svg)](https://david-dm.org/gchq/CyberChef)
[![npm](https://img.shields.io/npm/v/cyberchef.svg)](https://www.npmjs.com/package/cyberchef)
[![](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/gchq/CyberChef/blob/master/LICENSE)
[![Gitter](https://badges.gitter.im/gchq/CyberChef.svg)](https://gitter.im/gchq/CyberChef?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
@@ -10,7 +9,7 @@
#### *The Cyber Swiss Army Knife*
CyberChef is a simple, intuitive web app for carrying out all manner of "cyber" operations within a web browser. These operations include simple encoding like XOR or Base64, more complex encryption like AES, DES and Blowfish, creating binary and hexdumps, compression and decompression of data, calculating hashes and checksums, IPv6 and X.509 parsing, changing character encodings, and much more.
CyberChef is a simple, intuitive web app for carrying out all manner of "cyber" operations within a web browser. These operations include simple encoding like XOR and Base64, more complex encryption like AES, DES and Blowfish, creating binary and hexdumps, compression and decompression of data, calculating hashes and checksums, IPv6 and X.509 parsing, changing character encodings, and much more.
The tool is designed to enable both technical and non-technical analysts to manipulate data in complex ways without having to deal with complex tools or algorithms. It was conceived, designed, built and incrementally improved by an analyst in their 10% innovation time over several years.
@@ -106,7 +105,7 @@ An installation walkthrough, how-to guides for adding new operations and themes,
## Licencing
CyberChef is released under the [Apache 2.0 Licence](https://www.apache.org/licenses/LICENSE-2.0) and is covered by [Crown Copyright](https://www.nationalarchives.gov.uk/information-management/re-using-public-sector-information/copyright-and-re-use/crown-copyright/).
CyberChef is released under the [Apache 2.0 Licence](https://www.apache.org/licenses/LICENSE-2.0) and is covered by [Crown Copyright](https://www.nationalarchives.gov.uk/information-management/re-using-public-sector-information/uk-government-licensing-framework/crown-copyright/).
[1]: https://gchq.github.io/CyberChef

View File

@@ -11,6 +11,7 @@ module.exports = function(api) {
],
"plugins": [
"dynamic-import-node",
"@babel/plugin-syntax-import-assertions",
[
"babel-plugin-transform-builtin-extend", {
"globals": ["Error"]

28613
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "cyberchef",
"version": "9.31.0",
"version": "9.34.2",
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
"author": "n1474335 <n1474335@gmail.com>",
"homepage": "https://gchq.github.io/CyberChef",
@@ -27,118 +27,117 @@
"type": "git",
"url": "https://github.com/gchq/CyberChef/"
},
"main": "src/node/cjs.js",
"module": "src/node/index.mjs",
"main": "src/node/wrapper.js",
"exports": {
"import": "./src/node/index.mjs",
"require": "./src/node/wrapper.js"
},
"bugs": "https://github.com/gchq/CyberChef/issues",
"browserslist": [
"Chrome >= 50",
"Firefox >= 38",
"node >= 10"
"node >= 16"
],
"devDependencies": {
"@babel/core": "^7.12.16",
"@babel/plugin-transform-runtime": "^7.12.15",
"@babel/preset-env": "^7.12.16",
"autoprefixer": "^10.2.4",
"babel-eslint": "^10.1.0",
"babel-loader": "^8.2.2",
"@babel/core": "^7.17.8",
"@babel/eslint-parser": "^7.17.0",
"@babel/plugin-syntax-import-assertions": "^7.16.7",
"@babel/plugin-transform-runtime": "^7.17.0",
"@babel/preset-env": "^7.16.11",
"@babel/runtime": "^7.17.8",
"autoprefixer": "^10.4.4",
"babel-loader": "^8.2.4",
"babel-plugin-dynamic-import-node": "^2.3.3",
"chromedriver": "^92.0.0",
"cli-progress": "^3.9.0",
"chromedriver": "^99.0.0",
"cli-progress": "^3.10.0",
"colors": "^1.4.0",
"copy-webpack-plugin": "^7.0.0",
"css-loader": "^5.0.2",
"eslint": "^7.20.0",
"exports-loader": "^2.0.0",
"file-loader": "^6.2.0",
"grunt": "^1.3.0",
"copy-webpack-plugin": "^10.2.4",
"core-js": "^3.21.1",
"css-loader": "6.7.1",
"eslint": "^8.12.0",
"grunt": "^1.4.1",
"grunt-chmod": "~1.1.1",
"grunt-concurrent": "^3.0.0",
"grunt-contrib-clean": "~2.0.0",
"grunt-contrib-connect": "^3.0.0",
"grunt-contrib-copy": "~1.0.0",
"grunt-contrib-watch": "^1.1.0",
"grunt-eslint": "^23.0.0",
"grunt-eslint": "^24.0.0",
"grunt-exec": "~3.0.0",
"grunt-webpack": "^4.0.2",
"grunt-webpack": "^5.0.0",
"grunt-zip": "^0.18.2",
"html-webpack-plugin": "^5.1.0",
"imports-loader": "^2.0.0",
"mini-css-extract-plugin": "^1.3.7",
"nightwatch": "^1.7.7",
"node-sass": "^5.0.0",
"postcss": "^8.2.6",
"postcss-css-variables": "^0.17.0",
"postcss-import": "^14.0.0",
"postcss-loader": "^5.0.0",
"prompt": "^1.1.0",
"sass-loader": "^11.0.1",
"sitemap": "^6.3.6",
"style-loader": "^2.0.0",
"svg-url-loader": "^7.1.1",
"url-loader": "^4.1.1",
"webpack": "^5.22.0",
"webpack-bundle-analyzer": "^4.4.0",
"webpack-dev-server": "^3.11.2",
"html-webpack-plugin": "^5.5.0",
"imports-loader": "^3.1.1",
"mini-css-extract-plugin": "2.6.0",
"nightwatch": "^2.0.10",
"postcss": "^8.4.12",
"postcss-css-variables": "^0.18.0",
"postcss-import": "^14.1.0",
"postcss-loader": "^6.2.1",
"prompt": "^1.2.2",
"sass-loader": "^12.6.0",
"sitemap": "^7.1.1",
"terser": "^5.12.1",
"webpack": "^5.70.0",
"webpack-bundle-analyzer": "^4.5.0",
"webpack-dev-server": "4.7.4",
"webpack-node-externals": "^3.0.0",
"worker-loader": "^3.0.8"
},
"dependencies": {
"@babel/polyfill": "^7.12.1",
"@babel/runtime": "^7.12.13",
"arrive": "^2.4.1",
"avsc": "^5.5.3",
"avsc": "^5.7.3",
"babel-plugin-transform-builtin-extend": "1.1.2",
"bcryptjs": "^2.4.3",
"bignumber.js": "^9.0.1",
"blakejs": "^1.1.0",
"bootstrap": "4.6.0",
"bootstrap-colorpicker": "^3.2.0",
"bignumber.js": "^9.0.2",
"blakejs": "^1.2.1",
"bootstrap": "4.6.1",
"bootstrap-colorpicker": "^3.4.0",
"bootstrap-material-design": "^4.1.3",
"browserify-zlib": "^0.2.0",
"bson": "^4.2.2",
"bson": "^4.6.2",
"buffer": "^6.0.3",
"cbor": "^5.0.1",
"cbor": "8.1.0",
"chi-squared": "^1.1.0",
"codepage": "^1.14.0",
"core-js": "^3.8.3",
"codepage": "^1.15.0",
"crypto-api": "^0.8.5",
"crypto-browserify": "^3.12.0",
"crypto-js": "^4.0.0",
"crypto-js": "^4.1.1",
"ctph.js": "0.0.5",
"d3": "^6.5.0",
"d3": "7.3.0",
"d3-hexbin": "^0.2.2",
"diff": "^5.0.0",
"es6-promisify": "^6.1.1",
"es6-promisify": "^7.0.0",
"escodegen": "^2.0.0",
"esm": "^3.2.25",
"esprima": "^4.0.1",
"exif-parser": "^0.1.12",
"file-saver": "^2.0.5",
"flat": "^5.0.2",
"geodesy": "1.1.3",
"highlight.js": "^10.6.0",
"highlight.js": "^11.5.0",
"jimp": "^0.16.1",
"jquery": "3.5.1",
"jquery": "3.6.0",
"js-crc": "^0.2.0",
"js-sha3": "^0.8.0",
"jsesc": "^3.0.2",
"jsonpath": "^1.1.1",
"jsonwebtoken": "^8.5.1",
"jsqr": "^1.3.1",
"jsrsasign": "^10.3.0",
"jsqr": "^1.4.0",
"jsrsasign": "^10.5.14",
"kbpgp": "2.1.15",
"libbzip2-wasm": "0.0.4",
"libyara-wasm": "^1.1.0",
"lodash": "^4.17.21",
"loglevel": "^1.7.1",
"loglevel": "^1.8.0",
"loglevel-message-prefix": "^3.0.0",
"markdown-it": "^12.0.4",
"markdown-it": "^12.3.2",
"moment": "^2.29.1",
"moment-timezone": "^0.5.33",
"moment-timezone": "^0.5.34",
"ngeohash": "^0.6.3",
"node-forge": "^0.10.0",
"node-forge": "^1.3.0",
"node-md6": "^0.1.0",
"node-sass": "^7.0.1",
"nodom": "^2.4.0",
"notepack.io": "^2.3.0",
"nwmatcher": "^1.4.4",
@@ -146,35 +145,35 @@
"path": "^0.12.7",
"popper.js": "^1.16.1",
"process": "^0.11.10",
"protobufjs": "^6.11.2",
"qr-image": "^3.2.0",
"scryptsy": "^2.1.0",
"snackbarjs": "^1.1.0",
"sortablejs": "^1.13.0",
"split.js": "^1.6.2",
"ssdeep.js": "0.0.2",
"sortablejs": "^1.15.0",
"split.js": "^1.6.5",
"ssdeep.js": "0.0.3",
"stream-browserify": "^3.0.0",
"terser": "^5.6.0",
"tesseract.js": "2.1.1",
"ua-parser-js": "^0.7.24",
"tesseract.js": "2.1.5",
"ua-parser-js": "^1.0.2",
"unorm": "^1.6.0",
"utf8": "^3.0.0",
"vkbeautify": "^0.99.3",
"xmldom": "^0.6.0",
"xpath": "0.0.32",
"xregexp": "^5.0.1",
"xregexp": "^5.1.0",
"zlibjs": "^0.3.1"
},
"scripts": {
"start": "npx grunt dev",
"build": "npx grunt prod",
"repl": "node src/node/repl.js",
"test": "npx grunt configTests && node --experimental-modules --no-warnings --no-deprecation tests/node/index.mjs && node --experimental-modules --no-warnings --no-deprecation tests/operations/index.mjs",
"test-node-consumer": "npx grunt testnodeconsumer",
"repl": "node --experimental-modules --experimental-json-modules --experimental-specifier-resolution=node --no-warnings src/node/repl.mjs",
"test": "npx grunt configTests && node --experimental-modules --experimental-json-modules --no-warnings --no-deprecation tests/node/index.mjs && node --experimental-modules --experimental-json-modules --no-warnings --no-deprecation tests/operations/index.mjs",
"testnodeconsumer": "npx grunt testnodeconsumer",
"testui": "npx grunt testui",
"testuidev": "npx nightwatch --env=dev",
"lint": "npx grunt lint",
"postinstall": "npx grunt exec:fixCryptoApiImports",
"newop": "node --experimental-modules src/core/config/scripts/newOperation.mjs",
"newop": "node --experimental-modules --experimental-json-modules src/core/config/scripts/newOperation.mjs",
"getheapsize": "node -e 'console.log(`node heap limit = ${require(\"v8\").getHeapStatistics().heap_size_limit / (1024 * 1024)} Mb`)'",
"setheapsize": "export NODE_OPTIONS=--max_old_space_size=2048"
}

View File

@@ -7,7 +7,7 @@
*/
import Chef from "./Chef.mjs";
import OperationConfig from "./config/OperationConfig.json";
import OperationConfig from "./config/OperationConfig.json" assert {type: "json"};
import OpModules from "./config/modules/OpModules.mjs";
// Add ">" to the start of all log messages in the Chef Worker

View File

@@ -4,7 +4,7 @@
* @license Apache-2.0
*/
import OperationConfig from "./config/OperationConfig.json";
import OperationConfig from "./config/OperationConfig.json" assert {type: "json"};
import OperationError from "./errors/OperationError.mjs";
import Operation from "./Operation.mjs";
import DishError from "./errors/DishError.mjs";

View File

@@ -723,7 +723,8 @@ class Utils {
}
if (removeScriptAndStyle) {
htmlStr = recursiveRemove(/<(script|style)[^>]*>.*?<\/(script|style)>/gi, htmlStr);
htmlStr = recursiveRemove(/<script[^>]*>.*?<\/script>/gi, htmlStr);
htmlStr = recursiveRemove(/<style[^>]*>.*?<\/style>/gi, htmlStr);
}
return htmlStr.replace(/<[^>]+>/g, "");
}

2
src/core/config/Categories.json Executable file → Normal file
View File

@@ -191,6 +191,7 @@
"URL Encode",
"URL Decode",
"Protobuf Decode",
"Protobuf Encode",
"VarInt Encode",
"VarInt Decode",
"JA3 Fingerprint",
@@ -229,6 +230,7 @@
"From Case Insensitive Regex",
"Add line numbers",
"Remove line numbers",
"Get All Casings",
"To Table",
"Reverse",
"Sort",

View File

@@ -1,6 +1,6 @@
import OperationError from "./OperationError.mjs";
import DishError from "./DishError.mjs";
import ExcludedOperationError from "./ExcludedOperationError";
import ExcludedOperationError from "./ExcludedOperationError.mjs";
export {
OperationError,

View File

@@ -34,10 +34,10 @@ export function bitOp (input, key, func, nullPreserving, scheme) {
!(nullPreserving && (o === 0 || o === k))) {
switch (scheme) {
case "Input differential":
key[i % key.length] = x;
key[i % key.length] = o;
break;
case "Output differential":
key[i % key.length] = o;
key[i % key.length] = x;
break;
}
}

View File

@@ -1,4 +1,4 @@
import OperationConfig from "../config/OperationConfig.json";
import OperationConfig from "../config/OperationConfig.json" assert {type: "json"};
import Utils, { isWorkerEnvironment } from "../Utils.mjs";
import Recipe from "../Recipe.mjs";
import Dish from "../Dish.mjs";

View File

@@ -1,4 +1,5 @@
import Utils from "../Utils.mjs";
import protobuf from "protobufjs";
/**
* Protobuf lib. Contains functions to decode protobuf serialised
@@ -32,9 +33,10 @@ class Protobuf {
this.MSB = 0x80;
this.VALUE = 0x7f;
// Declare offset and length
// Declare offset, length, and field type object
this.offset = 0;
this.LENGTH = data.length;
this.fieldTypes = {};
}
// Public Functions
@@ -76,15 +78,281 @@ class Protobuf {
return pb._varInt();
}
/**
* Encode input JSON according to the given schema
*
* @param {Object} input
* @param {Object []} args
* @returns {Object}
*/
static encode(input, args) {
this.updateProtoRoot(args[0]);
if (!this.mainMessageName) {
throw new Error("Schema Error: Schema not defined");
}
const message = this.parsedProto.root.nested[this.mainMessageName];
// Convert input into instance of message, and verify instance
input = message.fromObject(input);
const error = message.verify(input);
if (error) {
throw new Error("Input Error: " + error);
}
// Encode input
const output = message.encode(input).finish();
return new Uint8Array(output).buffer;
}
/**
* Parse Protobuf data
*
* @param {byteArray} input
* @returns {Object}
*/
static decode(input) {
static decode(input, args) {
this.updateProtoRoot(args[0]);
this.showUnknownFields = args[1];
this.showTypes = args[2];
return this.mergeDecodes(input);
}
/**
* Update the parsedProto, throw parsing errors
*
* @param {string} protoText
*/
static updateProtoRoot(protoText) {
try {
this.parsedProto = protobuf.parse(protoText);
if (this.parsedProto.package) {
this.parsedProto.root = this.parsedProto.root.nested[this.parsedProto.package];
}
this.updateMainMessageName();
} catch (error) {
throw new Error("Schema " + error);
}
}
/**
* Set mainMessageName to the first instance of a message defined in the schema that is not a submessage
*
*/
static updateMainMessageName() {
const messageNames = [];
const fieldTypes = [];
this.parsedProto.root.nestedArray.forEach(block => {
if (block instanceof protobuf.Type) {
messageNames.push(block.name);
this.parsedProto.root.nested[block.name].fieldsArray.forEach(field => {
fieldTypes.push(field.type);
});
}
});
if (messageNames.length === 0) {
this.mainMessageName = null;
} else {
// for (const name of messageNames) {
// if (!fieldTypes.includes(name)) {
// this.mainMessageName = name;
// break;
// }
// }
this.mainMessageName = messageNames[0];
}
}
/**
* Decode input using Protobufjs package and raw methods, compare, and merge results
*
* @param {byteArray} input
* @returns {Object}
*/
static mergeDecodes(input) {
const pb = new Protobuf(input);
return pb._parse();
let rawDecode = pb._parse();
let message;
if (this.showTypes) {
rawDecode = this.showRawTypes(rawDecode, pb.fieldTypes);
this.parsedProto.root = this.appendTypesToFieldNames(this.parsedProto.root);
}
try {
message = this.parsedProto.root.nested[this.mainMessageName];
const packageDecode = message.toObject(message.decode(input), {
bytes: String,
longs: Number,
enums: String,
defualts: true
});
const output = {};
if (this.showUnknownFields) {
output[message.name] = packageDecode;
output["Unknown Fields"] = this.compareFields(rawDecode, message);
return output;
} else {
return packageDecode;
}
} catch (error) {
if (message) {
throw new Error("Input " + error);
} else {
return rawDecode;
}
}
}
/**
* Replace fieldnames with fieldname and type
*
* @param {Object} schemaRoot
* @returns {Object}
*/
static appendTypesToFieldNames(schemaRoot) {
for (const block of schemaRoot.nestedArray) {
if (block instanceof protobuf.Type) {
for (const [fieldName, fieldData] of Object.entries(block.fields)) {
schemaRoot.nested[block.name].remove(block.fields[fieldName]);
schemaRoot.nested[block.name].add(new protobuf.Field(`${fieldName} (${fieldData.type})`, fieldData.id, fieldData.type, fieldData.rule));
}
}
}
return schemaRoot;
}
/**
* Add field type to field name for fields in the raw decoded output
*
* @param {Object} rawDecode
* @param {Object} fieldTypes
* @returns {Object}
*/
static showRawTypes(rawDecode, fieldTypes) {
for (const [fieldNum, value] of Object.entries(rawDecode)) {
const fieldType = fieldTypes[fieldNum];
let outputFieldValue;
let outputFieldType;
// Submessages
if (isNaN(fieldType)) {
outputFieldType = 2;
// Repeated submessages
if (Array.isArray(value)) {
const fieldInstances = [];
for (const instance of Object.keys(value)) {
if (typeof(value[instance]) !== "string") {
fieldInstances.push(this.showRawTypes(value[instance], fieldType));
} else {
fieldInstances.push(value[instance]);
}
}
outputFieldValue = fieldInstances;
// Single submessage
} else {
outputFieldValue = this.showRawTypes(value, fieldType);
}
// Non-submessage field
} else {
outputFieldType = fieldType;
outputFieldValue = value;
}
// Substitute fieldNum with field number and type
rawDecode[`field #${fieldNum}: ${this.getTypeInfo(outputFieldType)}`] = outputFieldValue;
delete rawDecode[fieldNum];
}
return rawDecode;
}
/**
* Compare raw decode to package decode and return discrepancies
*
* @param rawDecodedMessage
* @param schemaMessage
* @returns {Object}
*/
static compareFields(rawDecodedMessage, schemaMessage) {
// Define message data using raw decode output and schema
const schemaFieldProperties = {};
const schemaFieldNames = Object.keys(schemaMessage.fields);
schemaFieldNames.forEach(field => schemaFieldProperties[schemaMessage.fields[field].id] = field);
// Loop over each field present in the raw decode output
for (const fieldName in rawDecodedMessage) {
let fieldId;
if (isNaN(fieldName)) {
fieldId = fieldName.match(/^field #(\d+)/)[1];
} else {
fieldId = fieldName;
}
// Check if this field is defined in the schema
if (fieldId in schemaFieldProperties) {
const schemaFieldName = schemaFieldProperties[fieldId];
// Extract the current field data from the raw decode and schema
const rawFieldData = rawDecodedMessage[fieldName];
const schemaField = schemaMessage.fields[schemaFieldName];
// Check for repeated fields
if (Array.isArray(rawFieldData) && !schemaField.repeated) {
rawDecodedMessage[`(${schemaMessage.name}) ${schemaFieldName} is a repeated field`] = rawFieldData;
}
// Check for submessage fields
if (schemaField.resolvedType instanceof protobuf.Type) {
const subMessageType = schemaMessage.fields[schemaFieldName].type;
const schemaSubMessage = this.parsedProto.root.nested[subMessageType];
const rawSubMessages = rawDecodedMessage[fieldName];
let rawDecodedSubMessage = {};
// Squash multiple submessage instances into one submessage
if (Array.isArray(rawSubMessages)) {
rawSubMessages.forEach(subMessageInstance => {
const instanceFields = Object.entries(subMessageInstance);
instanceFields.forEach(subField => {
rawDecodedSubMessage[subField[0]] = subField[1];
});
});
} else {
rawDecodedSubMessage = rawSubMessages;
}
// Treat submessage as own message and compare its fields
rawDecodedSubMessage = Protobuf.compareFields(rawDecodedSubMessage, schemaSubMessage);
if (Object.entries(rawDecodedSubMessage).length !== 0) {
rawDecodedMessage[`${schemaFieldName} (${subMessageType}) has missing fields`] = rawDecodedSubMessage;
}
}
delete rawDecodedMessage[fieldName];
}
}
return rawDecodedMessage;
}
/**
* Returns wiretype information for input wiretype number
*
* @param {number} wireType
* @returns {string}
*/
static getTypeInfo(wireType) {
switch (wireType) {
case 0:
return "VarInt (e.g. int32, bool)";
case 1:
return "64-Bit (e.g. fixed64, double)";
case 2:
return "L-delim (e.g. string, message)";
case 5:
return "32-Bit (e.g. fixed32, float)";
}
}
// Private Class Functions
@@ -143,6 +411,11 @@ class Protobuf {
const header = this._fieldHeader();
const type = header.type;
const key = header.key;
if (typeof(this.fieldTypes[key]) !== "object") {
this.fieldTypes[key] = type;
}
switch (type) {
// varint
case 0:
@@ -152,7 +425,7 @@ class Protobuf {
return { "key": key, "value": this._uint64() };
// length delimited
case 2:
return { "key": key, "value": this._lenDelim() };
return { "key": key, "value": this._lenDelim(key) };
// fixed 32
case 5:
return { "key": key, "value": this._uint32() };
@@ -237,10 +510,10 @@ class Protobuf {
* @returns {number}
*/
_uint64() {
// Read off a Uint64
let num = this.data[this.offset++] * 0x1000000 + (this.data[this.offset++] << 16) + (this.data[this.offset++] << 8) + this.data[this.offset++];
num = num * 0x100000000 + this.data[this.offset++] * 0x1000000 + (this.data[this.offset++] << 16) + (this.data[this.offset++] << 8) + this.data[this.offset++];
return num;
// Read off a Uint64 with little-endian
const lowerHalf = this.data[this.offset++] + (this.data[this.offset++] * 0x100) + (this.data[this.offset++] * 0x10000) + this.data[this.offset++] * 0x1000000;
const upperHalf = this.data[this.offset++] + (this.data[this.offset++] * 0x100) + (this.data[this.offset++] * 0x10000) + this.data[this.offset++] * 0x1000000;
return upperHalf * 0x100000000 + lowerHalf;
}
/**
@@ -249,7 +522,7 @@ class Protobuf {
* @private
* @returns {Object|string}
*/
_lenDelim() {
_lenDelim(fieldNum) {
// Read off the field length
const length = this._varInt();
const fieldBytes = this.data.slice(this.offset, this.offset + length);
@@ -258,6 +531,10 @@ class Protobuf {
// Attempt to parse as a new Protobuf Object
const pbObject = new Protobuf(fieldBytes);
field = pbObject._parse();
// Set field types object
this.fieldTypes[fieldNum] = {...this.fieldTypes[fieldNum], ...pbObject.fieldTypes};
} catch (err) {
// Otherwise treat as bytes
field = Utils.byteArrayToChars(fieldBytes);
@@ -276,7 +553,7 @@ class Protobuf {
_uint32() {
// Use a dataview to read off the integer
const dataview = new DataView(new Uint8Array(this.data.slice(this.offset, this.offset + 4)).buffer);
const value = dataview.getUint32(0);
const value = dataview.getUint32(0, true);
this.offset += 4;
return value;
}

View File

@@ -67,7 +67,7 @@ class DeriveEVPKey extends Operation {
iterations = args[2],
hasher = args[3],
salt = Utils.convertToByteString(args[4].string, args[4].option),
key = CryptoJS.EvpKDF(passphrase, salt, {
key = CryptoJS.EvpKDF(passphrase, salt, { // lgtm [js/insufficient-password-hash]
keySize: keySize,
hasher: CryptoJS.algo[hasher],
iterations: iterations,

View File

@@ -0,0 +1,53 @@
/**
* @author n1073645 [n1073645@gmail.com]
* @copyright Crown Copyright 2020
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
/**
* Permutate String operation
*/
class GetAllCasings extends Operation {
/**
* GetAllCasings constructor
*/
constructor() {
super();
this.name = "Get All Casings";
this.module = "Default";
this.description = "Outputs all possible casing variations of a string.";
this.infoURL = "";
this.inputType = "string";
this.outputType = "string";
this.args = [];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const length = input.length;
const max = 1 << length;
input = input.toLowerCase();
let result = "";
for (let i = 0; i < max; i++) {
const temp = input.split("");
for (let j = 0; j < length; j++) {
if (((i >> j) & 1) === 1) {
temp[j] = temp[j].toUpperCase();
}
}
result += temp.join("") + "\n";
}
return result;
}
}
export default GetAllCasings;

View File

@@ -20,12 +20,30 @@ class ProtobufDecode extends Operation {
super();
this.name = "Protobuf Decode";
this.module = "Default";
this.description = "Decodes any Protobuf encoded data to a JSON representation of the data using the field number as the field key.";
this.module = "Protobuf";
this.description = "Decodes any Protobuf encoded data to a JSON representation of the data using the field number as the field key.<br><br>If a .proto schema is defined, the encoded data will be decoded with reference to the schema. Only one message instance will be decoded. <br><br><u>Show Unknown Fields</u><br>When a schema is used, this option shows fields that are present in the input data but not defined in the schema.<br><br><u>Show Types</u><br>Show the type of a field next to its name. For undefined fields, the wiretype and example types are shown instead.";
this.infoURL = "https://wikipedia.org/wiki/Protocol_Buffers";
this.inputType = "ArrayBuffer";
this.outputType = "JSON";
this.args = [];
this.args = [
{
name: "Schema (.proto text)",
type: "text",
value: "",
rows: 8,
hint: "Drag and drop is enabled on this ingredient"
},
{
name: "Show Unknown Fields",
type: "boolean",
value: false
},
{
name: "Show Types",
type: "boolean",
value: false
}
];
}
/**
@@ -36,7 +54,7 @@ class ProtobufDecode extends Operation {
run(input, args) {
input = new Uint8Array(input);
try {
return Protobuf.decode(input);
return Protobuf.decode(input, args);
} catch (err) {
throw new OperationError(err);
}

View File

@@ -0,0 +1,54 @@
/**
* @author GCHQ Contributor [3]
* @copyright Crown Copyright 2021
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import Protobuf from "../lib/Protobuf.mjs";
/**
* Protobuf Encode operation
*/
class ProtobufEncode extends Operation {
/**
* ProtobufEncode constructor
*/
constructor() {
super();
this.name = "Protobuf Encode";
this.module = "Protobuf";
this.description = "Encodes a valid JSON object into a protobuf byte array using the input .proto schema.";
this.infoURL = "https://developers.google.com/protocol-buffers/docs/encoding";
this.inputType = "JSON";
this.outputType = "ArrayBuffer";
this.args = [
{
name: "Schema (.proto text)",
type: "text",
value: "",
rows: 8,
hint: "Drag and drop is enabled on this ingredient"
}
];
}
/**
* @param {Object} input
* @param {Object[]} args
* @returns {ArrayBuffer}
*/
run(input, args) {
try {
return Protobuf.encode(input, args);
} catch (error) {
throw new OperationError(error);
}
}
}
export default ProtobufEncode;

View File

@@ -10,7 +10,7 @@
import NodeDish from "./NodeDish.mjs";
import NodeRecipe from "./NodeRecipe.mjs";
import OperationConfig from "../core/config/OperationConfig.json";
import OperationConfig from "../core/config/OperationConfig.json" assert {type: "json"};
import { sanitise, removeSubheadingsFromArray, sentenceToCamelCase } from "./apiUtils.mjs";
import ExcludedOperationError from "../core/errors/ExcludedOperationError.mjs";

View File

@@ -1,13 +0,0 @@
/**
* Export the main ESM module as CommonJS
*
*
* @author d98762656 [d98762625@gmail.com]
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
/* eslint no-global-assign: ["off"] */
require = require("esm")(module);
module.exports = require("./index.mjs");
module.exports.File = require("./File.mjs");

View File

@@ -41,7 +41,7 @@ let code = `/**
import NodeDish from "./NodeDish.mjs";
import { _wrap, help, bake, _explainExcludedFunction } from "./api.mjs";
import File from "./File.mjs";
import { OperationError, DishError, ExcludedOperationError } from "../core/errors/index";
import { OperationError, DishError, ExcludedOperationError } from "../core/errors/index.mjs";
import {
// import as core_ to avoid name clashes after wrap.
`;
@@ -52,7 +52,7 @@ includedOperations.forEach((op) => {
});
code +=`
} from "../core/operations/index";
} from "../core/operations/index.mjs";
global.File = File;

View File

@@ -7,8 +7,8 @@
* @license Apache-2.0
*/
const chef = require("./cjs.js");
const repl = require("repl");
import chef from "./index.mjs";
import repl from "repl";
/* eslint no-console: ["off"] */

11
src/node/wrapper.js Normal file
View File

@@ -0,0 +1,11 @@
/**
* Export the main ESM module as CommonJS
*
*
* @author d98762656 [d98762625@gmail.com]
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
module.exports = (async () => await import("./index.mjs"))();
module.exports.File = (async () => await import("./File.mjs"))();

View File

@@ -29,7 +29,7 @@
<meta name="description" content="The Cyber Swiss Army Knife - a web app for encryption, encoding, compression and data analysis" />
<meta name="keywords" content="base64, hex, decode, encode, encrypt, decrypt, compress, decompress, regex, regular expressions, hash, crypt, hexadecimal, user agent, url, certificate, x.509, parser, JSON, gzip, md5, sha1, aes, des, blowfish, xor" />
<link rel="icon" type="image/ico" href="<%- require('../static/images/favicon.ico').default %>" />
<link rel="icon" type="image/ico" href="<%- require('../static/images/favicon.ico') %>" />
<script type="application/javascript">
"use strict";
@@ -197,7 +197,7 @@
</button>
<button type="button" class="mx-2 btn btn-lg btn-success btn-raised btn-block" id="bake">
<img aria-hidden="true" src="<%- require('../static/images/cook_male-32x32.png').default %>" alt="Chef Icon"/>
<img aria-hidden="true" src="<%- require('../static/images/cook_male-32x32.png') %>" alt="Chef Icon"/>
<span>Bake!</span>
</button>
@@ -271,7 +271,7 @@
<div class="file-overlay" id="file-overlay"></div>
<div style="position: relative; height: 100%;">
<div class="io-card card">
<img aria-hidden="true" src="<%- require('../static/images/file-128x128.png').default %>" alt="File icon" id="input-file-thumbnail"/>
<img aria-hidden="true" src="<%- require('../static/images/file-128x128.png') %>" alt="File icon" id="input-file-thumbnail"/>
<div class="card-body">
<button type="button" class="close" id="input-file-close">&times;</button>
Name: <span id="input-file-name"></span><br>
@@ -346,12 +346,12 @@
<div id="output-highlighter" class="no-select"></div>
<div id="output-html"></div>
<textarea id="output-text" readonly="readonly" spellcheck="false"></textarea>
<img id="show-file-overlay" aria-hidden="true" src="<%- require('../static/images/file-32x32.png').default %>" alt="Show file overlay" title="Show file overlay"/>
<img id="show-file-overlay" aria-hidden="true" src="<%- require('../static/images/file-32x32.png') %>" alt="Show file overlay" title="Show file overlay"/>
<div id="output-file">
<div class="file-overlay"></div>
<div style="position: relative; height: 100%;">
<div class="io-card card">
<img aria-hidden="true" src="<%- require('../static/images/file-128x128.png').default %>" alt="File icon"/>
<img aria-hidden="true" src="<%- require('../static/images/file-128x128.png') %>" alt="File icon"/>
<div class="card-body">
Size: <span id="output-file-size"></span><br>
<button id="output-file-download" type="button" class="btn btn-primary btn-outline">Download</button>
@@ -626,7 +626,7 @@
<h5 class="modal-title">CyberChef - The Cyber Swiss Army Knife</h5>
</div>
<div class="modal-body">
<img aria-hidden="true" class="about-img-left" src="<%- require('../static/images/cyberchef-128x128.png').default %>" alt="CyberChef Logo"/>
<img aria-hidden="true" class="about-img-left" src="<%- require('../static/images/cyberchef-128x128.png') %>" alt="CyberChef Logo"/>
<p class="subtext">
Version <%= htmlWebpackPlugin.options.version %><br>
Compile time: <%= htmlWebpackPlugin.options.compileTime %>
@@ -749,7 +749,7 @@
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
<a href="https://github.com/gchq/CyberChef">
<img aria-hidden="true" style="position: absolute; top: 0; right: 0; border: 0;" src="<%- require('../static/images/fork_me.png').default %>" alt="Fork me on GitHub">
<img aria-hidden="true" style="position: absolute; top: 0; right: 0; border: 0;" src="<%- require('../static/images/fork_me.png') %>" alt="Fork me on GitHub">
</a>
</div>
</div>

View File

@@ -17,8 +17,8 @@ import * as CanvasComponents from "../core/lib/CanvasComponents.mjs";
// CyberChef
import App from "./App.mjs";
import Categories from "../core/config/Categories.json";
import OperationConfig from "../core/config/OperationConfig.json";
import Categories from "../core/config/Categories.json" assert {type: "json"};
import OperationConfig from "../core/config/OperationConfig.json" assert {type: "json"};
/**

View File

@@ -1,5 +1,5 @@
import sm from "sitemap";
import OperationConfig from "../../core/config/OperationConfig.json";
import OperationConfig from "../../core/config/OperationConfig.json" assert {type: "json"};
/**

View File

@@ -303,7 +303,7 @@
#stale-indicator {
opacity: 1;
visibility: visibile;
visibility: visible;
transition: margin 0s, opacity 0.3s;
margin-left: 5px;
cursor: help;
@@ -316,7 +316,7 @@
#magic {
opacity: 1;
visibility: visibile;
visibility: visible;
transition: margin 0s 0.3s, opacity 0.3s 0.3s, visibility 0.3s 0.3s;
margin-left: 5px;
margin-bottom: 5px;

View File

@@ -71,7 +71,7 @@ module.exports = {
.moveToElement(toHex, 10, 10)
.useCss()
.waitForElementVisible(".popover-body", 1000)
.doubleClick();
.doubleClick("xpath", toHex);
// Confirm that it has been added to the recipe
browser
@@ -90,7 +90,7 @@ module.exports = {
browser
.useCss()
.waitForElementNotVisible("#stale-indicator", 1000)
.expect.element("#output-text").to.have.value.that.equals("44 6f 6e 27 74 20 50 61 6e 69 63 2e");
.expect.element("#output-text").to.have.property("value").that.equals("44 6f 6e 27 74 20 50 61 6e 69 63 2e");
// Clear recipe
browser
@@ -202,11 +202,11 @@ module.exports = {
browser
.getLocationInView(genUUID)
.moveToElement(genUUID, 10, 10)
.doubleClick()
.doubleClick("xpath", genUUID)
.useCss()
.waitForElementVisible(".operation .op-title", 1000)
.waitForElementNotVisible("#stale-indicator", 1000)
.expect.element("#output-text").to.have.value.which.matches(/[\da-f-]{36}/);
.expect.element("#output-text").to.have.property("value").which.matches(/[\da-f-]{36}/);
browser.click("#clr-recipe");
},

View File

@@ -393,13 +393,13 @@ function testOp(browser, opName, input, output, args=[]) {
.click("#clr-recipe")
.click("#clr-io")
.waitForElementNotPresent("#rec-list li.operation")
.expect.element("#input-text").to.have.value.that.equals("");
.expect.element("#input-text").to.have.property("value").that.equals("");
browser
.urlHash("recipe=" + recipeConfig)
.setValue("#input-text", input)
.waitForElementPresent("#rec-list li.operation")
.expect.element("#input-text").to.have.value.that.equals(input);
.expect.element("#input-text").to.have.property("value").that.equals(input);
browser
.waitForElementVisible("#stale-indicator", 5000)
@@ -410,8 +410,8 @@ function testOp(browser, opName, input, output, args=[]) {
.waitForElementNotVisible("#output-loader", 5000);
if (typeof output === "string") {
browser.expect.element("#output-text").to.have.value.that.equals(output);
browser.expect.element("#output-text").to.have.property("value").that.equals(output);
} else if (output instanceof RegExp) {
browser.expect.element("#output-text").to.have.value.that.matches(output);
browser.expect.element("#output-text").to.have.property("value").that.matches(output);
}
}

View File

@@ -6,24 +6,27 @@
* @license Apache-2.0
*/
const chef = require("cyberchef");
const assert = require("assert");
const d = chef.bake("Testing, 1 2 3", [
chef.toHex,
chef.reverse,
{
op: chef.unique,
args: {
delimiter: "Space",
}
},
{
op: chef.multiply,
args: {
delimiter: "Space",
}
}
]);
require("cyberchef").then(chef => {
assert.equal(d.value, "630957449041920");
const d = chef.bake("Testing, 1 2 3", [
chef.toHex,
chef.reverse,
{
op: chef.unique,
args: {
delimiter: "Space",
}
},
{
op: chef.multiply,
args: {
delimiter: "Space",
}
}
]);
assert.equal(d.value, "630957449041920");
});

View File

@@ -7,8 +7,28 @@
*/
import assert from "assert";
import chef from "cyberchef";
import { bake, toHex, reverse, unique, multiply } from "cyberchef";
const d = chef.bake("Testing, 1 2 3", [
const a = bake("Testing, 1 2 3", [
toHex,
reverse,
{
op: unique,
args: {
delimiter: "Space",
}
},
{
op: multiply,
args: {
delimiter: "Space",
}
}
]);
assert.equal(a.value, "630957449041920");
const b = chef.bake("Testing, 1 2 3", [
chef.toHex,
chef.reverse,
{
@@ -25,4 +45,4 @@ const d = chef.bake("Testing, 1 2 3", [
}
]);
assert.equal(d.value, "630957449041920");
assert.equal(b.value, "630957449041920");

View File

@@ -1,28 +0,0 @@
/**
* Tests to ensure that a consuming app can use named imports from deep import patch
*
* @author d98762625 [d98762625@gmail.com]
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
import assert from "assert";
import { bake, toHex, reverse, unique, multiply } from "cyberchef/src/node/index.mjs";
const d = bake("Testing, 1 2 3", [
toHex,
reverse,
{
op: unique,
args: {
delimiter: "Space",
}
},
{
op: multiply,
args: {
delimiter: "Space",
}
}
]);
assert.equal(d.value, "630957449041920");

View File

@@ -1,6 +1,6 @@
import TestRegister from "../../lib/TestRegister.mjs";
import Categories from "../../../src/core/config/Categories.json";
import OperationConfig from "../../../src/core/config/OperationConfig.json";
import Categories from "../../../src/core/config/Categories.json" assert {type: "json"};
import OperationConfig from "../../../src/core/config/OperationConfig.json" assert {type: "json"};
import it from "../assertionHandler.mjs";
import assert from "assert";

View File

@@ -32,7 +32,7 @@ import {
CSSMinify,
toBase64,
toHex
} from "../../../src/node/index";
} from "../../../src/node/index.mjs";
import chef from "../../../src/node/index.mjs";
import TestRegister from "../../lib/TestRegister.mjs";
import File from "../../../src/node/File.mjs";
@@ -685,8 +685,8 @@ Arguments:
it("Parse user agent", () => {
const result = chef.parseUserAgent("Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:47.0) Gecko/20100101 Firefox/47.0 ");
const expected = `Browser
Name: Mozilla
Version: 5.0
Name: Firefox
Version: 47.0
Device
Model: unknown
Type: unknown

View File

@@ -107,7 +107,7 @@ import "./tests/CBORDecode.mjs";
import "./tests/JA3Fingerprint.mjs";
import "./tests/JA3SFingerprint.mjs";
import "./tests/HASSH.mjs";
import "./tests/GetAllCasings.mjs";
// Cannot test operations that use the File type yet
// import "./tests/SplitColourChannels.mjs";

View File

@@ -6,7 +6,7 @@
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister";
import TestRegister from "../../lib/TestRegister.mjs";
TestRegister.addTests([
{

View File

@@ -5,8 +5,8 @@
* @copyright Karsten Silkenbäumer 2019
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister";
import { BACON_ALPHABETS, BACON_TRANSLATIONS } from "../../../src/core/lib/Bacon";
import TestRegister from "../../lib/TestRegister.mjs";
import { BACON_ALPHABETS, BACON_TRANSLATIONS } from "../../../src/core/lib/Bacon.mjs";
const alphabets = Object.keys(BACON_ALPHABETS);
const translations = BACON_TRANSLATIONS;

View File

@@ -0,0 +1,44 @@
/**
* GetAllCasings tests.
*
* @author n1073645 [n1073645@gmail.com]
* @copyright Crown Copyright 2020
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";
TestRegister.addTests([
{
name: "All casings of test",
input: "test",
expectedOutput: "test\nTest\ntEst\nTEst\nteSt\nTeSt\ntESt\nTESt\ntesT\nTesT\ntEsT\nTEsT\nteST\nTeST\ntEST\nTEST\n",
recipeConfig: [
{
"op": "Get All Casings",
"args": []
}
]
},
{
name: "All casings of t",
input: "t",
expectedOutput: "t\nT\n",
recipeConfig: [
{
"op": "Get All Casings",
"args": []
}
]
},
{
name: "All casings of null",
input: "",
expectedOutput: "\n",
recipeConfig: [
{
"op": "Get All Casings",
"args": []
}
]
}
]);

View File

@@ -10,10 +10,10 @@ import TestRegister from "../../lib/TestRegister.mjs";
TestRegister.addTests([
{
name: "Protobuf Decode",
name: "Protobuf Decode: no schema",
input: "0d1c0000001203596f751a024d65202b2a0a0a066162633132331200",
expectedOutput: JSON.stringify({
"1": 469762048,
"1": 28,
"2": "You",
"3": "Me",
"4": 43,
@@ -29,7 +29,277 @@ TestRegister.addTests([
},
{
"op": "Protobuf Decode",
"args": []
"args": ["", false, false]
}
]
},
{
name: "Protobuf Decode: partial schema, no unknown fields",
input: "0d1c0000001203596f751a024d65202b2a0a0a066162633132331200",
expectedOutput: JSON.stringify({
"Apple": [
28
],
"Banana": "You",
"Carrot": [
"Me"
]
}, null, 4),
recipeConfig: [
{
"op": "From Hex",
"args": ["Auto"]
},
{
"op": "Protobuf Decode",
"args": [
`message Test {
repeated fixed32 Apple = 1;
optional string Banana = 2;
repeated string Carrot = 3;
}`,
false,
false
]
}
]
},
{
name: "Protobuf Decode: partial schema, show unknown fields",
input: "0d1c0000001203596f751a024d65202b2a0a0a066162633132331200",
expectedOutput: JSON.stringify({
"Test": {
"Apple": [
28
],
"Banana": "You",
"Carrot": [
"Me"
]
},
"Unknown Fields": {
"4": 43,
"5": {
"1": "abc123",
"2": {}
}
}
}, null, 4),
recipeConfig: [
{
"op": "From Hex",
"args": ["Auto"]
},
{
"op": "Protobuf Decode",
"args": [
`message Test {
repeated fixed32 Apple = 1;
optional string Banana = 2;
repeated string Carrot = 3;
}`,
true,
false
]
}
]
},
{
name: "Protobuf Decode: full schema, no unknown fields",
input: "0d1c0000001203596f751a024d65202b2a0a0a06616263313233120031ff00000000000000",
expectedOutput: JSON.stringify({
"Apple": [
28
],
"Banana": "You",
"Carrot": [
"Me"
],
"Date": 43,
"Elderberry": {
"Fig": "abc123",
"Grape": {}
},
"Huckleberry": 255
}, null, 4),
recipeConfig: [
{
"op": "From Hex",
"args": ["Auto"]
},
{
"op": "Protobuf Decode",
"args": [
`message Test {
repeated fixed32 Apple = 1;
optional string Banana = 2;
repeated string Carrot = 3;
optional int32 Date = 4;
optional subTest Elderberry = 5;
optional fixed64 Huckleberry = 6;
}
message subTest {
optional string Fig = 1;
optional subSubTest Grape = 2;
}
message subSubTest {}`,
false,
false
]
}
]
},
{
name: "Protobuf Decode: partial schema, show unknown fields, show types",
input: "0d1c0000001203596f751a024d65202b2a0a0a06616263313233120031ba32a96cc10200003801",
expectedOutput: JSON.stringify({
"Test": {
"Banana (string)": "You",
"Carrot (string)": [
"Me"
],
"Date (int32)": 43,
"Imbe (Options)": "Option1"
},
"Unknown Fields": {
"field #1: 32-Bit (e.g. fixed32, float)": 28,
"field #5: L-delim (e.g. string, message)": {
"field #1: L-delim (e.g. string, message)": "abc123",
"field #2: L-delim (e.g. string, message)": {}
},
"field #6: 64-Bit (e.g. fixed64, double)": 3029774971578
}
}, null, 4),
recipeConfig: [
{
"op": "From Hex",
"args": ["Auto"]
},
{
"op": "Protobuf Decode",
"args": [
`message Test {
optional string Banana = 2;
repeated string Carrot = 3;
optional int32 Date = 4;
optional Options Imbe = 7;
}
message subTest {
optional string Fig = 1;
optional subSubTest Grape = 2;
}
message subSubTest {}
enum Options {
Option0 = 0;
Option1 = 1;
Option2 = 2;
}`,
true,
true
]
}
]
},
{
name: "Protobuf Encode",
input: JSON.stringify({
"Apple": [
28
],
"Banana": "You",
"Carrot": [
"Me"
],
"Date": 43,
"Elderberry": {
"Fig": "abc123",
"Grape": {}
},
"Huckleberry": [3029774971578],
"Imbe": 1
}, null, 4),
expectedOutput: "0d1c0000001203596f751a024d65202b2a0a0a06616263313233120031ba32a96cc10200003801",
recipeConfig: [
{
"op": "Protobuf Encode",
"args": [
`message Test {
repeated fixed32 Apple = 1;
optional string Banana = 2;
repeated string Carrot = 3;
optional int32 Date = 4;
optional subTest Elderberry = 5;
repeated fixed64 Huckleberry = 6;
optional Options Imbe = 7;
}
message subTest {
optional string Fig = 1;
optional subSubTest Grape = 2;
}
message subSubTest {}
enum Options {
Option0 = 0;
Option1 = 1;
Option2 = 2;
}`
]
},
{
"op": "To Hex",
"args": [
"None",
0
]
}
]
},
{
name: "Protobuf Encode: incomplete schema",
input: JSON.stringify({
"Apple": [
28
],
"Banana": "You",
"Carrot": [
"Me"
],
"Date": 43,
"Elderberry": {
"Fig": "abc123",
"Grape": {}
},
"Huckleberry": [3029774971578],
"Imbe": 1
}, null, 4),
expectedOutput: "1203596f75202b2a0a0a06616263313233120031ba32a96cc1020000",
recipeConfig: [
{
"op": "Protobuf Encode",
"args": [
`message Test {
optional string Banana = 2;
optional int32 Date = 4;
optional subTest Elderberry = 5;
repeated fixed64 Huckleberry = 6;
}
message subTest {
optional string Fig = 1;
optional subSubTest Grape = 2;
}
message subSubTest {}
enum Options {
Option0 = 0;
Option1 = 1;
Option2 = 2;
}`
]
},
{
"op": "To Hex",
"args": [
"None",
0
]
}
]
},

View File

@@ -36,7 +36,8 @@ const banner = `/**
module.exports = {
output: {
publicPath: "",
globalObject: "this"
globalObject: "this",
assetModuleFilename: "assets/[hash][ext][query]"
},
plugins: [
new webpack.ProvidePlugin({
@@ -122,7 +123,7 @@ module.exports = {
},
{
test: /prime.worker.min.js$/,
use: "raw-loader"
type: "asset/source"
},
{
test: /bootstrap-material-design/,
@@ -165,53 +166,33 @@ module.exports = {
"sass-loader",
]
},
/**
* The limit for these files has been increased to 60,000 (60KB)
* to ensure the material icons font is inlined.
*
* See: https://github.com/gchq/CyberChef/issues/612
*/
{
test: /\.(ico|eot|ttf|woff|woff2)$/,
loader: "url-loader",
options: {
limit: 60000,
name: "[hash].[ext]",
outputPath: "assets"
}
type: "asset/resource",
},
{
test: /\.svg$/,
loader: "svg-url-loader",
options: {
encoding: "base64"
}
type: "asset/inline",
},
{ // Store font .fnt and .png files in a separate fonts folder
test: /(\.fnt$|bmfonts\/.+\.png$)/,
loader: "file-loader",
options: {
name: "[name].[ext]",
outputPath: "assets/fonts"
type: "asset/resource",
generator: {
filename: "assets/fonts/[name][ext]"
}
},
{ // First party images are saved as files to be cached
test: /\.(png|jpg|gif)$/,
exclude: /(node_modules|bmfonts)/,
loader: "file-loader",
options: {
name: "images/[name].[ext]"
type: "asset/resource",
generator: {
filename: "images/[name][ext]"
}
},
{ // Third party images are inlined
test: /\.(png|jpg|gif)$/,
exclude: /web\/static/,
loader: "url-loader",
options: {
limit: 10000,
name: "[hash].[ext]",
outputPath: "assets"
}
type: "asset/inline",
},
]
},
@@ -219,14 +200,15 @@ module.exports = {
children: false,
chunks: false,
modules: false,
entrypoints: false,
warningsFilter: [
/source-map/,
/dependency is an expression/,
/export 'default'/,
/Can't resolve 'sodium'/
],
entrypoints: false
},
ignoreWarnings: [
/source-map/,
/source map/,
/dependency is an expression/,
/export 'default'/,
/Can't resolve 'sodium'/
],
performance: {
hints: false
}