2
0
mirror of https://github.com/gchq/CyberChef synced 2026-01-06 10:33:18 +00:00

Compare commits

..

69 Commits

Author SHA1 Message Date
n1474335
1400b5cca4 9.36.0 2022-03-29 12:48:47 +01:00
n1474335
98b5f9cc29 Updated CHANGELOG 2022-03-29 12:48:43 +01:00
n1474335
e766cb009e Merge branch 'hettysymes-SIGABA' 2022-03-29 12:45:56 +01:00
n1474335
993e276858 Tidied up Bletchley ops 2022-03-29 12:45:42 +01:00
n1474335
a762fb4df4 Merge branch 'SIGABA' of https://github.com/hettysymes/CyberChef into hettysymes-SIGABA 2022-03-29 12:26:39 +01:00
n1474335
00781fa459 Fixed lint 2022-03-29 11:55:41 +01:00
n1474335
c6e7367a4e 9.35.1 2022-03-28 17:15:51 +01:00
n1474335
3749bb1222 Merge branch 'AlexAndHisScripts-master' 2022-03-28 17:15:39 +01:00
n1474335
f3c83b2009 Merge branch 'master' of https://github.com/AlexAndHisScripts/CyberChef into AlexAndHisScripts-master 2022-03-28 17:14:57 +01:00
n1474335
d3583c31bc 9.35.0 2022-03-28 16:19:55 +01:00
n1474335
2f638d8c0c Updated CHANGELOG 2022-03-28 16:19:51 +01:00
n1474335
74e43ff65a Merge branch 't-8ch-base45' 2022-03-28 16:18:02 +01:00
n1474335
4f0b160ed3 Tidied up Base45 ops 2022-03-28 16:15:37 +01:00
n1474335
709b8696fc Merge branch 'base45' of https://github.com/t-8ch/CyberChef into t-8ch-base45 2022-03-28 16:04:34 +01:00
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
Thomas Weißschuh
7db1f39473 base45: Implement highlighting 2021-11-09 21:12:49 +01:00
Thomas Weißschuh
6017578964 Add Base45 operations
Closes #1219

Co-developed-by: Cyril Delétré <cyril.deletre@gmail.com>
2021-11-09 21:12:44 +01:00
Alex Chambers_Jones
d2174725a9 Fixed reflected XSS described in issue 1265 2021-10-29 17:59:02 +01: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
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
hettysymes
88947b9d42 Added operation description note and modified comment formatting 2020-06-08 12:27:40 +01:00
hettysymes
3c68ad1302 Modified control rotor stepping so the next control rotor steps once the previous rotor reaches "O" and added tests 2020-06-07 17:45:17 +01:00
hettysymes
e2b3389da6 Added SIGABA simple test 2020-06-06 19:47:15 +01:00
hettysymes
938385c18b Fixed grunt lint errors 2020-06-06 19:46:42 +01:00
hettysymes
5d01b06877 Added copyright and clarified description 2020-06-06 19:46:42 +01:00
hettysymes
f007c093eb Emulation of the WW2 SIGABA machine
I have created an emulation of the SIGABA machine and have tested it against some test data from a Master's thesis by Miao Ai: https://scholarworks.sjsu.edu/cgi/viewcontent.cgi?article=1237&context=etd_projects
2020-06-06 19:46:42 +01:00
59 changed files with 21316 additions and 6415 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,19 @@ All major and minor version changes will be documented in this file. Details of
## Details
### [9.36.0] - 2022-03-29
- 'SIGABA' operation added [@hettysymes] | [#934]
### [9.35.0] - 2022-03-28
- 'To Base45' and 'From Base45' operations added [@t-8ch] | [#1242]
### [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]
@@ -271,6 +284,10 @@ All major and minor version changes will be documented in this file. Details of
[9.36.0]: https://github.com/gchq/CyberChef/releases/tag/v9.36.0
[9.35.0]: https://github.com/gchq/CyberChef/releases/tag/v9.35.0
[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
@@ -384,6 +401,9 @@ 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
[@hettysymes]: https://github.com/hettysymes
[8ad18b]: https://github.com/gchq/CyberChef/commit/8ad18bc7db6d9ff184ba3518686293a7685bf7b7
[9a33498]: https://github.com/gchq/CyberChef/commit/9a33498fed26a8df9c9f35f39a78a174bf50a513
@@ -458,6 +478,7 @@ All major and minor version changes will be documented in this file. Details of
[#865]: https://github.com/gchq/CyberChef/pull/865
[#912]: https://github.com/gchq/CyberChef/pull/912
[#917]: https://github.com/gchq/CyberChef/pull/917
[#934]: https://github.com/gchq/CyberChef/pull/934
[#948]: https://github.com/gchq/CyberChef/pull/948
[#952]: https://github.com/gchq/CyberChef/pull/952
[#965]: https://github.com/gchq/CyberChef/pull/965
@@ -466,6 +487,12 @@ 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
[#1242]: https://github.com/gchq/CyberChef/pull/1242
[#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"]

25855
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "cyberchef",
"version": "9.32.1",
"version": "9.36.0",
"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,30 +27,34 @@
"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.15.0",
"@babel/plugin-transform-runtime": "^7.15.0",
"@babel/preset-env": "^7.15.0",
"autoprefixer": "^10.3.1",
"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.1",
"cli-progress": "^3.9.0",
"chromedriver": "^99.0.0",
"cli-progress": "^3.10.0",
"colors": "^1.4.0",
"copy-webpack-plugin": "^9.0.1",
"css-loader": "5.2.7",
"eslint": "^7.32.0",
"exports-loader": "^3.0.0",
"file-loader": "^6.2.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",
@@ -58,66 +62,60 @@
"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.3",
"grunt-webpack": "^5.0.0",
"grunt-zip": "^0.18.2",
"html-webpack-plugin": "^5.3.2",
"imports-loader": "^3.0.0",
"mini-css-extract-plugin": "1.3.7",
"nightwatch": "^1.7.8",
"node-sass": "^5.0.0",
"postcss": "^8.3.6",
"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.0.2",
"postcss-loader": "^6.1.1",
"prompt": "^1.1.0",
"sass-loader": "^12.1.0",
"sitemap": "^7.0.0",
"style-loader": "^3.2.1",
"svg-url-loader": "^7.1.1",
"url-loader": "^4.1.1",
"webpack": "^5.51.0",
"webpack-bundle-analyzer": "^4.4.2",
"webpack-dev-server": "3.11.2",
"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.15.3",
"arrive": "^2.4.1",
"avsc": "^5.7.3",
"babel-plugin-transform-builtin-extend": "1.1.2",
"bcryptjs": "^2.4.3",
"bignumber.js": "^9.0.1",
"blakejs": "^1.1.1",
"bootstrap": "4.6.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.4.1",
"bson": "^4.6.2",
"buffer": "^6.0.3",
"cbor": "5.0.1",
"cbor": "8.1.0",
"chi-squared": "^1.1.0",
"codepage": "^1.15.0",
"core-js": "^3.16.2",
"crypto-api": "^0.8.5",
"crypto-browserify": "^3.12.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": "^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": "^11.2.0",
"highlight.js": "^11.5.0",
"jimp": "^0.16.1",
"jquery": "3.6.0",
"js-crc": "^0.2.0",
@@ -126,19 +124,20 @@
"jsonpath": "^1.1.1",
"jsonwebtoken": "^8.5.1",
"jsqr": "^1.4.0",
"jsrsasign": "^10.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.2.0",
"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",
@@ -150,13 +149,12 @@
"qr-image": "^3.2.0",
"scryptsy": "^2.1.0",
"snackbarjs": "^1.1.0",
"sortablejs": "^1.14.0",
"split.js": "^1.6.4",
"sortablejs": "^1.15.0",
"split.js": "^1.6.5",
"ssdeep.js": "0.0.3",
"stream-browserify": "^3.0.0",
"terser": "^5.7.1",
"tesseract.js": "2.1.5",
"ua-parser-js": "^0.7.28",
"ua-parser-js": "^1.0.2",
"unorm": "^1.6.0",
"utf8": "^3.0.0",
"vkbeautify": "^0.99.3",
@@ -168,14 +166,14 @@
"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, "");
}
@@ -1206,6 +1207,30 @@ class Utils {
}[token];
}
/**
* Iterate object in chunks of given size.
*
* @param {Iterable} iterable
* @param {number} chunksize
*/
static* chunked(iterable, chunksize) {
const iterator = iterable[Symbol.iterator]();
while (true) {
const res = [];
for (let i = 0; i < chunksize; i++) {
const next = iterator.next();
if (next.done) {
break;
}
res.push(next.value);
}
if (res.length) {
yield res;
} else {
return;
}
}
}
}
/**

View File

@@ -20,6 +20,8 @@
"From Octal",
"To Base32",
"From Base32",
"To Base45",
"From Base45",
"To Base58",
"From Base58",
"To Base62",
@@ -118,7 +120,8 @@
"Multiple Bombe",
"Typex",
"Lorenz",
"Colossus"
"Colossus",
"SIGABA"
]
},
{
@@ -230,6 +233,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,

27
src/core/lib/Base45.mjs Normal file
View File

@@ -0,0 +1,27 @@
/**
* Base45 resources.
*
* @author Thomas Weißschuh [thomas@t-8ch.de]
* @copyright Crown Copyright 2021
* @license Apache-2.0
*/
/**
* Highlight to Base45
*/
export function highlightToBase45(pos, args) {
pos[0].start = Math.floor(pos[0].start / 2) * 3;
pos[0].end = Math.ceil(pos[0].end / 2) * 3;
return pos;
}
/**
* Highlight from Base45
*/
export function highlightFromBase45(pos, args) {
pos[0].start = Math.floor(pos[0].start / 3) * 2;
pos[0].end = Math.ceil(pos[0].end / 3) * 2;
return pos;
}
export const ALPHABET = "0-9A-Z $%*+\\-./:";

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

@@ -6,6 +6,7 @@
*/
import OperationError from "../errors/OperationError.mjs";
import Utils from "../Utils.mjs";
/**
* @constant
@@ -128,7 +129,7 @@ export function getScatterValuesWithColour(input, recordDelimiter, fieldDelimite
if (Number.isNaN(x)) throw new OperationError("Values must be numbers in base 10.");
if (Number.isNaN(y)) throw new OperationError("Values must be numbers in base 10.");
return [x, y, colour];
return [x, y, Utils.escapeHtml(colour)];
});
return { headings, values };

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

@@ -141,7 +141,7 @@ class Protobuf {
const messageNames = [];
const fieldTypes = [];
this.parsedProto.root.nestedArray.forEach(block => {
if (block.constructor.name === "Type") {
if (block instanceof protobuf.Type) {
messageNames.push(block.name);
this.parsedProto.root.nested[block.name].fieldsArray.forEach(field => {
fieldTypes.push(field.type);
@@ -152,12 +152,12 @@ class Protobuf {
if (messageNames.length === 0) {
this.mainMessageName = null;
} else {
for (const name of messageNames) {
if (!fieldTypes.includes(name)) {
this.mainMessageName = name;
break;
}
}
// for (const name of messageNames) {
// if (!fieldTypes.includes(name)) {
// this.mainMessageName = name;
// break;
// }
// }
this.mainMessageName = messageNames[0];
}
}
@@ -213,7 +213,7 @@ class Protobuf {
*/
static appendTypesToFieldNames(schemaRoot) {
for (const block of schemaRoot.nestedArray) {
if (block.constructor.name === "Type") {
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));
@@ -306,7 +306,7 @@ class Protobuf {
}
// Check for submessage fields
if (schemaField.resolvedType !== null && schemaField.resolvedType.constructor.name === "Type") {
if (schemaField.resolvedType instanceof protobuf.Type) {
const subMessageType = schemaMessage.fields[schemaFieldName].type;
const schemaSubMessage = this.parsedProto.root.nested[subMessageType];
const rawSubMessages = rawDecodedMessage[fieldName];

502
src/core/lib/SIGABA.mjs Normal file
View File

@@ -0,0 +1,502 @@
/**
* Emulation of the SIGABA machine
*
* @author hettysymes
* @copyright hettysymes 2020
* @license Apache-2.0
*/
/**
* A set of randomised example SIGABA cipher/control rotors (these rotors are interchangeable). Cipher and control rotors can be referred to as C and R rotors respectively.
*/
export const CR_ROTORS = [
{name: "Example 1", value: "SRGWANHPJZFXVIDQCEUKBYOLMT"},
{name: "Example 2", value: "THQEFSAZVKJYULBODCPXNIMWRG"},
{name: "Example 3", value: "XDTUYLEVFNQZBPOGIRCSMHWKAJ"},
{name: "Example 4", value: "LOHDMCWUPSTNGVXYFJREQIKBZA"},
{name: "Example 5", value: "ERXWNZQIJYLVOFUMSGHTCKPBDA"},
{name: "Example 6", value: "FQECYHJIOUMDZVPSLKRTGWXBAN"},
{name: "Example 7", value: "TBYIUMKZDJSOPEWXVANHLCFQGR"},
{name: "Example 8", value: "QZUPDTFNYIAOMLEBWJXCGHKRSV"},
{name: "Example 9", value: "CZWNHEMPOVXLKRSIDGJFYBTQAU"},
{name: "Example 10", value: "ENPXJVKYQBFZTICAGMOHWRLDUS"}
];
/**
* A set of randomised example SIGABA index rotors (may be referred to as I rotors).
*/
export const I_ROTORS = [
{name: "Example 1", value: "6201348957"},
{name: "Example 2", value: "6147253089"},
{name: "Example 3", value: "8239647510"},
{name: "Example 4", value: "7194835260"},
{name: "Example 5", value: "4873205916"}
];
export const NUMBERS = "0123456789".split("");
/**
* Converts a letter to uppercase (if it already isn't)
*
* @param {char} letter - letter to convert to uppercase
* @returns {char}
*/
export function convToUpperCase(letter) {
const charCode = letter.charCodeAt();
if (97<=charCode && charCode<=122) {
return String.fromCharCode(charCode-32);
}
return letter;
}
/**
* The SIGABA machine consisting of the 3 rotor banks: cipher, control and index banks.
*/
export class SigabaMachine {
/**
* SigabaMachine constructor
*
* @param {Object[]} cipherRotors - list of CRRotors
* @param {Object[]} controlRotors - list of CRRotors
* @param {object[]} indexRotors - list of IRotors
*/
constructor(cipherRotors, controlRotors, indexRotors) {
this.cipherBank = new CipherBank(cipherRotors);
this.controlBank = new ControlBank(controlRotors);
this.indexBank = new IndexBank(indexRotors);
}
/**
* Steps all the correct rotors in the machine.
*/
step() {
const controlOut = this.controlBank.goThroughControl();
const indexOut = this.indexBank.goThroughIndex(controlOut);
this.cipherBank.step(indexOut);
}
/**
* Encrypts a letter. A space is converted to a "Z" before encryption, and a "Z" is converted to an "X". This allows spaces to be encrypted.
*
* @param {char} letter - letter to encrypt
* @returns {char}
*/
encryptLetter(letter) {
letter = convToUpperCase(letter);
if (letter === " ") {
letter = "Z";
} else if (letter === "Z") {
letter = "X";
}
const encryptedLetter = this.cipherBank.encrypt(letter);
this.step();
return encryptedLetter;
}
/**
* Decrypts a letter. A letter decrypted as a "Z" is converted to a space before it is output, since spaces are converted to "Z"s before encryption.
*
* @param {char} letter - letter to decrypt
* @returns {char}
*/
decryptLetter(letter) {
letter = convToUpperCase(letter);
let decryptedLetter = this.cipherBank.decrypt(letter);
if (decryptedLetter === "Z") {
decryptedLetter = " ";
}
this.step();
return decryptedLetter;
}
/**
* Encrypts a message of one or more letters
*
* @param {string} msg - message to encrypt
* @returns {string}
*/
encrypt(msg) {
let ciphertext = "";
for (const letter of msg) {
ciphertext = ciphertext.concat(this.encryptLetter(letter));
}
return ciphertext;
}
/**
* Decrypts a message of one or more letters
*
* @param {string} msg - message to decrypt
* @returns {string}
*/
decrypt(msg) {
let plaintext = "";
for (const letter of msg) {
plaintext = plaintext.concat(this.decryptLetter(letter));
}
return plaintext;
}
}
/**
* The cipher rotor bank consists of 5 cipher rotors in either a forward or reversed orientation.
*/
export class CipherBank {
/**
* CipherBank constructor
*
* @param {Object[]} rotors - list of CRRotors
*/
constructor(rotors) {
this.rotors = rotors;
}
/**
* Encrypts a letter through the cipher rotors (signal goes from left-to-right)
*
* @param {char} inputPos - the input position of the signal (letter to be encrypted)
* @returns {char}
*/
encrypt(inputPos) {
for (const rotor of this.rotors) {
inputPos = rotor.crypt(inputPos, "leftToRight");
}
return inputPos;
}
/**
* Decrypts a letter through the cipher rotors (signal goes from right-to-left)
*
* @param {char} inputPos - the input position of the signal (letter to be decrypted)
* @returns {char}
*/
decrypt(inputPos) {
const revOrderedRotors = [...this.rotors].reverse();
for (const rotor of revOrderedRotors) {
inputPos = rotor.crypt(inputPos, "rightToLeft");
}
return inputPos;
}
/**
* Step the cipher rotors forward according to the inputs from the index rotors
*
* @param {number[]} indexInputs - the inputs from the index rotors
*/
step(indexInputs) {
const logicDict = {0: [0, 9], 1: [7, 8], 2: [5, 6], 3: [3, 4], 4: [1, 2]};
const rotorsToMove = [];
for (const key in logicDict) {
const item = logicDict[key];
for (const i of indexInputs) {
if (item.includes(i)) {
rotorsToMove.push(this.rotors[key]);
break;
}
}
}
for (const rotor of rotorsToMove) {
rotor.step();
}
}
}
/**
* The control rotor bank consists of 5 control rotors in either a forward or reversed orientation. Signals to the control rotor bank always go from right-to-left.
*/
export class ControlBank {
/**
* ControlBank constructor. The rotors have been reversed as signals go from right-to-left through the control rotors.
*
* @param {Object[]} rotors - list of CRRotors
*/
constructor(rotors) {
this.rotors = [...rotors].reverse();
}
/**
* Encrypts a letter.
*
* @param {char} inputPos - the input position of the signal
* @returns {char}
*/
crypt(inputPos) {
for (const rotor of this.rotors) {
inputPos = rotor.crypt(inputPos, "rightToLeft");
}
return inputPos;
}
/**
* Gets the outputs of the control rotors. The inputs to the control rotors are always "F", "G", "H" and "I".
*
* @returns {number[]}
*/
getOutputs() {
const outputs = [this.crypt("F"), this.crypt("G"), this.crypt("H"), this.crypt("I")];
const logicDict = {1: "B", 2: "C", 3: "DE", 4: "FGH", 5: "IJK", 6: "LMNO", 7: "PQRST", 8: "UVWXYZ", 9: "A"};
const numberOutputs = [];
for (const key in logicDict) {
const item = logicDict[key];
for (const output of outputs) {
if (item.includes(output)) {
numberOutputs.push(key);
break;
}
}
}
return numberOutputs;
}
/**
* Steps the control rotors. Only 3 of the control rotors step: one after every encryption, one after every 26, and one after every 26 squared.
*/
step() {
const MRotor = this.rotors[1], FRotor = this.rotors[2], SRotor = this.rotors[3];
// 14 is the offset of "O" from "A" - the next rotor steps once the previous rotor reaches "O"
if (FRotor.state === 14) {
if (MRotor.state === 14) {
SRotor.step();
}
MRotor.step();
}
FRotor.step();
}
/**
* The goThroughControl function combines getting the outputs from the control rotor bank and then stepping them.
*
* @returns {number[]}
*/
goThroughControl() {
const outputs = this.getOutputs();
this.step();
return outputs;
}
}
/**
* The index rotor bank consists of 5 index rotors all placed in the forwards orientation.
*/
export class IndexBank {
/**
* IndexBank constructor
*
* @param {Object[]} rotors - list of IRotors
*/
constructor(rotors) {
this.rotors = rotors;
}
/**
* Encrypts a number.
*
* @param {number} inputPos - the input position of the signal
* @returns {number}
*/
crypt(inputPos) {
for (const rotor of this.rotors) {
inputPos = rotor.crypt(inputPos);
}
return inputPos;
}
/**
* The goThroughIndex function takes the inputs from the control rotor bank and returns the list of outputs after encryption through the index rotors.
*
* @param {number[]} controlInputs - inputs from the control rotors
* @returns {number[]}
*/
goThroughIndex(controlInputs) {
const outputs = [];
for (const inp of controlInputs) {
outputs.push(this.crypt(inp));
}
return outputs;
}
}
/**
* Rotor class
*/
export class Rotor {
/**
* Rotor constructor
*
* @param {number[]} wireSetting - the wirings within the rotor: mapping from left-to-right, the index of the number in the list maps onto the number at that index
* @param {bool} rev - true if the rotor is reversed, false if it isn't
* @param {number} key - the starting position or state of the rotor
*/
constructor(wireSetting, key, rev) {
this.state = key;
this.numMapping = this.getNumMapping(wireSetting, rev);
this.posMapping = this.getPosMapping(rev);
}
/**
* Get the number mapping from the wireSetting (only different from wireSetting if rotor is reversed)
*
* @param {number[]} wireSetting - the wirings within the rotors
* @param {bool} rev - true if reversed, false if not
* @returns {number[]}
*/
getNumMapping(wireSetting, rev) {
if (rev===false) {
return wireSetting;
} else {
const length = wireSetting.length;
const tempMapping = new Array(length);
for (let i=0; i<length; i++) {
tempMapping[wireSetting[i]] = i;
}
return tempMapping;
}
}
/**
* Get the position mapping (how the position numbers map onto the numbers of the rotor)
*
* @param {bool} rev - true if reversed, false if not
* @returns {number[]}
*/
getPosMapping(rev) {
const length = this.numMapping.length;
const posMapping = [];
if (rev===false) {
for (let i = this.state; i < this.state+length; i++) {
let res = i%length;
if (res<0) {
res += length;
}
posMapping.push(res);
}
} else {
for (let i = this.state; i > this.state-length; i--) {
let res = i%length;
if (res<0) {
res += length;
}
posMapping.push(res);
}
}
return posMapping;
}
/**
* Encrypt/decrypt data. This process is identical to the rotors of cipher machines such as Enigma or Typex.
*
* @param {number} inputPos - the input position of the signal (the data to encrypt/decrypt)
* @param {string} direction - one of "leftToRight" and "rightToLeft", states the direction in which the signal passes through the rotor
* @returns {number}
*/
cryptNum(inputPos, direction) {
const inpNum = this.posMapping[inputPos];
let outNum;
if (direction === "leftToRight") {
outNum = this.numMapping[inpNum];
} else if (direction === "rightToLeft") {
outNum = this.numMapping.indexOf(inpNum);
}
const outPos = this.posMapping.indexOf(outNum);
return outPos;
}
/**
* Steps the rotor. The number at position 0 will be moved to position 1 etc.
*/
step() {
const lastNum = this.posMapping.pop();
this.posMapping.splice(0, 0, lastNum);
this.state = this.posMapping[0];
}
}
/**
* A CRRotor is a cipher (C) or control (R) rotor. These rotors are identical and interchangeable. A C or R rotor consists of 26 contacts, one for each letter, and may be put into either a forwards of reversed orientation.
*/
export class CRRotor extends Rotor {
/**
* CRRotor constructor
*
* @param {string} wireSetting - the rotor wirings (string of letters)
* @param {char} key - initial state of rotor
* @param {bool} rev - true if reversed, false if not
*/
constructor(wireSetting, key, rev=false) {
wireSetting = wireSetting.split("").map(CRRotor.letterToNum);
super(wireSetting, CRRotor.letterToNum(key), rev);
}
/**
* Static function which converts a letter into its number i.e. its offset from the letter "A"
*
* @param {char} letter - letter to convert to number
* @returns {number}
*/
static letterToNum(letter) {
return letter.charCodeAt()-65;
}
/**
* Static function which converts a number (a letter's offset from "A") into its letter
*
* @param {number} num - number to convert to letter
* @returns {char}
*/
static numToLetter(num) {
return String.fromCharCode(num+65);
}
/**
* Encrypts/decrypts a letter.
*
* @param {char} inputPos - the input position of the signal ("A" refers to position 0 etc.)
* @param {string} direction - one of "leftToRight" and "rightToLeft"
* @returns {char}
*/
crypt(inputPos, direction) {
inputPos = CRRotor.letterToNum(inputPos);
const outPos = this.cryptNum(inputPos, direction);
return CRRotor.numToLetter(outPos);
}
}
/**
* An IRotor is an index rotor, which consists of 10 contacts each numbered from 0 to 9. Unlike C and R rotors, they cannot be put in the reversed orientation. The index rotors do not step at any point during encryption or decryption.
*/
export class IRotor extends Rotor {
/**
* IRotor constructor
*
* @param {string} wireSetting - the rotor wirings (string of numbers)
* @param {char} key - initial state of rotor
*/
constructor(wireSetting, key) {
wireSetting = wireSetting.split("").map(Number);
super(wireSetting, Number(key), false);
}
/**
* Encrypts a number
*
* @param {number} inputPos - the input position of the signal
* @returns {number}
*/
crypt(inputPos) {
return this.cryptNum(inputPos, "leftToRight");
}
}

View File

@@ -1,6 +1,9 @@
/**
* Emulation of the Bombe machine.
*
* Tested against the Bombe Rebuild at Bletchley Park's TNMOC
* using a variety of inputs and settings to confirm correctness.
*
* @author s2224834
* @copyright Crown Copyright 2019
* @license Apache-2.0

View File

@@ -1,6 +1,9 @@
/**
* Emulation of Colossus.
*
* Tested against the Colossus Rebuild at Bletchley Park's TNMOC
* using a variety of inputs and settings to confirm correctness.
*
* @author VirtualColossus [martin@virtualcolossus.co.uk]
* @copyright Crown Copyright 2019
* @license Apache-2.0

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

@@ -1,6 +1,9 @@
/**
* Emulation of the Enigma machine.
*
* Tested against various genuine Enigma machines using a variety of inputs
* and settings to confirm correctness.
*
* @author s2224834
* @copyright Crown Copyright 2019
* @license Apache-2.0

View File

@@ -0,0 +1,89 @@
/**
* @author Thomas Weißschuh [thomas@t-8ch.de]
* @copyright Crown Copyright 2021
* @license Apache-2.0
*/
import {ALPHABET, highlightToBase45, highlightFromBase45} from "../lib/Base45.mjs";
import Operation from "../Operation.mjs";
import OperationError from "../errors/OperationError.mjs";
import Utils from "../Utils.mjs";
/**
* From Base45 operation
*/
class FromBase45 extends Operation {
/**
* FromBase45 constructor
*/
constructor() {
super();
this.name = "From Base45";
this.module = "Default";
this.description = "Base45 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. The high number base results in shorter strings than with the decimal or hexadecimal system. Base45 is optimized for usage with QR codes.";
this.infoURL = "https://wikipedia.org/wiki/List_of_numeral_systems";
this.inputType = "string";
this.outputType = "byteArray";
this.args = [
{
name: "Alphabet",
type: "string",
value: ALPHABET
}
];
this.highlight = highlightFromBase45;
this.highlightReverse = highlightToBase45;
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {byteArray}
*/
run(input, args) {
if (!input) return [];
const alphabet = Utils.expandAlphRange(args[0]);
const res = [];
for (const triple of Utils.chunked(input, 3)) {
triple.reverse();
let b = 0;
for (const c of triple) {
const idx = alphabet.indexOf(c);
if (idx === -1) {
throw new OperationError(`Character not in alphabet: '${c}'`);
}
b *= 45;
b += idx;
}
if (b > 65535) {
throw new OperationError(`Triplet too large: '${triple.join("")}'`);
}
if (triple.length > 2) {
/**
* The last triple may only have 2 bytes so we push the MSB when we got 3 bytes
* Pushing MSB
*/
res.push(b >> 8);
}
/**
* Pushing LSB
*/
res.push(b & 0xff);
}
return res;
}
}
export default FromBase45;

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

@@ -1,6 +1,9 @@
/**
* Emulation of the Lorenz SZ40/42a/42b cipher attachment.
*
* Tested against the Colossus Rebuild at Bletchley Park's TNMOC
* using a variety of inputs and settings to confirm correctness.
*
* @author VirtualColossus [martin@virtualcolossus.co.uk]
* @copyright Crown Copyright 2019
* @license Apache-2.0

View File

@@ -0,0 +1,287 @@
/**
* Emulation of the SIGABA machine.
*
* @author hettysymes
* @copyright hettysymes 2020
* @license Apache-2.0
*/
import Operation from "../Operation.mjs";
import {LETTERS} from "../lib/Enigma.mjs";
import {NUMBERS, CR_ROTORS, I_ROTORS, SigabaMachine, CRRotor, IRotor} from "../lib/SIGABA.mjs";
/**
* Sigaba operation
*/
class Sigaba extends Operation {
/**
* Sigaba constructor
*/
constructor() {
super();
this.name = "SIGABA";
this.module = "Bletchley";
this.description = "Encipher/decipher with the WW2 SIGABA machine. <br><br>SIGABA, otherwise known as ECM Mark II, was used by the United States for message encryption during WW2 up to the 1950s. It was developed in the 1930s by the US Army and Navy, and has up to this day never been broken. Consisting of 15 rotors: 5 cipher rotors and 10 rotors (5 control rotors and 5 index rotors) controlling the stepping of the cipher rotors, the rotor stepping for SIGABA is much more complex than other rotor machines of its time, such as Enigma. All example rotor wirings are random example sets.<br><br>To configure rotor wirings, for the cipher and control rotors enter a string of letters which map from A to Z, and for the index rotors enter a sequence of numbers which map from 0 to 9. Note that encryption is not the same as decryption, so first choose the desired mode. <br><br> Note: Whilst this has been tested against other software emulators, it has not been tested against hardware.";
this.infoURL = "https://wikipedia.org/wiki/SIGABA";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
name: "1st (left-hand) cipher rotor",
type: "editableOption",
value: CR_ROTORS,
defaultIndex: 0
},
{
name: "1st cipher rotor reversed",
type: "boolean",
value: false
},
{
name: "1st cipher rotor intial value",
type: "option",
value: LETTERS
},
{
name: "2nd cipher rotor",
type: "editableOption",
value: CR_ROTORS,
defaultIndex: 0
},
{
name: "2nd cipher rotor reversed",
type: "boolean",
value: false
},
{
name: "2nd cipher rotor intial value",
type: "option",
value: LETTERS
},
{
name: "3rd (middle) cipher rotor",
type: "editableOption",
value: CR_ROTORS,
defaultIndex: 0
},
{
name: "3rd cipher rotor reversed",
type: "boolean",
value: false
},
{
name: "3rd cipher rotor intial value",
type: "option",
value: LETTERS
},
{
name: "4th cipher rotor",
type: "editableOption",
value: CR_ROTORS,
defaultIndex: 0
},
{
name: "4th cipher rotor reversed",
type: "boolean",
value: false
},
{
name: "4th cipher rotor intial value",
type: "option",
value: LETTERS
},
{
name: "5th (right-hand) cipher rotor",
type: "editableOption",
value: CR_ROTORS,
defaultIndex: 0
},
{
name: "5th cipher rotor reversed",
type: "boolean",
value: false
},
{
name: "5th cipher rotor intial value",
type: "option",
value: LETTERS
},
{
name: "1st (left-hand) control rotor",
type: "editableOption",
value: CR_ROTORS,
defaultIndex: 0
},
{
name: "1st control rotor reversed",
type: "boolean",
value: false
},
{
name: "1st control rotor intial value",
type: "option",
value: LETTERS
},
{
name: "2nd control rotor",
type: "editableOption",
value: CR_ROTORS,
defaultIndex: 0
},
{
name: "2nd control rotor reversed",
type: "boolean",
value: false
},
{
name: "2nd control rotor intial value",
type: "option",
value: LETTERS
},
{
name: "3rd (middle) control rotor",
type: "editableOption",
value: CR_ROTORS,
defaultIndex: 0
},
{
name: "3rd control rotor reversed",
type: "boolean",
value: false
},
{
name: "3rd control rotor intial value",
type: "option",
value: LETTERS
},
{
name: "4th control rotor",
type: "editableOption",
value: CR_ROTORS,
defaultIndex: 0
},
{
name: "4th control rotor reversed",
type: "boolean",
value: false
},
{
name: "4th control rotor intial value",
type: "option",
value: LETTERS
},
{
name: "5th (right-hand) control rotor",
type: "editableOption",
value: CR_ROTORS,
defaultIndex: 0
},
{
name: "5th control rotor reversed",
type: "boolean",
value: false
},
{
name: "5th control rotor intial value",
type: "option",
value: LETTERS
},
{
name: "1st (left-hand) index rotor",
type: "editableOption",
value: I_ROTORS,
defaultIndex: 0
},
{
name: "1st index rotor intial value",
type: "option",
value: NUMBERS
},
{
name: "2nd index rotor",
type: "editableOption",
value: I_ROTORS,
defaultIndex: 0
},
{
name: "2nd index rotor intial value",
type: "option",
value: NUMBERS
},
{
name: "3rd (middle) index rotor",
type: "editableOption",
value: I_ROTORS,
defaultIndex: 0
},
{
name: "3rd index rotor intial value",
type: "option",
value: NUMBERS
},
{
name: "4th index rotor",
type: "editableOption",
value: I_ROTORS,
defaultIndex: 0
},
{
name: "4th index rotor intial value",
type: "option",
value: NUMBERS
},
{
name: "5th (right-hand) index rotor",
type: "editableOption",
value: I_ROTORS,
defaultIndex: 0
},
{
name: "5th index rotor intial value",
type: "option",
value: NUMBERS
},
{
name: "SIGABA mode",
type: "option",
value: ["Encrypt", "Decrypt"]
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const sigabaSwitch = args[40];
const cipherRotors = [];
const controlRotors = [];
const indexRotors = [];
for (let i=0; i<5; i++) {
const rotorWiring = args[i*3];
cipherRotors.push(new CRRotor(rotorWiring, args[i*3+2], args[i*3+1]));
}
for (let i=5; i<10; i++) {
const rotorWiring = args[i*3];
controlRotors.push(new CRRotor(rotorWiring, args[i*3+2], args[i*3+1]));
}
for (let i=15; i<20; i++) {
const rotorWiring = args[i*2];
indexRotors.push(new IRotor(rotorWiring, args[i*2+1]));
}
const sigaba = new SigabaMachine(cipherRotors, controlRotors, indexRotors);
let result;
if (sigabaSwitch === "Encrypt") {
result = sigaba.encrypt(input);
} else if (sigabaSwitch === "Decrypt") {
result = sigaba.decrypt(input);
}
return result;
}
}
export default Sigaba;

View File

@@ -87,7 +87,7 @@ class ScatterChart extends Operation {
const recordDelimiter = Utils.charRep(args[0]),
fieldDelimiter = Utils.charRep(args[1]),
columnHeadingsAreIncluded = args[2],
fillColour = args[5],
fillColour = Utils.escapeHtml(args[5]),
radius = args[6],
colourInInput = args[7],
dimension = 500;

View File

@@ -72,7 +72,10 @@ class SeriesChart extends Operation {
fieldDelimiter = Utils.charRep(args[1]),
xLabel = args[2],
pipRadius = args[3],
seriesColours = args[4].split(","),
// Escape HTML from all colours to prevent reflected XSS. See https://github.com/gchq/CyberChef/issues/1265
seriesColours = args[4].split(",").map((colour) => {
return Utils.escapeHtml(colour);
}),
svgWidth = 500,
interSeriesPadding = 20,
xAxisHeight = 50,

View File

@@ -0,0 +1,78 @@
/**
* @author Thomas Weißschuh [thomas@t-8ch.de]
* @copyright Crown Copyright 2021
* @license Apache-2.0
*/
import {ALPHABET, highlightToBase45, highlightFromBase45} from "../lib/Base45.mjs";
import Operation from "../Operation.mjs";
import Utils from "../Utils.mjs";
/**
* To Base45 operation
*/
class ToBase45 extends Operation {
/**
* ToBase45 constructor
*/
constructor() {
super();
this.name = "To Base45";
this.module = "Default";
this.description = "Base45 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. The high number base results in shorter strings than with the decimal or hexadecimal system. Base45 is optimized for usage with QR codes.";
this.infoURL = "https://wikipedia.org/wiki/List_of_numeral_systems";
this.inputType = "ArrayBuffer";
this.outputType = "string";
this.args = [
{
name: "Alphabet",
type: "string",
value: ALPHABET
}
];
this.highlight = highlightToBase45;
this.highlightReverse = highlightFromBase45;
}
/**
* @param {ArrayBuffer} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
input = new Uint8Array(input);
const alphabet = Utils.expandAlphRange(args[0]);
if (!input) return "";
const res = [];
for (const pair of Utils.chunked(input, 2)) {
let b = 0;
for (const e of pair) {
b *= 256;
b += e;
}
let chars = 0;
do {
res.push(alphabet[b % 45]);
chars++;
b = Math.floor(b / 45);
} while (b > 0);
if (chars < 2) {
res.push("0");
}
}
return res.join("");
}
}
export default ToBase45;

View File

@@ -1,6 +1,9 @@
/**
* Emulation of the Typex machine.
*
* Tested against a genuine Typex machine using a variety of inputs
* and settings to confirm correctness.
*
* @author s2224834
* @copyright Crown Copyright 2019
* @license Apache-2.0

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

@@ -20,6 +20,7 @@ import TestRegister from "../lib/TestRegister.mjs";
import "./tests/BCD.mjs";
import "./tests/BSON.mjs";
import "./tests/BaconCipher.mjs";
import "./tests/Base45.mjs";
import "./tests/Base58.mjs";
import "./tests/Base64.mjs";
import "./tests/Base62.mjs";
@@ -107,6 +108,8 @@ import "./tests/CBORDecode.mjs";
import "./tests/JA3Fingerprint.mjs";
import "./tests/JA3SFingerprint.mjs";
import "./tests/HASSH.mjs";
import "./tests/GetAllCasings.mjs";
import "./tests/SIGABA.mjs";
// Cannot test operations that use the File type yet

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,103 @@
/**
* Base45 tests.
*
* @author Thomas Weißschuh [thomas@t-8ch.de]
*
* @copyright Crown Copyright 2021
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";
const defaultB45Alph = "0-9A-Z $%*+\\-./:";
TestRegister.addTests([
{
name: "To Base45: nothing",
input: "",
expectedOutput: "",
recipeConfig: [
{
op: "To Base45",
args: [defaultB45Alph],
},
],
},
{
name: "To Base45: Spec encoding example 1",
input: "AB",
expectedOutput: "BB8",
recipeConfig: [
{
op: "To Base45",
args: [defaultB45Alph],
},
],
},
{
name: "To Base45: Spec encoding example 2",
input: "Hello!!",
expectedOutput: "%69 VD92EX0",
recipeConfig: [
{
op: "To Base45",
args: [defaultB45Alph],
},
],
},
{
name: "To Base45: Spec encoding example 3",
input: "base-45",
expectedOutput: "UJCLQE7W581",
recipeConfig: [
{
op: "To Base45",
args: [defaultB45Alph],
},
],
},
{
name: "From Base45: nothing",
input: "",
expectedOutput: "",
recipeConfig: [
{
op: "From Base45",
args: [defaultB45Alph],
},
],
},
{
name: "From Base45: Spec decoding example 1",
input: "QED8WEX0",
expectedOutput: "ietf!",
recipeConfig: [
{
op: "From Base45",
args: [defaultB45Alph],
},
],
},
{
name: "From Base45: Invalid character",
input: "!",
expectedOutput: "Character not in alphabet: '!'",
recipeConfig: [
{
op: "From Base45",
args: [defaultB45Alph],
},
],
},
{
name: "From Base45: Invalid triplet value",
input: "ZZZ",
expectedOutput: "Triplet too large: 'ZZZ'",
recipeConfig: [
{
op: "From Base45",
args: [defaultB45Alph],
},
],
},
]);

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

@@ -0,0 +1,91 @@
/**
* SIGABA machine tests
*
* @author hettysymes
* @copyright hettysymes 2020
* @license Apache-2.0
*/
import TestRegister from "../../lib/TestRegister.mjs";
TestRegister.addTests([
{
name: "SIGABA: encrypt test 1",
input: "HELLO WORLD TESTING THE SIGABA MACHINE",
expectedOutput: "ULBECJCZJBJFVUDWAVRGRBMPSQHOTTNVQEESKN",
recipeConfig: [
{
"op": "SIGABA",
"args": [
"BHKWECJDOVAYLFMITUGXRNSPZQ", true, "G",
"CDTAKGQOZXLVJYHSWMIBPRUNEF", false, "L",
"WAXHJZMBVDPOLTUYRCQFNSGKEI", false, "I",
"HUSCWIMJQXDALVGBFTOYZKRPNE", false, "T",
"RTLSMNKXFVWQUZGCHEJBYDAIPO", false, "B",
"GHAQBRJWDMNZTSKLOUXYPFIECV", false, "N",
"VFLGEMTCXZIQDYAKRPBONHWSUJ", true, "Q",
"ZQCAYHRJNXPFLKIOTBUSVWMGDE", false, "B",
"EZVSWPCTULGAOFDJNBIYMXKQHR", false, "J",
"ELKSGDXMVYJUZNCAROQBPWHITF", false, "R",
"3891625740", "3",
"6297135408", "1",
"2389715064", "8",
"9264351708", "6",
"9573086142", "6",
"Encrypt"
]
}
]
},
{
name: "SIGABA: encrypt test 2",
input: "PCRPJZWSPNOHMWANBFBEIVZOXDQESPYDEFBNTHXLSICIRPKUATJVDUQFLZOKGHHHDUDIBRKUHVCGAGLBWVGFFXNDHKPFSPSCIIPCXUFRRHNYWIJFEJWQSGMSNJHWSLPKVXHUQUWIURHDIHIUTWGQFIYLTKEZAUESWYEKIWXUSSXWXBEHCXCUDQWKCISVPKXJVPOIJZWTUGKAORBMKBAQUZOPTSUSYZRROWQUYKNCLHVIHEGWCCONGVHEKCEXVYIPNILIXTXDELNGLJGMEQKKQJWZLPNXPOGIOSVAEAJYKWYJXXGKKPLVYAZGDCMNHMPLCYWDQSRBEMVVVZVFYJMRYGHJOTDOEQVRQOVXOGOVYGTXETFHAYELRYVDGWOFVGAOWPMHQYRZMNXVTAHWSKZLJDFVQPZGMHZWFNOBHSZHEDAEXIFCEEJYZDOEFOQWCXTKPJRUEITKHVCITCLKBUFNAFBYXELAYPBRGGGOCCAGLXXJXTSWCJHMHQPVUIBAGBDKAGEEEPKRGGICJQXSYHBNNAKGYODRAUWAEYHWCKHEQIBAONWQJYQCIFKDTOCTJMBJULWKMSNNMPXINHZQWUMJQLQKIPVZVRGYPCJJZMENWTFTUSPCSPRXHMZPCHCNQTUDCOUJHRKYQIUWWVEVVRYFDIYRQISNGPMQLNMCNMVBEWHNCUODHAGEVEUMKVZLEIKYAMPGVVSBYNRJMFCATDXTQCYXIBCXXKYEYHHYERQGQWZTWCEJBFQLRFFCIVVSZUKGLOTLNGLQNTIKTBBWVFMONUFKRLCJASEKUEEDDQDIVQMFRSJRNHYZJODFHSCJSDAIRUXOSDNFUFUFMNZYQIEGRUXKUPCHENUEZHRKYHDRJYSHLZNYRBWVXORMJMJRIRNSAJQRUMPCXUDFYRGKEAXQXJHPEWNIYIDURDGWIFEMSOFYYCFRZGMZXJNTLTJBBSZIULQSOMEVGCTCVXUHTIEHSPOPQYCJLPAJAPQPAQXE",
expectedOutput: "GMEXPPCMFGKUVGXZHVTCKXRSTJUYWNOKFVELWAHHSJBXGOEXCMLOVSIMCDMGEYMWWTFDUMCDUJEZITNPVVBGQDJEVHJXSKJAAUZWBELMSPUTXCUYPDTJCQXEBGWPWRSQLSNFMASCTJZDSFNKDDTAXLRGUPKCBNXMZPADJSFGGNYKRPYBNTYPTGVPACBEINILNACWFVKMJPGCEZFROEYYKTGYSQYMFSGVDOJJONNYEYSCCIXWLKUSJZDRVAQSNUWHMDJVDNNMPGOYRGQRSBGSPQKGCTFZQWSOXBWSQZDCRQJQAWZDPQEILGMMABIMCDPNSKAFCLPQGIRJCMGQREBEUHBYREXFABFMVZTZBDUMASVNUMHIYRSZLGNZFMVAIABLCUZLJLKKZPWEXDHYZFVSNRLCLNDRKLKSWRHQVQJRTHCNFZXDEXSLAXXOGMFVSGCJGAWOLGDMTLWSFNTCUVCCEACINRZAZZOGLEHHXLPHVKILBBJDPOOCILQKKGODSXOBDPZZDXHJLLBOBVFCHJVMUBUZZIKGCWGCYGXVEHHIJGPEQERWEZLILQNHPHALFKFMGADNELGBKILKIUETGDCBQUEOECWVFNOXTJKUYPWBNEKYSIKMVSAMBZGLIKDAOELRSTKFASEKABTUCPSFEGXXQGDFPSPVOLBHGLZSLLWCABSRKZDQQRKVCKXDGTIHPDNMPDZEXYFYKXZTPJPLYOFNLWAGKJEOHOYLMZELXIDWWNXPKEPUCKNNNHJLFYHPQNHMMCGMUPHSUSYYIVWTIMFKKKTFPGFTLTWWSQBRBMGBTZXPVULKNZIIKVTYLJFISGPTLZFTCLGNZOMVKZOIMUDGXRDDSVFRHRYWBEWHYLCUISYMRWAZZAQPJYXZQQKZLILOSHXUTQJFPTXQSREKSUDZTLGUDLUGOJMQHJRJHXCHQTKJULTWWQOXIRFRQEYBPJPEKXFIRMNATWNFBADOSIJVZYRYDBHDAEDJUVDHLDAU",
recipeConfig: [
{ "op": "SIGABA",
"args": [
"YCHLQSUGBDIXNZKERPVJTAWFOM", true, "A",
"INPXBWETGUYSAOCHVLDMQKZJFR", false, "B",
"WNDRIOZPTAXHFJYQBMSVEKUCGL", false, "C",
"TZGHOBKRVUXLQDMPNFWCJYEIAS", false, "D",
"YWTAHRQJVLCEXUNGBIPZMSDFOK", true, "E",
"QSLRBTEKOGAICFWYVMHJNXZUDP", false, "F",
"CHJDQIGNBSAKVTUOXFWLEPRMZY", false, "G",
"CDFAJXTIMNBEQHSUGRYLWZKVPO", true, "H",
"XHFESZDNRBCGKQIJLTVMUOYAPW", false, "I",
"EZJQXMOGYTCSFRIUPVNADLHWBK", false, "J",
"7591482630", "0",
"3810592764", "1",
"4086153297", "2",
"3980526174", "3",
"6497135280", "4",
"Encrypt"]
}
]
},
{
name: "SIGABA: decrypt test",
input: "AKDHFWAYSLHJDKXEVMJJHGKFTQBZPJPJILOVHMBYOAGBZVLLTQUOIKXFPUFNILBDPCAELMAPSXTLMUEGSDTNUDWGZDADBFELWWHKVPRZNDATDPYEHIDMTGAGPDEZYXFSASVKSBMXVOJQXRMHDBWUNZDTIIIVKHJYPIEUHAJCNBXNLGVFADEWIKXDJZBUTGOQBCQZWYKRVEENWRWWRYDNOAPGMODTPTUJZCLUCRDILJABNTBTWUEIJSJRQBUVCOUJJDWFMNNUHXBDFYXLGUMXQEAWSVHBXQGEOOGPYRVOAJLAIYIOHHEXACDTAWWCBGQRNPERSIKHTXPXKBUNACZLFZTRBMBBDDGKNBIQMFHZROCZZBGNZSJKDRRWPEQHLCFADNPWPWSLPIFNKBWQPMARUERGWUUODXSCOJQECGHIZRFRNRSXWSFWKISHHTUFRVXLHCQWGBMRDHCYDSVNIDDRSTODCGJSSBLUYOBGEWFOVKOZBJTYCAKMZECUGLJGTSZJNBOLTMUZRRSIGGRQHLRPMGLINASSMZOBNACKUMSFNIZAUFCPFXXOOTJQWWLZOFLGZLHJCWZJCRJKVOUDLNMKQATGVTOFHACAEKFLRWRTTMVRXHYGOTYPNBMUSKDAKXFCICUOVSWXGPQOYUUWTWRPQMEQCSDJMMJKELIHGEDYKWOVHVPUAIBFGAODXODXVFIIZIGWRZSBTIGXVHFABMMOPGVMLGHQQXNOEJRDLOBGUOWSELBHERZFSBLUODMOGIBNVGVGQYDBTKLOPNKZZNGLTTGZYYXIBAHZJDCILZXKNSJDHXWTYQLFHTUINTYSBPIXOPLOQHSAHGQPYUWYNPKMRBBBYIICCBBJRKWVLBIDBBEKJCXHLPUBMIGBUFYDPOCSRUNZOKMKJHMYFJZWFNHQZOGGRTNNUVLMRLDSAJIECTYCJKBYVNAXGCMGNVFJEDSATZQDQTYRBPLZKHAXMOVJZEDKINXKBUVWXXHTYUFO",
expectedOutput: "KTSOYDGMLPMVXEAJIATXCNQFXHBNCBXIJOCQGCQBRQSBYFOOEVPVXACBMIUIRNVMJHREKRHBSXJFSMWCKTTCYXJOFSJCQECXXCHTEGPEYSMYDHCSMODUAVBNLILYUIBBIXJCXXNQPCERRSMJTPQLMOXSKTRPWOFUSWXOYRJLBIJGIOYTEAEJEGGYAGSXNHNQTETANPWEGATHSBFLHCVHVIJUAKDVGQCWUSIFFFVAJYPJAFUYDXSLGPGESOUAYXBQIIOXWTXNOXLNCGWSUKVIBMOUGNHORYLSNVNNJLKKFDUAEISOLBLCXYHMDGVBVVVIKDLTMTDVWWJBXWXROVTJBXXKXLEWTTISKIUMYSACVUGGNANMCGUMFNQUXDLTHJNYTFIQEPKQQQSSROYJOILJYQXICXACWGOHCSHENXJILOMIIFCIOUDXDCINIVKIRJCVHWXSFQXMNRBJJWTPXNJADEOPEJBLKHKXNTORIRVRLXUXXAMKMODBXNLQCVJXVOTBRHXBBVJHPFEQFCRXYRRXHXPTXXSUESUTHUGOWQYQPQFPXQPVGEIRPQNKXXMBHIPECRUWFEWJUTYIKSMJSRQIQAIAMXTGDXSJIABHIGKUPJBCHWMVYTMQNQYGDHCNMBSVTPXNFRELFXXQYIOLCDEXDXDVSINICOXRMNSPICPQMOBIDJCNBJKXFAVMUXOXHERJIBIXLMXXULDXKXXHAQDXEXIWXOEEUGKSUGCMRWJDPYCYKXTPCOXMURAJCPRXKFJAJALERWRHVMFHOGMFHXGSXQDPJCJNXRQFGHKRCYTEBJDHPCMYFEAPWSVVMMBVUJJMCAAYURHUPVQVJYDCSNMQEMNIFEXYXIIXBVRVILXAUCBDXRJHGPKPYXHPPPNVSBBCDRLVVIYPKAKYIXTJVYDGVPHXULWMADBEICNIFKWUOOHEFNANDKOXMCVBVORLQYNXLULOEGVGWNKNMOHYVRSYSOVYGAKCGAWKGAIAQNQR",
recipeConfig: [
{ "op": "SIGABA",
"args": [
"YCHLQSUGBDIXNZKERPVJTAWFOM", true, "A",
"INPXBWETGUYSAOCHVLDMQKZJFR", false, "B",
"WNDRIOZPTAXHFJYQBMSVEKUCGL", false, "C",
"TZGHOBKRVUXLQDMPNFWCJYEIAS", false, "D",
"YWTAHRQJVLCEXUNGBIPZMSDFOK", true, "E",
"QSLRBTEKOGAICFWYVMHJNXZUDP", false, "F",
"CHJDQIGNBSAKVTUOXFWLEPRMZY", false, "G",
"CDFAJXTIMNBEQHSUGRYLWZKVPO", true, "H",
"XHFESZDNRBCGKQIJLTVMUOYAPW", false, "I",
"EZJQXMOGYTCSFRIUPVNADLHWBK", false, "J",
"7591482630", "0",
"3810592764", "1",
"4086153297", "2",
"3980526174", "3",
"6497135280", "4",
"Decrypt"]
}
]
}
]);

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
}