mirror of
https://github.com/gchq/CyberChef
synced 2026-01-05 18:13:15 +00:00
Compare commits
496 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
31a4eef001 | ||
|
|
d6e2c9a6b9 | ||
|
|
e069f5db13 | ||
|
|
96b59cf0df | ||
|
|
c1e1d4b7e3 | ||
|
|
32d869231e | ||
|
|
6f95f01dda | ||
|
|
61a1c44f26 | ||
|
|
e6c7899569 | ||
|
|
a74a14145e | ||
|
|
04022b22be | ||
|
|
4f3010691c | ||
|
|
672b477751 | ||
|
|
19360391a6 | ||
|
|
447be8af34 | ||
|
|
0989550e5c | ||
|
|
4d9b48b4d8 | ||
|
|
979652387d | ||
|
|
de84fbdd1c | ||
|
|
170e564319 | ||
|
|
530836876f | ||
|
|
1abc46058c | ||
|
|
892a3716ed | ||
|
|
5d982a9c8d | ||
|
|
6206224f1e | ||
|
|
766310e2c7 | ||
|
|
02a397d2ae | ||
|
|
4563c86acd | ||
|
|
0a59f8068e | ||
|
|
24548e3a48 | ||
|
|
f4784d49e7 | ||
|
|
14d5069c6e | ||
|
|
9fdd55c5c6 | ||
|
|
5bc523aeff | ||
|
|
3ae2e2e2c8 | ||
|
|
83e49da7f6 | ||
|
|
fe6df8778f | ||
|
|
69073c9d99 | ||
|
|
d5a0adea0c | ||
|
|
1bcb8e433d | ||
|
|
fa05cf1d78 | ||
|
|
63dff0d34d | ||
|
|
e228b197f9 | ||
|
|
4bbeb6caa3 | ||
|
|
139d25dff9 | ||
|
|
6984258404 | ||
|
|
ba66fd6546 | ||
|
|
47bbefd81f | ||
|
|
50f796049c | ||
|
|
618da545b1 | ||
|
|
21236f1938 | ||
|
|
4169a15066 | ||
|
|
6b10f61e11 | ||
|
|
83f119f7e4 | ||
|
|
041c899a35 | ||
|
|
5412fc01b3 | ||
|
|
76926d9252 | ||
|
|
3270961574 | ||
|
|
9a1ef71aec | ||
|
|
ba878925ad | ||
|
|
8d6b71bfaa | ||
|
|
b6845aa03c | ||
|
|
4a673bd92a | ||
|
|
fdffabfdd4 | ||
|
|
ba8591293b | ||
|
|
9b3aae10cf | ||
|
|
5c85c4df63 | ||
|
|
8ece2603fb | ||
|
|
1b54584820 | ||
|
|
3ce3866000 | ||
|
|
becc258b6c | ||
|
|
16c9e7119d | ||
|
|
f5888fea9c | ||
|
|
b5162c7549 | ||
|
|
1baea1da3d | ||
|
|
40899a6fe4 | ||
|
|
66c533431d | ||
|
|
74ae77f17a | ||
|
|
99eb1cced5 | ||
|
|
c880ecf3c4 | ||
|
|
c54c34d88e | ||
|
|
60b3c597a7 | ||
|
|
372ab32539 | ||
|
|
e14745a973 | ||
|
|
afffe584cf | ||
|
|
cf532f1e30 | ||
|
|
46425ba552 | ||
|
|
9f65fac4e6 | ||
|
|
af98feff51 | ||
|
|
339c741a2c | ||
|
|
d1bde23f00 | ||
|
|
be544faf0f | ||
|
|
eff77fd3bb | ||
|
|
3df57ba3dd | ||
|
|
4bae662357 | ||
|
|
357c90546e | ||
|
|
54769a90ac | ||
|
|
0550aedd54 | ||
|
|
5947ed21fc | ||
|
|
0a0949246f | ||
|
|
09c6e181fb | ||
|
|
02cf394bcd | ||
|
|
46afbf9888 | ||
|
|
7cf19d22a8 | ||
|
|
46d708360f | ||
|
|
7ec91e2366 | ||
|
|
a74ee47bf0 | ||
|
|
7b68b92498 | ||
|
|
274f3acd45 | ||
|
|
53dff8b30f | ||
|
|
9892ee273e | ||
|
|
7dccecb336 | ||
|
|
aa09da0403 | ||
|
|
98d7f1481c | ||
|
|
7d8bdbcf7e | ||
|
|
db009d3689 | ||
|
|
d7bc529a95 | ||
|
|
3f035294a6 | ||
|
|
36282e362f | ||
|
|
223353cf4d | ||
|
|
ded32da632 | ||
|
|
d6fc21cc34 | ||
|
|
b86e960456 | ||
|
|
7747bfe0f2 | ||
|
|
fabea8cc61 | ||
|
|
de4cd2eebc | ||
|
|
e16ce1d9c2 | ||
|
|
345ad741b3 | ||
|
|
e53108c493 | ||
|
|
6129378854 | ||
|
|
11a1416dcc | ||
|
|
9025538544 | ||
|
|
46929e1844 | ||
|
|
bf023cad48 | ||
|
|
f649236bad | ||
|
|
54b1454c0a | ||
|
|
a41b1c2f5e | ||
|
|
0327d7cb7a | ||
|
|
621d7c3683 | ||
|
|
ae7c3fca31 | ||
|
|
1b3295ff59 | ||
|
|
e40e7a0e4e | ||
|
|
cf5fd7cbf2 | ||
|
|
ec37a676a8 | ||
|
|
f33193e122 | ||
|
|
7c40204e4f | ||
|
|
2b2ffb3346 | ||
|
|
39b7e4ff9e | ||
|
|
a1109c43f6 | ||
|
|
887ea0cf06 | ||
|
|
3e0525ee9e | ||
|
|
e6eafc2843 | ||
|
|
3e8dea73d2 | ||
|
|
bbf19ee944 | ||
|
|
f6c8c9e76c | ||
|
|
9dba1232b7 | ||
|
|
bf14c8983f | ||
|
|
3ab95384df | ||
|
|
953a581a94 | ||
|
|
3bfddd708c | ||
|
|
13a54ec318 | ||
|
|
2781640a2a | ||
|
|
7989f119d3 | ||
|
|
2e0aa7ae87 | ||
|
|
0b5ee7c79f | ||
|
|
23cbe1c426 | ||
|
|
de727bcddc | ||
|
|
c9d9730726 | ||
|
|
a380aed878 | ||
|
|
4dafa50799 | ||
|
|
d4ae241758 | ||
|
|
53e69835ff | ||
|
|
939208903a | ||
|
|
7526f4d7b1 | ||
|
|
616b38c6fb | ||
|
|
a302df8f91 | ||
|
|
093512a55a | ||
|
|
007224c92e | ||
|
|
738ee33959 | ||
|
|
d720a6b250 | ||
|
|
5ce3cc17bb | ||
|
|
5c35205315 | ||
|
|
10751934e4 | ||
|
|
d658f91106 | ||
|
|
fae96af17d | ||
|
|
57c1a03c4f | ||
|
|
cb8fe42c66 | ||
|
|
7f4b2574b0 | ||
|
|
fad163e0eb | ||
|
|
7ad3992bd1 | ||
|
|
e7b5c0e37c | ||
|
|
cc35127459 | ||
|
|
1c0ecd29c2 | ||
|
|
1f0fddd0e9 | ||
|
|
18c6b9bc09 | ||
|
|
2233b9a094 | ||
|
|
e0f000b913 | ||
|
|
73864e0809 | ||
|
|
cd8a85975c | ||
|
|
2f94ec20b0 | ||
|
|
09d9deae43 | ||
|
|
4c3324aea1 | ||
|
|
ac2fcee90f | ||
|
|
94e00115fe | ||
|
|
29255d2338 | ||
|
|
39278cfce7 | ||
|
|
46cc48cfb9 | ||
|
|
eb4009949d | ||
|
|
57c48a4bd2 | ||
|
|
45011de494 | ||
|
|
5e51ed0a5f | ||
|
|
875802ef2a | ||
|
|
bbc255ef83 | ||
|
|
fc155ec3fc | ||
|
|
3a0c8a199a | ||
|
|
9c729c4490 | ||
|
|
19bdbd66e5 | ||
|
|
ea090f79ee | ||
|
|
1be6c54be2 | ||
|
|
a4eeb226b1 | ||
|
|
d136717636 | ||
|
|
ad0a2e6f58 | ||
|
|
0212bfb46e | ||
|
|
5e0d661542 | ||
|
|
4c5f529ef4 | ||
|
|
b765534b8b | ||
|
|
7c672c5ee9 | ||
|
|
090bf3f8ec | ||
|
|
9f4ef9cdad | ||
|
|
26fa66ef64 | ||
|
|
b69e4567c0 | ||
|
|
26b19350f2 | ||
|
|
2018b7e247 | ||
|
|
cbff4161a1 | ||
|
|
130bdfb7f2 | ||
|
|
d0c43f5aa9 | ||
|
|
f864a5f31e | ||
|
|
ff585584f6 | ||
|
|
2e0af64ac3 | ||
|
|
8a029e5147 | ||
|
|
4251089687 | ||
|
|
dbcd670ca8 | ||
|
|
cecae671d8 | ||
|
|
b4e23ac454 | ||
|
|
e7209ca085 | ||
|
|
022ef71d2c | ||
|
|
0fad891a3a | ||
|
|
47f608b502 | ||
|
|
4ab745f730 | ||
|
|
1f89ac11d2 | ||
|
|
1a5dae76c2 | ||
|
|
032c7f529a | ||
|
|
707818abcc | ||
|
|
58e8b4c618 | ||
|
|
9c0c2867dd | ||
|
|
4308c717c3 | ||
|
|
30bc8dfbe9 | ||
|
|
342b67581b | ||
|
|
75da5b650c | ||
|
|
5b6a53be3e | ||
|
|
5b5105c864 | ||
|
|
9d09146f68 | ||
|
|
1b19d20d0c | ||
|
|
0eacab5ddc | ||
|
|
0d7874bac1 | ||
|
|
5cddfafbd0 | ||
|
|
5ce133c47e | ||
|
|
53a579028c | ||
|
|
570a84b67a | ||
|
|
a68bfd7223 | ||
|
|
fd7176a445 | ||
|
|
0a06472639 | ||
|
|
3f3a7cd4f6 | ||
|
|
99415359d0 | ||
|
|
54cb2d268b | ||
|
|
0e40daecb6 | ||
|
|
21a822b082 | ||
|
|
a770d09687 | ||
|
|
27b81c4e11 | ||
|
|
8826c80e07 | ||
|
|
02e3ce7fc1 | ||
|
|
673e6aede5 | ||
|
|
5809dea0fc | ||
|
|
165ca9ebc1 | ||
|
|
154b9386f7 | ||
|
|
62dd7c3dbc | ||
|
|
82d098fc1a | ||
|
|
c69ac7f0f2 | ||
|
|
5578f4577d | ||
|
|
28bd8a32e3 | ||
|
|
24fd35e6af | ||
|
|
c4493d15b6 | ||
|
|
f9ef9739b0 | ||
|
|
d50b9103c2 | ||
|
|
196a611c9b | ||
|
|
7c057ad254 | ||
|
|
cced384e0a | ||
|
|
cce7abecd5 | ||
|
|
8013b3b5e9 | ||
|
|
64b979e25e | ||
|
|
5e7b004925 | ||
|
|
1e791d7f1b | ||
|
|
a255d1912c | ||
|
|
3d1266f815 | ||
|
|
ede78c540f | ||
|
|
c0f003b450 | ||
|
|
14190fc533 | ||
|
|
9f34009244 | ||
|
|
bc2fefd1b2 | ||
|
|
940b56ba5f | ||
|
|
8f2a1f5b2c | ||
|
|
20d0ae5304 | ||
|
|
2ba37af109 | ||
|
|
728f8e65d6 | ||
|
|
d78730edc0 | ||
|
|
b0d2593968 | ||
|
|
38a033f1a9 | ||
|
|
846ad1796a | ||
|
|
355a6d6b76 | ||
|
|
6090842372 | ||
|
|
0a3bd6456c | ||
|
|
ab6576d739 | ||
|
|
d5615b90bb | ||
|
|
cf1349ccb2 | ||
|
|
36190f1967 | ||
|
|
3ecbe22d99 | ||
|
|
b045dc37f5 | ||
|
|
015d0f065f | ||
|
|
d7cc6c7363 | ||
|
|
a5bc1c6f9e | ||
|
|
c2212f9ab3 | ||
|
|
3fb5bf14a6 | ||
|
|
f32b7d5de5 | ||
|
|
7a58567659 | ||
|
|
4be0a436f2 | ||
|
|
1e71fc91a1 | ||
|
|
0ab96dd4ca | ||
|
|
1509b2b96c | ||
|
|
4430ea55c4 | ||
|
|
4b6cebc068 | ||
|
|
a06303c2fd | ||
|
|
115b064081 | ||
|
|
1197859865 | ||
|
|
293a95e938 | ||
|
|
9a3464a5ec | ||
|
|
55dddd3ef9 | ||
|
|
23956480b7 | ||
|
|
6dbaf6a36c | ||
|
|
1d8c7dcb97 | ||
|
|
41c8a5aff0 | ||
|
|
597fba2fd0 | ||
|
|
0f0674daf6 | ||
|
|
d9b7fe2bb9 | ||
|
|
ace8121d0e | ||
|
|
f7be8d720b | ||
|
|
0a5038e533 | ||
|
|
5feba30956 | ||
|
|
23a228bbd9 | ||
|
|
598813ff88 | ||
|
|
118f0130d8 | ||
|
|
e77d3a4b7d | ||
|
|
bf0bd620f1 | ||
|
|
62edd76d7e | ||
|
|
cef6585cab | ||
|
|
481241b88d | ||
|
|
93c0c7cc10 | ||
|
|
01d9536bbd | ||
|
|
24a7c75926 | ||
|
|
c2eea7a9f7 | ||
|
|
e2812cadb5 | ||
|
|
cde958af16 | ||
|
|
bf70589b3c | ||
|
|
78d1114869 | ||
|
|
ab83caa77b | ||
|
|
42dd03bb84 | ||
|
|
cb09949fb9 | ||
|
|
0c6eac3b21 | ||
|
|
5e771c521c | ||
|
|
b8afbf7458 | ||
|
|
be59efbd6b | ||
|
|
99ccd06f23 | ||
|
|
f4d75f88a9 | ||
|
|
9112bd4936 | ||
|
|
3e513efd59 | ||
|
|
4100a22c7f | ||
|
|
71078d9332 | ||
|
|
72ba579e1e | ||
|
|
5fd2512a9b | ||
|
|
3a1a6a94d2 | ||
|
|
928178716a | ||
|
|
08419a20c0 | ||
|
|
60506ee2d1 | ||
|
|
6e411c9dd9 | ||
|
|
86db43e6dd | ||
|
|
252ac0bdaa | ||
|
|
4d8b1721bc | ||
|
|
fd390bc61b | ||
|
|
813a151524 | ||
|
|
c06502cd76 | ||
|
|
974ce1fd12 | ||
|
|
d2dc50fe8e | ||
|
|
ec50105e34 | ||
|
|
86ebed132d | ||
|
|
47ccafcbb2 | ||
|
|
9f901188af | ||
|
|
ccdd2af8be | ||
|
|
a387db6109 | ||
|
|
b88a35cd14 | ||
|
|
bcafaebf77 | ||
|
|
798f013219 | ||
|
|
61e6423d95 | ||
|
|
c32fec6b53 | ||
|
|
4c0d944992 | ||
|
|
57ee3f305d | ||
|
|
61ab9a904f | ||
|
|
820bd2f867 | ||
|
|
44c2b71e6c | ||
|
|
b806be3f49 | ||
|
|
2750284eea | ||
|
|
5366f1a2eb | ||
|
|
32625dc0b0 | ||
|
|
dfc8f517f2 | ||
|
|
b459c15d74 | ||
|
|
8a02b35d7d | ||
|
|
d4441823aa | ||
|
|
13e9a4f0da | ||
|
|
33471a33d6 | ||
|
|
a6fa0628f2 | ||
|
|
8e5aa2c393 | ||
|
|
1118ff598d | ||
|
|
09e93b4639 | ||
|
|
d16bbe1e7e | ||
|
|
4814922e67 | ||
|
|
81d1007bb7 | ||
|
|
610d46a1a4 | ||
|
|
f7acef4642 | ||
|
|
fd5b6c5243 | ||
|
|
a8917e4713 | ||
|
|
04036e001e | ||
|
|
725b0d42f8 | ||
|
|
071c1bdea6 | ||
|
|
7386c145ef | ||
|
|
25ca8d85a6 | ||
|
|
c60ed2c403 | ||
|
|
7d41d4d030 | ||
|
|
6d77fe6eb3 | ||
|
|
40d3c8b071 | ||
|
|
02ec4a3bfd | ||
|
|
7a4ebbf47e | ||
|
|
2e7ce477d7 | ||
|
|
c1a22ef639 | ||
|
|
0a7b78b7ee | ||
|
|
e1cb62848c | ||
|
|
acf5c733c2 | ||
|
|
7c25e29515 | ||
|
|
7c72871c02 | ||
|
|
ddb77c6ab3 | ||
|
|
8502fd246d | ||
|
|
30c6917914 | ||
|
|
33464b3388 | ||
|
|
2205637ad6 | ||
|
|
149198ef1c | ||
|
|
2c40353180 | ||
|
|
a62a6c2aa4 | ||
|
|
4be06f6779 | ||
|
|
03f4740968 | ||
|
|
ea6d80edfb | ||
|
|
68e8a221ff | ||
|
|
cce84c3782 | ||
|
|
c1878ca28b | ||
|
|
e9b7a43b9a | ||
|
|
3921b4f445 | ||
|
|
dfd4cca43f | ||
|
|
69c6c3e790 | ||
|
|
4541d75f49 | ||
|
|
9eda670026 | ||
|
|
d3c13b118d | ||
|
|
8e2345cf9e | ||
|
|
d240d65c5f | ||
|
|
462f619f43 | ||
|
|
ef61735f64 | ||
|
|
a2780ca056 | ||
|
|
d025c8bd9a | ||
|
|
acf38e47ba | ||
|
|
4122d4207d | ||
|
|
d550ae7d93 | ||
|
|
815a542cc1 | ||
|
|
123a0ccd70 | ||
|
|
4c737475d4 | ||
|
|
4e0d97f2c1 | ||
|
|
85906cafbb | ||
|
|
a8dc691033 | ||
|
|
4d7988b78e | ||
|
|
841e760b04 | ||
|
|
31e758ca45 | ||
|
|
f81ca3ba60 |
@@ -47,6 +47,7 @@
|
|||||||
"block-spacing": "error",
|
"block-spacing": "error",
|
||||||
"array-bracket-spacing": "error",
|
"array-bracket-spacing": "error",
|
||||||
"comma-spacing": "error",
|
"comma-spacing": "error",
|
||||||
|
"spaced-comment": ["error", "always", { "exceptions": ["/"] } ],
|
||||||
"comma-style": "error",
|
"comma-style": "error",
|
||||||
"computed-property-spacing": "error",
|
"computed-property-spacing": "error",
|
||||||
"no-trailing-spaces": "warn",
|
"no-trailing-spaces": "warn",
|
||||||
@@ -62,7 +63,8 @@
|
|||||||
}],
|
}],
|
||||||
"linebreak-style": ["error", "unix"],
|
"linebreak-style": ["error", "unix"],
|
||||||
"quotes": ["error", "double", {
|
"quotes": ["error", "double", {
|
||||||
"avoidEscape": true
|
"avoidEscape": true,
|
||||||
|
"allowTemplateLiterals": true
|
||||||
}],
|
}],
|
||||||
"camelcase": ["error", {
|
"camelcase": ["error", {
|
||||||
"properties": "always"
|
"properties": "always"
|
||||||
|
|||||||
32
.github/workflows/codeql.yml
vendored
Normal file
32
.github/workflows/codeql.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
name: "CodeQL Analysis"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
# The branches below must be a subset of the branches above
|
||||||
|
branches: [ master ]
|
||||||
|
schedule:
|
||||||
|
- cron: '22 17 * * 5'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
name: Analyze
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
language: [ 'javascript' ]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v1
|
||||||
|
with:
|
||||||
|
languages: ${{ matrix.language }}
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v1
|
||||||
54
.github/workflows/master.yml
vendored
Normal file
54
.github/workflows/master.yml
vendored
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
name: "Master Build, Test & Deploy"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
main:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Set node version
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: '10.x'
|
||||||
|
|
||||||
|
- name: Install
|
||||||
|
run: |
|
||||||
|
npm install
|
||||||
|
export NODE_OPTIONS=--max_old_space_size=2048
|
||||||
|
|
||||||
|
- name: Lint
|
||||||
|
run: npx grunt lint
|
||||||
|
|
||||||
|
- name: Unit Tests
|
||||||
|
run: |
|
||||||
|
npm test
|
||||||
|
npx grunt testnodeconsumer
|
||||||
|
|
||||||
|
- name: Production Build
|
||||||
|
if: success()
|
||||||
|
run: npx grunt prod
|
||||||
|
|
||||||
|
- name: Generate sitemap
|
||||||
|
run: npx grunt exec:sitemap
|
||||||
|
|
||||||
|
- name: UI Tests
|
||||||
|
if: success()
|
||||||
|
run: xvfb-run --server-args="-screen 0 1200x800x24" npx grunt testui
|
||||||
|
|
||||||
|
- name: Prepare for GitHub Pages
|
||||||
|
if: success()
|
||||||
|
run: npx grunt copy:ghPages
|
||||||
|
|
||||||
|
- name: Deploy to GitHub Pages
|
||||||
|
if: success() && github.ref == 'refs/heads/master'
|
||||||
|
uses: crazy-max/ghaction-github-pages@v2
|
||||||
|
with:
|
||||||
|
target_branch: gh-pages
|
||||||
|
build_dir: ./build/prod
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
37
.github/workflows/pull_requests.yml
vendored
Normal file
37
.github/workflows/pull_requests.yml
vendored
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
name: "Pull Requests"
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [synchronize, opened, reopened]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
main:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Set node version
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: '10.x'
|
||||||
|
|
||||||
|
- name: Install
|
||||||
|
run: |
|
||||||
|
npm install
|
||||||
|
export NODE_OPTIONS=--max_old_space_size=2048
|
||||||
|
|
||||||
|
- name: Lint
|
||||||
|
run: npx grunt lint
|
||||||
|
|
||||||
|
- name: Unit Tests
|
||||||
|
run: |
|
||||||
|
npm test
|
||||||
|
npx grunt testnodeconsumer
|
||||||
|
|
||||||
|
- name: Production Build
|
||||||
|
if: success()
|
||||||
|
run: npx grunt prod
|
||||||
|
|
||||||
|
- name: UI Tests
|
||||||
|
if: success()
|
||||||
|
run: xvfb-run --server-args="-screen 0 1200x800x24" npx grunt testui
|
||||||
56
.github/workflows/releases.yml
vendored
Normal file
56
.github/workflows/releases.yml
vendored
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
name: "Releases"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tags:
|
||||||
|
- 'v*'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
main:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Set node version
|
||||||
|
uses: actions/setup-node@v1
|
||||||
|
with:
|
||||||
|
node-version: '10.x'
|
||||||
|
|
||||||
|
- name: Install
|
||||||
|
run: |
|
||||||
|
npm install
|
||||||
|
export NODE_OPTIONS=--max_old_space_size=2048
|
||||||
|
|
||||||
|
- name: Lint
|
||||||
|
run: npx grunt lint
|
||||||
|
|
||||||
|
- name: Unit Tests
|
||||||
|
run: |
|
||||||
|
npm test
|
||||||
|
npx grunt testnodeconsumer
|
||||||
|
|
||||||
|
- name: Production Build
|
||||||
|
if: success()
|
||||||
|
run: npx grunt prod
|
||||||
|
|
||||||
|
- name: UI Tests
|
||||||
|
if: success()
|
||||||
|
run: xvfb-run --server-args="-screen 0 1200x800x24" npx grunt testui
|
||||||
|
|
||||||
|
- name: Upload Release Assets
|
||||||
|
if: success()
|
||||||
|
id: upload-release-assets
|
||||||
|
uses: svenstaro/upload-release-action@v2
|
||||||
|
with:
|
||||||
|
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
file: build/prod/*.zip
|
||||||
|
tag: ${{ github.ref }}
|
||||||
|
overwrite: true
|
||||||
|
file_glob: true
|
||||||
|
body: "See the [CHANGELOG](https://github.com/gchq/CyberChef/blob/master/CHANGELOG.md) and [commit messages](https://github.com/gchq/CyberChef/commits/master) for details."
|
||||||
|
|
||||||
|
- name: Publish to NPM
|
||||||
|
if: success()
|
||||||
|
uses: JS-DevTools/npm-publish@v1
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.NPM_TOKEN }}
|
||||||
54
.travis.yml
54
.travis.yml
@@ -1,54 +0,0 @@
|
|||||||
language: node_js
|
|
||||||
node_js:
|
|
||||||
- lts/dubnium
|
|
||||||
cache: npm
|
|
||||||
addons:
|
|
||||||
chrome: stable
|
|
||||||
install: npm install
|
|
||||||
before_script:
|
|
||||||
- npm install -g grunt
|
|
||||||
- export NODE_OPTIONS=--max_old_space_size=2048
|
|
||||||
script:
|
|
||||||
- grunt lint
|
|
||||||
- grunt test
|
|
||||||
- grunt testnodeconsumer
|
|
||||||
- grunt prod --msg="$COMPILE_MSG"
|
|
||||||
- xvfb-run --server-args="-screen 0 1200x800x24" grunt testui
|
|
||||||
before_deploy:
|
|
||||||
- grunt exec:sitemap
|
|
||||||
- grunt copy:ghPages
|
|
||||||
deploy:
|
|
||||||
- provider: pages
|
|
||||||
skip_cleanup: true
|
|
||||||
github_token: $GITHUB_TOKEN
|
|
||||||
local_dir: build/prod/
|
|
||||||
target_branch: gh-pages
|
|
||||||
on:
|
|
||||||
repo: gchq/CyberChef
|
|
||||||
branch: master
|
|
||||||
- provider: releases
|
|
||||||
skip_cleanup: true
|
|
||||||
api_key:
|
|
||||||
secure: "HV1WSKv4l/0Y2bKKs1iBJocBcmLj08PCRUeEM/jTwA4jqJ8EiLHWiXtER/D5sEg2iibRVKd2OQjfrmS6bo4AiwdeVgAKmv0FtS2Jw+391N8Nd5AkEANHa5Om/IpHLTL2YRAjpJTsDpY72bMUTJIwjQA3TFJkgrpOw6KYfohOcgbxLpZ4XuNJRU3VL4Hsxdv5V9aOVmfFOmMOVPQlakXy7NgtW5POp1f2WJwgcZxylkR1CjwaqMyXmSoVl46pyH3tr5+dptsQoKSGdi6sIHGA60oDotFPcm+0ifa47wZw+vapuuDi4tdNxhrHGaDMG8xiE0WFDHwQUDlk2/+W7j9SEX0H3Em7us371JXRp56EDwEcDa34VpVkC6i8HGcHK55hnxVbMZXGf3qhOFD8wY7qMbjMRvIpucrMHBi86OfkDfv0vDj2LyvIl5APj/AX50BrE0tfH1MZbH26Jkx4NdlkcxQ14GumarmUqfmVvbX/fsoA6oUuAAE9ZgRRi3KHO4wci6KUcRfdm+XOeUkaBFsL86G3EEYIvrtBTuaypdz+Cx7nd1iPZyWMx5Y1gXnVzha4nBdV4+7l9JIsFggD8QVpw2uHXQiS1KXFjOeqA3DBD8tjMB7q26Fl2fD3jkOo4BTbQ2NrRIZUu/iL+fOmMPsyMt2qulB0yaSBCfkbEq8xrUA="
|
|
||||||
file_glob: true
|
|
||||||
file:
|
|
||||||
- build/prod/*.zip
|
|
||||||
- src/node/cjs.js
|
|
||||||
on:
|
|
||||||
repo: gchq/CyberChef
|
|
||||||
tags: true
|
|
||||||
- provider: npm
|
|
||||||
skip_cleanup: true
|
|
||||||
email: "n1474335@gmail.com"
|
|
||||||
api_key:
|
|
||||||
secure: "UnDQL3Kh+GK2toL0TK3FObO0ujVssU3Eg4BBuYdjwLB81GhiGE5/DTh7THdZPOpbLo6wQeOwfZDuMeKC1OU+0Uf4NsdYFu1aq6xMO20qBQ4qUfgsyiK4Qgywj9gk0p1+OFZdGAZ/j1CNRAaF71XQIY6iV84c+SO4WoizXYrNT0Jh4sr2DA4/97G2xmJtPi0qOzYrJ09R56ZUozmqeik5G0pMRIuJRbpjS/7bZXV+N7WV0ombZc9RkUaetbabEVOLQ+Xx5YAIVq+VuEeMe9VBSnxY/FfCLmy1wJsjGzpLCyBI9nbrG4nw8Wgc2m8NfK9rcpIvBTGner9r2j60NVDkZ8kLZPrqXhq6AZMwa+oz6K5UQCqRo2RRQzSGwXxg67HY5Tcq+oNmjd+DqpPg4LZ3eGlluyP5XfG+hpSr9Ya4d8q8SrUWLxkoLHI6ZKMtoKFbTCSSQPiluW5hsZxjz3yDkkjsJw64M/EM8UyJrgaXqDklQu+7rBGKLfsK6os7RDiqjBWpQ7gwpo8HvY0O8yqEAabPz+QGkanpjcCOZCXFbSkzWxYy37RMAPu88iINVZVlZE4l+WJenCpZY95ueyy0mG9cyMSzVRPyX6A+/n4H6VMFPFjpGDLTD588ACEjY1lmHfS/eXwXJcgqPPD2gW0XdRdUheU/ssqlfCfGWQMTDXs="
|
|
||||||
on:
|
|
||||||
tags: true
|
|
||||||
branch: master
|
|
||||||
notifications:
|
|
||||||
webhooks:
|
|
||||||
urls:
|
|
||||||
- https://webhooks.gitter.im/e/83c143a6822e218d5b34
|
|
||||||
on_success: change
|
|
||||||
on_failure: always
|
|
||||||
on_start: never
|
|
||||||
93
CHANGELOG.md
93
CHANGELOG.md
@@ -1,7 +1,63 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## Versioning
|
||||||
|
|
||||||
|
CyberChef uses the [semver](https://semver.org/) system to manage versioning: `<MAJOR>.<MINOR>.<PATCH>`.
|
||||||
|
|
||||||
|
- MAJOR version changes represent a significant change to the fundamental architecture of CyberChef and may (but don't always) make breaking changes that are not backwards compatible.
|
||||||
|
- MINOR version changes usually mean the addition of new operations or reasonably significant new features.
|
||||||
|
- PATCH versions are used for bug fixes and any other small tweaks that modify or improve existing capabilities.
|
||||||
|
|
||||||
All major and minor version changes will be documented in this file. Details of patch-level version changes can be found in [commit messages](https://github.com/gchq/CyberChef/commits/master).
|
All major and minor version changes will be documented in this file. Details of patch-level version changes can be found in [commit messages](https://github.com/gchq/CyberChef/commits/master).
|
||||||
|
|
||||||
|
|
||||||
|
## Details
|
||||||
|
|
||||||
|
### [9.26.0] - 2021-02-11
|
||||||
|
- 'Get Time' operation added [@n1073645] [@n1474335] | [#1045]
|
||||||
|
|
||||||
|
### [9.25.0] - 2021-02-11
|
||||||
|
- 'Extract ID3' operation added [@n1073645] [@n1474335] | [#1006]
|
||||||
|
|
||||||
|
### [9.24.0] - 2021-02-02
|
||||||
|
- 'SM3' hashing function added along with more configuration options for other hashing operations [@n1073645] [@n1474335] | [#1022]
|
||||||
|
|
||||||
|
### [9.23.0] - 2021-02-01
|
||||||
|
- Various RSA operations added to encrypt, decrypt, sign, verify and generate keys [@mattnotmitt] [@GCHQ77703] | [#652]
|
||||||
|
|
||||||
|
### [9.22.0] - 2021-02-01
|
||||||
|
- 'Unicode Text Format' operation added [@mattnotmitt] | [#1083]
|
||||||
|
|
||||||
|
### [9.21.0] - 2020-06-12
|
||||||
|
- Node API now exports `magic` operation [@d98762625] | [#1049]
|
||||||
|
|
||||||
|
### [9.20.0] - 2020-03-27
|
||||||
|
- 'Parse ObjectID Timestamp' operation added [@dmfj] | [#987]
|
||||||
|
|
||||||
|
### [9.19.0] - 2020-03-24
|
||||||
|
- Improvements to the 'Magic' operation, allowing it to recognise more data formats and provide more accurate results [@n1073645] [@n1474335] | [#966] [b765534b](https://github.com/gchq/CyberChef/commit/b765534b8b2a0454a5132a0a52d1d8844bcbdaaa)
|
||||||
|
|
||||||
|
### [9.18.0] - 2020-03-13
|
||||||
|
- 'Convert to NATO alphabet' operation added [@MarvinJWendt] | [#674]
|
||||||
|
|
||||||
|
### [9.17.0] - 2020-03-13
|
||||||
|
- 'Generate Image' operation added [@pointhi] | [#683]
|
||||||
|
|
||||||
|
### [9.16.0] - 2020-03-06
|
||||||
|
- 'Colossus' operation added [@VirtualColossus] | [#917]
|
||||||
|
|
||||||
|
### [9.15.0] - 2020-03-05
|
||||||
|
- 'CipherSaber2 Encrypt' and 'CipherSaber2 Decrypt' operations added [@n1073645] | [#952]
|
||||||
|
|
||||||
|
### [9.14.0] - 2020-03-05
|
||||||
|
- 'Luhn Checksum' operation added [@n1073645] | [#965]
|
||||||
|
|
||||||
|
### [9.13.0] - 2020-02-13
|
||||||
|
- 'Rail Fence Cipher Encode' and 'Rail Fence Cipher Decode' operations added [@Flavsditz] | [#948]
|
||||||
|
|
||||||
|
### [9.12.0] - 2019-12-20
|
||||||
|
- 'Normalise Unicode' operation added [@matthieuxyz] | [#912]
|
||||||
|
|
||||||
### [9.11.0] - 2019-11-06
|
### [9.11.0] - 2019-11-06
|
||||||
- Implemented CFB, OFB, and CTR modes for Blowfish operations [@cbeuw] | [#653]
|
- Implemented CFB, OFB, and CTR modes for Blowfish operations [@cbeuw] | [#653]
|
||||||
|
|
||||||
@@ -197,6 +253,21 @@ All major and minor version changes will be documented in this file. Details of
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[9.26.0]: https://github.com/gchq/CyberChef/releases/tag/v9.26.0
|
||||||
|
[9.25.0]: https://github.com/gchq/CyberChef/releases/tag/v9.25.0
|
||||||
|
[9.24.0]: https://github.com/gchq/CyberChef/releases/tag/v9.24.0
|
||||||
|
[9.23.0]: https://github.com/gchq/CyberChef/releases/tag/v9.23.0
|
||||||
|
[9.22.0]: https://github.com/gchq/CyberChef/releases/tag/v9.22.0
|
||||||
|
[9.21.0]: https://github.com/gchq/CyberChef/releases/tag/v9.21.0
|
||||||
|
[9.20.0]: https://github.com/gchq/CyberChef/releases/tag/v9.20.0
|
||||||
|
[9.19.0]: https://github.com/gchq/CyberChef/releases/tag/v9.19.0
|
||||||
|
[9.18.0]: https://github.com/gchq/CyberChef/releases/tag/v9.18.0
|
||||||
|
[9.17.0]: https://github.com/gchq/CyberChef/releases/tag/v9.17.0
|
||||||
|
[9.16.0]: https://github.com/gchq/CyberChef/releases/tag/v9.16.0
|
||||||
|
[9.15.0]: https://github.com/gchq/CyberChef/releases/tag/v9.15.0
|
||||||
|
[9.14.0]: https://github.com/gchq/CyberChef/releases/tag/v9.14.0
|
||||||
|
[9.13.0]: https://github.com/gchq/CyberChef/releases/tag/v9.13.0
|
||||||
|
[9.12.0]: https://github.com/gchq/CyberChef/releases/tag/v9.12.0
|
||||||
[9.11.0]: https://github.com/gchq/CyberChef/releases/tag/v9.11.0
|
[9.11.0]: https://github.com/gchq/CyberChef/releases/tag/v9.11.0
|
||||||
[9.10.0]: https://github.com/gchq/CyberChef/releases/tag/v9.10.0
|
[9.10.0]: https://github.com/gchq/CyberChef/releases/tag/v9.10.0
|
||||||
[9.9.0]: https://github.com/gchq/CyberChef/releases/tag/v9.9.0
|
[9.9.0]: https://github.com/gchq/CyberChef/releases/tag/v9.9.0
|
||||||
@@ -257,6 +328,7 @@ All major and minor version changes will be documented in this file. Details of
|
|||||||
[@n1474335]: https://github.com/n1474335
|
[@n1474335]: https://github.com/n1474335
|
||||||
[@d98762625]: https://github.com/d98762625
|
[@d98762625]: https://github.com/d98762625
|
||||||
[@j433866]: https://github.com/j433866
|
[@j433866]: https://github.com/j433866
|
||||||
|
[@n1073645]: https://github.com/n1073645
|
||||||
[@GCHQ77703]: https://github.com/GCHQ77703
|
[@GCHQ77703]: https://github.com/GCHQ77703
|
||||||
[@h345983745]: https://github.com/h345983745
|
[@h345983745]: https://github.com/h345983745
|
||||||
[@s2224834]: https://github.com/s2224834
|
[@s2224834]: https://github.com/s2224834
|
||||||
@@ -281,6 +353,12 @@ All major and minor version changes will be documented in this file. Details of
|
|||||||
[@jarrodconnolly]: https://github.com/jarrodconnolly
|
[@jarrodconnolly]: https://github.com/jarrodconnolly
|
||||||
[@VirtualColossus]: https://github.com/VirtualColossus
|
[@VirtualColossus]: https://github.com/VirtualColossus
|
||||||
[@cbeuw]: https://github.com/cbeuw
|
[@cbeuw]: https://github.com/cbeuw
|
||||||
|
[@matthieuxyz]: https://github.com/matthieuxyz
|
||||||
|
[@Flavsditz]: https://github.com/Flavsditz
|
||||||
|
[@pointhi]: https://github.com/pointhi
|
||||||
|
[@MarvinJWendt]: https://github.com/MarvinJWendt
|
||||||
|
[@dmfj]: https://github.com/dmfj
|
||||||
|
[@mattnotmitt]: https://github.com/mattnotmitt
|
||||||
|
|
||||||
[#95]: https://github.com/gchq/CyberChef/pull/299
|
[#95]: https://github.com/gchq/CyberChef/pull/299
|
||||||
[#173]: https://github.com/gchq/CyberChef/pull/173
|
[#173]: https://github.com/gchq/CyberChef/pull/173
|
||||||
@@ -342,5 +420,20 @@ All major and minor version changes will be documented in this file. Details of
|
|||||||
[#625]: https://github.com/gchq/CyberChef/pull/625
|
[#625]: https://github.com/gchq/CyberChef/pull/625
|
||||||
[#627]: https://github.com/gchq/CyberChef/pull/627
|
[#627]: https://github.com/gchq/CyberChef/pull/627
|
||||||
[#632]: https://github.com/gchq/CyberChef/pull/632
|
[#632]: https://github.com/gchq/CyberChef/pull/632
|
||||||
|
[#652]: https://github.com/gchq/CyberChef/pull/652
|
||||||
[#653]: https://github.com/gchq/CyberChef/pull/653
|
[#653]: https://github.com/gchq/CyberChef/pull/653
|
||||||
|
[#674]: https://github.com/gchq/CyberChef/pull/674
|
||||||
|
[#683]: https://github.com/gchq/CyberChef/pull/683
|
||||||
[#865]: https://github.com/gchq/CyberChef/pull/865
|
[#865]: https://github.com/gchq/CyberChef/pull/865
|
||||||
|
[#912]: https://github.com/gchq/CyberChef/pull/912
|
||||||
|
[#917]: https://github.com/gchq/CyberChef/pull/917
|
||||||
|
[#948]: https://github.com/gchq/CyberChef/pull/948
|
||||||
|
[#952]: https://github.com/gchq/CyberChef/pull/952
|
||||||
|
[#965]: https://github.com/gchq/CyberChef/pull/965
|
||||||
|
[#966]: https://github.com/gchq/CyberChef/pull/966
|
||||||
|
[#987]: https://github.com/gchq/CyberChef/pull/987
|
||||||
|
[#1006]: https://github.com/gchq/CyberChef/pull/1006
|
||||||
|
[#1022]: https://github.com/gchq/CyberChef/pull/1022
|
||||||
|
[#1045]: https://github.com/gchq/CyberChef/pull/1045
|
||||||
|
[#1049]: https://github.com/gchq/CyberChef/pull/1049
|
||||||
|
[#1083]: https://github.com/gchq/CyberChef/pull/1083
|
||||||
160
Gruntfile.js
160
Gruntfile.js
@@ -26,7 +26,7 @@ module.exports = function (grunt) {
|
|||||||
grunt.registerTask("prod",
|
grunt.registerTask("prod",
|
||||||
"Creates a production-ready build. Use the --msg flag to add a compile message.",
|
"Creates a production-ready build. Use the --msg flag to add a compile message.",
|
||||||
[
|
[
|
||||||
"eslint", "clean:prod", "clean:config", "exec:generateConfig", "webpack:web",
|
"eslint", "clean:prod", "clean:config", "exec:generateConfig", "findModules", "webpack:web",
|
||||||
"copy:standalone", "zip:standalone", "clean:standalone", "chmod"
|
"copy:standalone", "zip:standalone", "clean:standalone", "chmod"
|
||||||
]);
|
]);
|
||||||
|
|
||||||
@@ -36,11 +36,10 @@ module.exports = function (grunt) {
|
|||||||
"clean:node", "clean:config", "clean:nodeConfig", "exec:generateConfig", "exec:generateNodeIndex"
|
"clean:node", "clean:config", "clean:nodeConfig", "exec:generateConfig", "exec:generateNodeIndex"
|
||||||
]);
|
]);
|
||||||
|
|
||||||
grunt.registerTask("test",
|
grunt.registerTask("configTests",
|
||||||
"A task which runs all the operation tests in the tests directory.",
|
"A task which configures config files in preparation for tests to be run. Use `npm test` to run tests.",
|
||||||
[
|
[
|
||||||
"clean:config", "clean:nodeConfig", "exec:generateConfig", "exec:generateNodeIndex",
|
"clean:config", "clean:nodeConfig", "exec:generateConfig", "exec:generateNodeIndex"
|
||||||
"exec:nodeTests", "exec:opTests"
|
|
||||||
]);
|
]);
|
||||||
|
|
||||||
grunt.registerTask("testui",
|
grunt.registerTask("testui",
|
||||||
@@ -55,9 +54,21 @@ module.exports = function (grunt) {
|
|||||||
"Lints the code base",
|
"Lints the code base",
|
||||||
["eslint", "exec:repoSize"]);
|
["eslint", "exec:repoSize"]);
|
||||||
|
|
||||||
grunt.registerTask("tests", "test");
|
|
||||||
grunt.registerTask("lint", "eslint");
|
grunt.registerTask("lint", "eslint");
|
||||||
|
|
||||||
|
grunt.registerTask("findModules",
|
||||||
|
"Finds all generated modules and updates the entry point list for Webpack",
|
||||||
|
function(arg1, arg2) {
|
||||||
|
const moduleEntryPoints = listEntryModules();
|
||||||
|
|
||||||
|
grunt.log.writeln(`Found ${Object.keys(moduleEntryPoints).length} modules.`);
|
||||||
|
|
||||||
|
grunt.config.set("webpack.web.entry",
|
||||||
|
Object.assign({
|
||||||
|
main: "./src/web/index.js"
|
||||||
|
}, moduleEntryPoints));
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
// Load tasks provided by each plugin
|
// Load tasks provided by each plugin
|
||||||
grunt.loadNpmTasks("grunt-eslint");
|
grunt.loadNpmTasks("grunt-eslint");
|
||||||
@@ -67,7 +78,6 @@ module.exports = function (grunt) {
|
|||||||
grunt.loadNpmTasks("grunt-contrib-watch");
|
grunt.loadNpmTasks("grunt-contrib-watch");
|
||||||
grunt.loadNpmTasks("grunt-chmod");
|
grunt.loadNpmTasks("grunt-chmod");
|
||||||
grunt.loadNpmTasks("grunt-exec");
|
grunt.loadNpmTasks("grunt-exec");
|
||||||
grunt.loadNpmTasks("grunt-accessibility");
|
|
||||||
grunt.loadNpmTasks("grunt-concurrent");
|
grunt.loadNpmTasks("grunt-concurrent");
|
||||||
grunt.loadNpmTasks("grunt-contrib-connect");
|
grunt.loadNpmTasks("grunt-contrib-connect");
|
||||||
grunt.loadNpmTasks("grunt-zip");
|
grunt.loadNpmTasks("grunt-zip");
|
||||||
@@ -83,7 +93,53 @@ module.exports = function (grunt) {
|
|||||||
PKG_VERSION: JSON.stringify(pkg.version),
|
PKG_VERSION: JSON.stringify(pkg.version),
|
||||||
},
|
},
|
||||||
moduleEntryPoints = listEntryModules(),
|
moduleEntryPoints = listEntryModules(),
|
||||||
nodeConsumerTestPath = "~/tmp-cyberchef";
|
nodeConsumerTestPath = "~/tmp-cyberchef",
|
||||||
|
/**
|
||||||
|
* Configuration for Webpack production build. Defined as a function so that it
|
||||||
|
* can be recalculated when new modules are generated.
|
||||||
|
*/
|
||||||
|
webpackProdConf = () => {
|
||||||
|
return {
|
||||||
|
mode: "production",
|
||||||
|
target: "web",
|
||||||
|
entry: Object.assign({
|
||||||
|
main: "./src/web/index.js"
|
||||||
|
}, moduleEntryPoints),
|
||||||
|
output: {
|
||||||
|
path: __dirname + "/build/prod",
|
||||||
|
filename: chunkData => {
|
||||||
|
return chunkData.chunk.name === "main" ? "assets/[name].js": "[name].js";
|
||||||
|
},
|
||||||
|
globalObject: "this"
|
||||||
|
},
|
||||||
|
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,
|
||||||
|
minify: {
|
||||||
|
removeComments: true,
|
||||||
|
collapseWhitespace: true,
|
||||||
|
minifyJS: true,
|
||||||
|
minifyCSS: true
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
new BundleAnalyzerPlugin({
|
||||||
|
analyzerMode: "static",
|
||||||
|
reportFilename: "BundleAnalyzerReport.html",
|
||||||
|
openAnalyzer: false
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -118,7 +174,7 @@ module.exports = function (grunt) {
|
|||||||
// previous one fails. & would coninue on a fail
|
// previous one fails. & would coninue on a fail
|
||||||
.join("&&")
|
.join("&&")
|
||||||
// Windows does not support \n properly
|
// Windows does not support \n properly
|
||||||
.replace("\n", "\\n");
|
.replace(/\n/g, "\\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
grunt.initConfig({
|
grunt.initConfig({
|
||||||
@@ -140,67 +196,15 @@ module.exports = function (grunt) {
|
|||||||
node: ["src/node/**/*.{js,mjs}"],
|
node: ["src/node/**/*.{js,mjs}"],
|
||||||
tests: ["tests/**/*.{js,mjs}"],
|
tests: ["tests/**/*.{js,mjs}"],
|
||||||
},
|
},
|
||||||
accessibility: {
|
|
||||||
options: {
|
|
||||||
accessibilityLevel: "WCAG2A",
|
|
||||||
verbose: false,
|
|
||||||
ignore: [
|
|
||||||
"WCAG2A.Principle1.Guideline1_3.1_3_1.H42.2"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
test: {
|
|
||||||
src: ["build/**/*.html"]
|
|
||||||
}
|
|
||||||
},
|
|
||||||
webpack: {
|
webpack: {
|
||||||
options: webpackConfig,
|
options: webpackConfig,
|
||||||
web: () => {
|
web: webpackProdConf(),
|
||||||
return {
|
|
||||||
mode: "production",
|
|
||||||
target: "web",
|
|
||||||
entry: Object.assign({
|
|
||||||
main: "./src/web/index.js"
|
|
||||||
}, moduleEntryPoints),
|
|
||||||
output: {
|
|
||||||
path: __dirname + "/build/prod",
|
|
||||||
filename: chunkData => {
|
|
||||||
return chunkData.chunk.name === "main" ? "assets/[name].js": "[name].js";
|
|
||||||
},
|
|
||||||
globalObject: "this"
|
|
||||||
},
|
|
||||||
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,
|
|
||||||
minify: {
|
|
||||||
removeComments: true,
|
|
||||||
collapseWhitespace: true,
|
|
||||||
minifyJS: true,
|
|
||||||
minifyCSS: true
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
new BundleAnalyzerPlugin({
|
|
||||||
analyzerMode: "static",
|
|
||||||
reportFilename: "BundleAnalyzerReport.html",
|
|
||||||
openAnalyzer: false
|
|
||||||
}),
|
|
||||||
]
|
|
||||||
};
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
"webpack-dev-server": {
|
"webpack-dev-server": {
|
||||||
options: {
|
options: {
|
||||||
webpack: webpackConfig,
|
webpack: webpackConfig,
|
||||||
host: "0.0.0.0",
|
host: "0.0.0.0",
|
||||||
|
port: grunt.option("port") || 8080,
|
||||||
disableHostCheck: true,
|
disableHostCheck: true,
|
||||||
overlay: true,
|
overlay: true,
|
||||||
inline: false,
|
inline: false,
|
||||||
@@ -257,7 +261,7 @@ module.exports = function (grunt) {
|
|||||||
connect: {
|
connect: {
|
||||||
prod: {
|
prod: {
|
||||||
options: {
|
options: {
|
||||||
port: 8000,
|
port: grunt.option("port") || 8000,
|
||||||
base: "build/prod/"
|
base: "build/prod/"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -285,7 +289,7 @@ module.exports = function (grunt) {
|
|||||||
},
|
},
|
||||||
files: [
|
files: [
|
||||||
{
|
{
|
||||||
src: "build/prod/index.html",
|
src: ["build/prod/index.html"],
|
||||||
dest: "build/prod/index.html"
|
dest: "build/prod/index.html"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -307,7 +311,7 @@ module.exports = function (grunt) {
|
|||||||
},
|
},
|
||||||
files: [
|
files: [
|
||||||
{
|
{
|
||||||
src: "build/prod/index.html",
|
src: ["build/prod/index.html"],
|
||||||
dest: `build/prod/CyberChef_v${pkg.version}.html`
|
dest: `build/prod/CyberChef_v${pkg.version}.html`
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@@ -345,7 +349,8 @@ module.exports = function (grunt) {
|
|||||||
command: "git gc --prune=now --aggressive"
|
command: "git gc --prune=now --aggressive"
|
||||||
},
|
},
|
||||||
sitemap: {
|
sitemap: {
|
||||||
command: "node --experimental-modules --no-warnings --no-deprecation src/web/static/sitemap.mjs > build/prod/sitemap.xml"
|
command: "node --experimental-modules --no-warnings --no-deprecation src/web/static/sitemap.mjs > build/prod/sitemap.xml",
|
||||||
|
sync: true
|
||||||
},
|
},
|
||||||
generateConfig: {
|
generateConfig: {
|
||||||
command: chainCommands([
|
command: chainCommands([
|
||||||
@@ -354,7 +359,8 @@ module.exports = function (grunt) {
|
|||||||
"node --experimental-modules --no-warnings --no-deprecation src/core/config/scripts/generateOpsIndex.mjs",
|
"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 --experimental-modules --no-warnings --no-deprecation src/core/config/scripts/generateConfig.mjs",
|
||||||
"echo '--- Config scripts finished. ---\n'"
|
"echo '--- Config scripts finished. ---\n'"
|
||||||
])
|
]),
|
||||||
|
sync: true
|
||||||
},
|
},
|
||||||
generateNodeIndex: {
|
generateNodeIndex: {
|
||||||
command: chainCommands([
|
command: chainCommands([
|
||||||
@@ -362,16 +368,11 @@ module.exports = function (grunt) {
|
|||||||
"node --experimental-modules --no-warnings --no-deprecation src/node/config/scripts/generateNodeIndex.mjs",
|
"node --experimental-modules --no-warnings --no-deprecation src/node/config/scripts/generateNodeIndex.mjs",
|
||||||
"echo '--- Node index generated. ---\n'"
|
"echo '--- Node index generated. ---\n'"
|
||||||
]),
|
]),
|
||||||
},
|
sync: true
|
||||||
opTests: {
|
|
||||||
command: "node --experimental-modules --no-warnings --no-deprecation tests/operations/index.mjs"
|
|
||||||
},
|
},
|
||||||
browserTests: {
|
browserTests: {
|
||||||
command: "./node_modules/.bin/nightwatch --env prod"
|
command: "./node_modules/.bin/nightwatch --env prod"
|
||||||
},
|
},
|
||||||
nodeTests: {
|
|
||||||
command: "node --experimental-modules --no-warnings --no-deprecation tests/node/index.mjs"
|
|
||||||
},
|
|
||||||
setupNodeConsumers: {
|
setupNodeConsumers: {
|
||||||
command: chainCommands([
|
command: chainCommands([
|
||||||
"echo '\n--- Testing node consumers ---'",
|
"echo '\n--- Testing node consumers ---'",
|
||||||
@@ -381,6 +382,7 @@ module.exports = function (grunt) {
|
|||||||
`cd ${nodeConsumerTestPath}`,
|
`cd ${nodeConsumerTestPath}`,
|
||||||
"npm link cyberchef"
|
"npm link cyberchef"
|
||||||
]),
|
]),
|
||||||
|
sync: true
|
||||||
},
|
},
|
||||||
teardownNodeConsumers: {
|
teardownNodeConsumers: {
|
||||||
command: chainCommands([
|
command: chainCommands([
|
||||||
@@ -409,6 +411,16 @@ module.exports = function (grunt) {
|
|||||||
]),
|
]),
|
||||||
stdout: false,
|
stdout: false,
|
||||||
},
|
},
|
||||||
|
fixCryptoApiImports: {
|
||||||
|
command: [
|
||||||
|
`[[ "$OSTYPE" == "darwin"* ]]`,
|
||||||
|
"&&",
|
||||||
|
`find ./node_modules/crypto-api/src/ \\( -type d -name .git -prune \\) -o -type f -print0 | xargs -0 sed -i '' -e '/\\.mjs/!s/\\(from "\\.[^"]*\\)";/\\1.mjs";/g'`,
|
||||||
|
"||",
|
||||||
|
`find ./node_modules/crypto-api/src/ \\( -type d -name .git -prune \\) -o -type f -print0 | xargs -0 sed -i -e '/\\.mjs/!s/\\(from "\\.[^"]*\\)";/\\1.mjs";/g'`
|
||||||
|
].join(" "),
|
||||||
|
stdout: false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
12963
package-lock.json
generated
12963
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
182
package.json
182
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "cyberchef",
|
"name": "cyberchef",
|
||||||
"version": "9.11.2",
|
"version": "9.26.1",
|
||||||
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
|
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
|
||||||
"author": "n1474335 <n1474335@gmail.com>",
|
"author": "n1474335 <n1474335@gmail.com>",
|
||||||
"homepage": "https://gchq.github.io/CyberChef",
|
"homepage": "https://gchq.github.io/CyberChef",
|
||||||
@@ -36,133 +36,143 @@
|
|||||||
"node >= 10"
|
"node >= 10"
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.5.5",
|
"@babel/core": "^7.12.10",
|
||||||
"@babel/plugin-transform-runtime": "^7.5.5",
|
"@babel/plugin-transform-runtime": "^7.12.10",
|
||||||
"@babel/preset-env": "^7.5.5",
|
"@babel/preset-env": "^7.12.11",
|
||||||
"autoprefixer": "^9.6.1",
|
"autoprefixer": "^10.2.4",
|
||||||
"babel-eslint": "^10.0.3",
|
"babel-eslint": "^10.1.0",
|
||||||
"babel-loader": "^8.0.6",
|
"babel-loader": "^8.2.2",
|
||||||
"babel-plugin-dynamic-import-node": "^2.3.0",
|
"babel-plugin-dynamic-import-node": "^2.3.3",
|
||||||
"chromedriver": "^77.0.0",
|
"chromedriver": "^88.0.0",
|
||||||
"colors": "^1.3.3",
|
"cli-progress": "^3.9.0",
|
||||||
"copy-webpack-plugin": "^5.0.4",
|
"colors": "^1.4.0",
|
||||||
"css-loader": "^3.2.0",
|
"copy-webpack-plugin": "^7.0.0",
|
||||||
"eslint": "^6.2.2",
|
"css-loader": "^5.0.1",
|
||||||
"exports-loader": "^0.7.0",
|
"eslint": "^7.19.0",
|
||||||
"file-loader": "^4.2.0",
|
"exports-loader": "^2.0.0",
|
||||||
"grunt": "^1.0.4",
|
"file-loader": "^6.2.0",
|
||||||
"grunt-accessibility": "~6.0.0",
|
"grunt": "^1.3.0",
|
||||||
"grunt-chmod": "~1.1.1",
|
"grunt-chmod": "~1.1.1",
|
||||||
"grunt-concurrent": "^3.0.0",
|
"grunt-concurrent": "^3.0.0",
|
||||||
"grunt-contrib-clean": "~2.0.0",
|
"grunt-contrib-clean": "~2.0.0",
|
||||||
"grunt-contrib-connect": "^2.0.0",
|
"grunt-contrib-connect": "^3.0.0",
|
||||||
"grunt-contrib-copy": "~1.0.0",
|
"grunt-contrib-copy": "~1.0.0",
|
||||||
"grunt-contrib-watch": "^1.1.0",
|
"grunt-contrib-watch": "^1.1.0",
|
||||||
"grunt-eslint": "^22.0.0",
|
"grunt-eslint": "^23.0.0",
|
||||||
"grunt-exec": "~3.0.0",
|
"grunt-exec": "~3.0.0",
|
||||||
"grunt-webpack": "^3.1.3",
|
"grunt-webpack": "^4.0.2",
|
||||||
"grunt-zip": "^0.18.2",
|
"grunt-zip": "^0.18.2",
|
||||||
"html-webpack-plugin": "^3.2.0",
|
"html-webpack-plugin": "^4.5.1",
|
||||||
"imports-loader": "^0.8.0",
|
"imports-loader": "^2.0.0",
|
||||||
"mini-css-extract-plugin": "^0.8.0",
|
"mini-css-extract-plugin": "^1.3.5",
|
||||||
"nightwatch": "^1.2.1",
|
"nightwatch": "^1.5.1",
|
||||||
"node-sass": "^4.12.0",
|
"node-sass": "^5.0.0",
|
||||||
"postcss-css-variables": "^0.13.0",
|
"postcss": "^8.2.4",
|
||||||
"postcss-import": "^12.0.1",
|
"postcss-css-variables": "^0.17.0",
|
||||||
"postcss-loader": "^3.0.0",
|
"postcss-import": "^14.0.0",
|
||||||
"prompt": "^1.0.0",
|
"postcss-loader": "^4.2.0",
|
||||||
"sass-loader": "^8.0.0",
|
"prompt": "^1.1.0",
|
||||||
"sitemap": "^4.1.1",
|
"sass-loader": "^10.1.1",
|
||||||
"style-loader": "^1.0.0",
|
"sitemap": "^6.3.5",
|
||||||
"svg-url-loader": "^3.0.1",
|
"style-loader": "^2.0.0",
|
||||||
"url-loader": "^2.1.0",
|
"svg-url-loader": "^7.1.1",
|
||||||
"webpack": "^4.39.3",
|
"url-loader": "^4.1.1",
|
||||||
"webpack-bundle-analyzer": "^3.4.1",
|
"webpack": "^5.19.0",
|
||||||
"webpack-dev-server": "^3.8.0",
|
"webpack-bundle-analyzer": "^4.4.0",
|
||||||
"webpack-node-externals": "^1.7.2",
|
"webpack-dev-server": "^3.11.2",
|
||||||
"worker-loader": "^2.0.0"
|
"webpack-node-externals": "^2.5.2",
|
||||||
|
"worker-loader": "^3.0.7"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@babel/polyfill": "^7.4.4",
|
"@babel/polyfill": "^7.12.1",
|
||||||
"@babel/runtime": "^7.5.5",
|
"@babel/runtime": "^7.12.5",
|
||||||
"arrive": "^2.4.1",
|
"arrive": "^2.4.1",
|
||||||
"avsc": "^5.4.16",
|
"avsc": "^5.5.3",
|
||||||
"babel-plugin-transform-builtin-extend": "1.1.2",
|
"babel-plugin-transform-builtin-extend": "1.1.2",
|
||||||
"bcryptjs": "^2.4.3",
|
"bcryptjs": "^2.4.3",
|
||||||
"bignumber.js": "^9.0.0",
|
"bignumber.js": "^9.0.1",
|
||||||
"blakejs": "^1.1.0",
|
"blakejs": "^1.1.0",
|
||||||
"bootstrap": "4.3.1",
|
"bootstrap": "4.6.0",
|
||||||
"bootstrap-colorpicker": "^3.1.2",
|
"bootstrap-colorpicker": "^3.2.0",
|
||||||
"bootstrap-material-design": "^4.1.2",
|
"bootstrap-material-design": "^4.1.3",
|
||||||
"bson": "^4.0.2",
|
"browserify-zlib": "^0.2.0",
|
||||||
|
"bson": "^4.2.2",
|
||||||
|
"buffer": "^6.0.3",
|
||||||
"chi-squared": "^1.1.0",
|
"chi-squared": "^1.1.0",
|
||||||
"codepage": "^1.14.0",
|
"codepage": "^1.14.0",
|
||||||
"core-js": "^3.2.1",
|
"core-js": "^3.8.3",
|
||||||
"crypto-api": "^0.8.5",
|
"crypto-api": "^0.8.5",
|
||||||
"crypto-js": "^3.1.9-1",
|
"crypto-browserify": "^3.12.0",
|
||||||
|
"crypto-js": "^4.0.0",
|
||||||
"ctph.js": "0.0.5",
|
"ctph.js": "0.0.5",
|
||||||
"d3": "^5.11.0",
|
"d3": "^6.5.0",
|
||||||
"d3-hexbin": "^0.2.2",
|
"d3-hexbin": "^0.2.2",
|
||||||
"diff": "^4.0.1",
|
"diff": "^5.0.0",
|
||||||
"es6-promisify": "^6.0.2",
|
"es6-promisify": "^6.1.1",
|
||||||
"escodegen": "^1.12.0",
|
"escodegen": "^2.0.0",
|
||||||
"esm": "^3.2.25",
|
"esm": "^3.2.25",
|
||||||
"esmangle": "^1.0.1",
|
|
||||||
"esprima": "^4.0.1",
|
"esprima": "^4.0.1",
|
||||||
"exif-parser": "^0.1.12",
|
"exif-parser": "^0.1.12",
|
||||||
"file-saver": "^2.0.2",
|
"file-saver": "^2.0.5",
|
||||||
|
"flat": "^5.0.2",
|
||||||
"geodesy": "^1.1.3",
|
"geodesy": "^1.1.3",
|
||||||
"highlight.js": "^9.15.10",
|
"highlight.js": "^10.5.0",
|
||||||
"jimp": "^0.6.4",
|
"jimp": "^0.16.1",
|
||||||
"jquery": "3.4.1",
|
"jquery": "3.5.1",
|
||||||
"js-crc": "^0.2.0",
|
"js-crc": "^0.2.0",
|
||||||
"js-sha3": "^0.8.0",
|
"js-sha3": "^0.8.0",
|
||||||
"jsesc": "^2.5.2",
|
"jsesc": "^3.0.2",
|
||||||
"jsonpath": "^1.0.2",
|
"jsonpath": "^1.1.0",
|
||||||
"jsonwebtoken": "^8.5.1",
|
"jsonwebtoken": "^8.5.1",
|
||||||
"jsqr": "^1.2.0",
|
"jsqr": "^1.3.1",
|
||||||
"jsrsasign": "8.0.12",
|
"jsrsasign": "10.1.5",
|
||||||
"kbpgp": "2.1.3",
|
"kbpgp": "2.1.15",
|
||||||
"libbzip2-wasm": "0.0.4",
|
"libbzip2-wasm": "0.0.4",
|
||||||
"libyara-wasm": "^1.0.1",
|
"libyara-wasm": "^1.1.0",
|
||||||
"lodash": "^4.17.15",
|
"lodash": "^4.17.20",
|
||||||
"loglevel": "^1.6.3",
|
"loglevel": "^1.7.1",
|
||||||
"loglevel-message-prefix": "^3.0.0",
|
"loglevel-message-prefix": "^3.0.0",
|
||||||
"markdown-it": "^9.1.0",
|
"markdown-it": "^12.0.4",
|
||||||
"moment": "^2.24.0",
|
"moment": "^2.29.1",
|
||||||
"moment-timezone": "^0.5.26",
|
"moment-timezone": "^0.5.32",
|
||||||
"ngeohash": "^0.6.3",
|
"ngeohash": "^0.6.3",
|
||||||
"node-forge": "^0.9.1",
|
"node-forge": "^0.10.0",
|
||||||
"node-md6": "^0.1.0",
|
"node-md6": "^0.1.0",
|
||||||
"nodom": "^2.2.0",
|
"nodom": "^2.4.0",
|
||||||
"notepack.io": "^2.2.0",
|
"notepack.io": "^2.3.0",
|
||||||
"nwmatcher": "^1.4.4",
|
"nwmatcher": "^1.4.4",
|
||||||
"otp": "^0.1.3",
|
"otp": "^0.1.3",
|
||||||
"popper.js": "^1.15.0",
|
"path": "^0.12.7",
|
||||||
|
"popper.js": "^1.16.1",
|
||||||
|
"process": "^0.11.10",
|
||||||
"qr-image": "^3.2.0",
|
"qr-image": "^3.2.0",
|
||||||
"scryptsy": "^2.1.0",
|
"scryptsy": "^2.1.0",
|
||||||
"snackbarjs": "^1.1.0",
|
"snackbarjs": "^1.1.0",
|
||||||
"sortablejs": "^1.9.0",
|
"sortablejs": "^1.13.0",
|
||||||
"split.js": "^1.5.11",
|
"split.js": "^1.6.2",
|
||||||
"ssdeep.js": "0.0.2",
|
"ssdeep.js": "0.0.2",
|
||||||
"tesseract.js": "^2.0.0-alpha.15",
|
"stream-browserify": "^3.0.0",
|
||||||
"ua-parser-js": "^0.7.20",
|
"terser": "^5.5.1",
|
||||||
|
"tesseract.js": "^2.1.1",
|
||||||
|
"ua-parser-js": "^0.7.23",
|
||||||
|
"unorm": "^1.6.0",
|
||||||
"utf8": "^3.0.0",
|
"utf8": "^3.0.0",
|
||||||
"vkbeautify": "^0.99.3",
|
"vkbeautify": "^0.99.3",
|
||||||
"xmldom": "^0.1.27",
|
"xmldom": "^0.4.0",
|
||||||
"xpath": "0.0.27",
|
"xpath": "0.0.32",
|
||||||
"xregexp": "^4.2.4",
|
"xregexp": "^4.4.1",
|
||||||
"zlibjs": "^0.3.1"
|
"zlibjs": "^0.3.1"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "grunt dev",
|
"start": "npx grunt dev",
|
||||||
"build": "grunt prod",
|
"build": "npx grunt prod",
|
||||||
"repl": "node src/node/repl.js",
|
"repl": "node src/node/repl.js",
|
||||||
"test": "grunt test",
|
"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": "grunt testnodeconsumer",
|
"test-node-consumer": "npx grunt testnodeconsumer",
|
||||||
"testui": "grunt testui",
|
"testui": "npx grunt testui",
|
||||||
"testuidev": "npx nightwatch --env=dev",
|
"testuidev": "npx nightwatch --env=dev",
|
||||||
"lint": "grunt lint",
|
"lint": "npx grunt lint",
|
||||||
|
"postinstall": "npx grunt exec:fixCryptoApiImports",
|
||||||
"newop": "node --experimental-modules src/core/config/scripts/newOperation.mjs"
|
"newop": "node --experimental-modules src/core/config/scripts/newOperation.mjs"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ class Chef {
|
|||||||
*/
|
*/
|
||||||
async bake(input, recipeConfig, options) {
|
async bake(input, recipeConfig, options) {
|
||||||
log.debug("Chef baking");
|
log.debug("Chef baking");
|
||||||
const startTime = new Date().getTime(),
|
const startTime = Date.now(),
|
||||||
recipe = new Recipe(recipeConfig),
|
recipe = new Recipe(recipeConfig),
|
||||||
containsFc = recipe.containsFlowControl(),
|
containsFc = recipe.containsFlowControl(),
|
||||||
notUTF8 = options && "treatAsUtf8" in options && !options.treatAsUtf8;
|
notUTF8 = options && "treatAsUtf8" in options && !options.treatAsUtf8;
|
||||||
@@ -73,10 +73,10 @@ class Chef {
|
|||||||
// The threshold is specified in KiB.
|
// The threshold is specified in KiB.
|
||||||
const threshold = (options.ioDisplayThreshold || 1024) * 1024;
|
const threshold = (options.ioDisplayThreshold || 1024) * 1024;
|
||||||
const returnType =
|
const returnType =
|
||||||
this.dish.size > threshold ?
|
this.dish.type === Dish.HTML ?
|
||||||
Dish.ARRAY_BUFFER :
|
Dish.HTML :
|
||||||
this.dish.type === Dish.HTML ?
|
this.dish.size > threshold ?
|
||||||
Dish.HTML :
|
Dish.ARRAY_BUFFER :
|
||||||
Dish.STRING;
|
Dish.STRING;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -84,7 +84,7 @@ class Chef {
|
|||||||
result: await this.dish.get(returnType, notUTF8),
|
result: await this.dish.get(returnType, notUTF8),
|
||||||
type: Dish.enumLookup(this.dish.type),
|
type: Dish.enumLookup(this.dish.type),
|
||||||
progress: progress,
|
progress: progress,
|
||||||
duration: new Date().getTime() - startTime,
|
duration: Date.now() - startTime,
|
||||||
error: error
|
error: error
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -110,7 +110,7 @@ class Chef {
|
|||||||
silentBake(recipeConfig) {
|
silentBake(recipeConfig) {
|
||||||
log.debug("Running silent bake");
|
log.debug("Running silent bake");
|
||||||
|
|
||||||
const startTime = new Date().getTime(),
|
const startTime = Date.now(),
|
||||||
recipe = new Recipe(recipeConfig),
|
recipe = new Recipe(recipeConfig),
|
||||||
dish = new Dish();
|
dish = new Dish();
|
||||||
|
|
||||||
@@ -119,7 +119,7 @@ class Chef {
|
|||||||
} catch (err) {
|
} catch (err) {
|
||||||
// Suppress all errors
|
// Suppress all errors
|
||||||
}
|
}
|
||||||
return new Date().getTime() - startTime;
|
return Date.now() - startTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -146,7 +146,12 @@ class Chef {
|
|||||||
const func = direction === "forward" ? highlights[i].f : highlights[i].b;
|
const func = direction === "forward" ? highlights[i].f : highlights[i].b;
|
||||||
|
|
||||||
if (typeof func == "function") {
|
if (typeof func == "function") {
|
||||||
pos = func(pos, highlights[i].args);
|
try {
|
||||||
|
pos = func(pos, highlights[i].args);
|
||||||
|
} catch (err) {
|
||||||
|
// Throw away highlighting errors
|
||||||
|
pos = [];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ self.loadRequiredModules = function(recipeConfig) {
|
|||||||
if (!(module in OpModules)) {
|
if (!(module in OpModules)) {
|
||||||
log.info(`Loading ${module} module`);
|
log.info(`Loading ${module} module`);
|
||||||
self.sendStatusMessage(`Loading ${module} module`);
|
self.sendStatusMessage(`Loading ${module} module`);
|
||||||
self.importScripts(`${self.docURL}/modules/${module}.js`);
|
self.importScripts(`${self.docURL}/modules/${module}.js`); // lgtm [js/client-side-unvalidated-url-redirection]
|
||||||
self.sendStatusMessage("");
|
self.sendStatusMessage("");
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -207,7 +207,7 @@ class Dish {
|
|||||||
const data = new Uint8Array(this.value.slice(0, 2048)),
|
const data = new Uint8Array(this.value.slice(0, 2048)),
|
||||||
types = detectFileType(data);
|
types = detectFileType(data);
|
||||||
|
|
||||||
if (!types.length || !types[0].mime || !types[0].mime === "text/plain") {
|
if (!types.length || !types[0].mime || !(types[0].mime === "text/plain")) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
return types[0].mime;
|
return types[0].mime;
|
||||||
|
|||||||
@@ -113,6 +113,7 @@ class Ingredient {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
case "number":
|
case "number":
|
||||||
|
if (data === null) return data;
|
||||||
number = parseFloat(data);
|
number = parseFloat(data);
|
||||||
if (isNaN(number)) {
|
if (isNaN(number)) {
|
||||||
const sample = Utils.truncate(data.toString(), 10);
|
const sample = Utils.truncate(data.toString(), 10);
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ class Recipe {
|
|||||||
module: OperationConfig[c.op].module,
|
module: OperationConfig[c.op].module,
|
||||||
ingValues: c.args,
|
ingValues: c.args,
|
||||||
breakpoint: c.breakpoint,
|
breakpoint: c.breakpoint,
|
||||||
disabled: c.disabled,
|
disabled: c.disabled || c.op === "Comment",
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -170,13 +170,18 @@ class Utils {
|
|||||||
*
|
*
|
||||||
* @param {string} str - The input string to display.
|
* @param {string} str - The input string to display.
|
||||||
* @param {boolean} [preserveWs=false] - Whether or not to print whitespace.
|
* @param {boolean} [preserveWs=false] - Whether or not to print whitespace.
|
||||||
|
* @param {boolean} [onlyAscii=false] - Whether or not to replace non ASCII characters.
|
||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
static printable(str, preserveWs=false) {
|
static printable(str, preserveWs=false, onlyAscii=false) {
|
||||||
if (isWebEnvironment() && window.app && !window.app.options.treatAsUtf8) {
|
if (isWebEnvironment() && window.app && !window.app.options.treatAsUtf8) {
|
||||||
str = Utils.byteArrayToChars(Utils.strToByteArray(str));
|
str = Utils.byteArrayToChars(Utils.strToByteArray(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (onlyAscii) {
|
||||||
|
return str.replace(/[^\x20-\x7f]/g, ".");
|
||||||
|
}
|
||||||
|
|
||||||
// eslint-disable-next-line no-misleading-character-class
|
// eslint-disable-next-line no-misleading-character-class
|
||||||
const re = /[\0-\x08\x0B-\x0C\x0E-\x1F\x7F-\x9F\xAD\u0378\u0379\u037F-\u0383\u038B\u038D\u03A2\u0528-\u0530\u0557\u0558\u0560\u0588\u058B-\u058E\u0590\u05C8-\u05CF\u05EB-\u05EF\u05F5-\u0605\u061C\u061D\u06DD\u070E\u070F\u074B\u074C\u07B2-\u07BF\u07FB-\u07FF\u082E\u082F\u083F\u085C\u085D\u085F-\u089F\u08A1\u08AD-\u08E3\u08FF\u0978\u0980\u0984\u098D\u098E\u0991\u0992\u09A9\u09B1\u09B3-\u09B5\u09BA\u09BB\u09C5\u09C6\u09C9\u09CA\u09CF-\u09D6\u09D8-\u09DB\u09DE\u09E4\u09E5\u09FC-\u0A00\u0A04\u0A0B-\u0A0E\u0A11\u0A12\u0A29\u0A31\u0A34\u0A37\u0A3A\u0A3B\u0A3D\u0A43-\u0A46\u0A49\u0A4A\u0A4E-\u0A50\u0A52-\u0A58\u0A5D\u0A5F-\u0A65\u0A76-\u0A80\u0A84\u0A8E\u0A92\u0AA9\u0AB1\u0AB4\u0ABA\u0ABB\u0AC6\u0ACA\u0ACE\u0ACF\u0AD1-\u0ADF\u0AE4\u0AE5\u0AF2-\u0B00\u0B04\u0B0D\u0B0E\u0B11\u0B12\u0B29\u0B31\u0B34\u0B3A\u0B3B\u0B45\u0B46\u0B49\u0B4A\u0B4E-\u0B55\u0B58-\u0B5B\u0B5E\u0B64\u0B65\u0B78-\u0B81\u0B84\u0B8B-\u0B8D\u0B91\u0B96-\u0B98\u0B9B\u0B9D\u0BA0-\u0BA2\u0BA5-\u0BA7\u0BAB-\u0BAD\u0BBA-\u0BBD\u0BC3-\u0BC5\u0BC9\u0BCE\u0BCF\u0BD1-\u0BD6\u0BD8-\u0BE5\u0BFB-\u0C00\u0C04\u0C0D\u0C11\u0C29\u0C34\u0C3A-\u0C3C\u0C45\u0C49\u0C4E-\u0C54\u0C57\u0C5A-\u0C5F\u0C64\u0C65\u0C70-\u0C77\u0C80\u0C81\u0C84\u0C8D\u0C91\u0CA9\u0CB4\u0CBA\u0CBB\u0CC5\u0CC9\u0CCE-\u0CD4\u0CD7-\u0CDD\u0CDF\u0CE4\u0CE5\u0CF0\u0CF3-\u0D01\u0D04\u0D0D\u0D11\u0D3B\u0D3C\u0D45\u0D49\u0D4F-\u0D56\u0D58-\u0D5F\u0D64\u0D65\u0D76-\u0D78\u0D80\u0D81\u0D84\u0D97-\u0D99\u0DB2\u0DBC\u0DBE\u0DBF\u0DC7-\u0DC9\u0DCB-\u0DCE\u0DD5\u0DD7\u0DE0-\u0DF1\u0DF5-\u0E00\u0E3B-\u0E3E\u0E5C-\u0E80\u0E83\u0E85\u0E86\u0E89\u0E8B\u0E8C\u0E8E-\u0E93\u0E98\u0EA0\u0EA4\u0EA6\u0EA8\u0EA9\u0EAC\u0EBA\u0EBE\u0EBF\u0EC5\u0EC7\u0ECE\u0ECF\u0EDA\u0EDB\u0EE0-\u0EFF\u0F48\u0F6D-\u0F70\u0F98\u0FBD\u0FCD\u0FDB-\u0FFF\u10C6\u10C8-\u10CC\u10CE\u10CF\u1249\u124E\u124F\u1257\u1259\u125E\u125F\u1289\u128E\u128F\u12B1\u12B6\u12B7\u12BF\u12C1\u12C6\u12C7\u12D7\u1311\u1316\u1317\u135B\u135C\u137D-\u137F\u139A-\u139F\u13F5-\u13FF\u169D-\u169F\u16F1-\u16FF\u170D\u1715-\u171F\u1737-\u173F\u1754-\u175F\u176D\u1771\u1774-\u177F\u17DE\u17DF\u17EA-\u17EF\u17FA-\u17FF\u180F\u181A-\u181F\u1878-\u187F\u18AB-\u18AF\u18F6-\u18FF\u191D-\u191F\u192C-\u192F\u193C-\u193F\u1941-\u1943\u196E\u196F\u1975-\u197F\u19AC-\u19AF\u19CA-\u19CF\u19DB-\u19DD\u1A1C\u1A1D\u1A5F\u1A7D\u1A7E\u1A8A-\u1A8F\u1A9A-\u1A9F\u1AAE-\u1AFF\u1B4C-\u1B4F\u1B7D-\u1B7F\u1BF4-\u1BFB\u1C38-\u1C3A\u1C4A-\u1C4C\u1C80-\u1CBF\u1CC8-\u1CCF\u1CF7-\u1CFF\u1DE7-\u1DFB\u1F16\u1F17\u1F1E\u1F1F\u1F46\u1F47\u1F4E\u1F4F\u1F58\u1F5A\u1F5C\u1F5E\u1F7E\u1F7F\u1FB5\u1FC5\u1FD4\u1FD5\u1FDC\u1FF0\u1FF1\u1FF5\u1FFF\u200B-\u200F\u202A-\u202E\u2060-\u206F\u2072\u2073\u208F\u209D-\u209F\u20BB-\u20CF\u20F1-\u20FF\u218A-\u218F\u23F4-\u23FF\u2427-\u243F\u244B-\u245F\u2700\u2B4D-\u2B4F\u2B5A-\u2BFF\u2C2F\u2C5F\u2CF4-\u2CF8\u2D26\u2D28-\u2D2C\u2D2E\u2D2F\u2D68-\u2D6E\u2D71-\u2D7E\u2D97-\u2D9F\u2DA7\u2DAF\u2DB7\u2DBF\u2DC7\u2DCF\u2DD7\u2DDF\u2E3C-\u2E7F\u2E9A\u2EF4-\u2EFF\u2FD6-\u2FEF\u2FFC-\u2FFF\u3040\u3097\u3098\u3100-\u3104\u312E-\u3130\u318F\u31BB-\u31BF\u31E4-\u31EF\u321F\u32FF\u4DB6-\u4DBF\u9FCD-\u9FFF\uA48D-\uA48F\uA4C7-\uA4CF\uA62C-\uA63F\uA698-\uA69E\uA6F8-\uA6FF\uA78F\uA794-\uA79F\uA7AB-\uA7F7\uA82C-\uA82F\uA83A-\uA83F\uA878-\uA87F\uA8C5-\uA8CD\uA8DA-\uA8DF\uA8FC-\uA8FF\uA954-\uA95E\uA97D-\uA97F\uA9CE\uA9DA-\uA9DD\uA9E0-\uA9FF\uAA37-\uAA3F\uAA4E\uAA4F\uAA5A\uAA5B\uAA7C-\uAA7F\uAAC3-\uAADA\uAAF7-\uAB00\uAB07\uAB08\uAB0F\uAB10\uAB17-\uAB1F\uAB27\uAB2F-\uABBF\uABEE\uABEF\uABFA-\uABFF\uD7A4-\uD7AF\uD7C7-\uD7CA\uD7FC-\uD7FF\uE000-\uF8FF\uFA6E\uFA6F\uFADA-\uFAFF\uFB07-\uFB12\uFB18-\uFB1C\uFB37\uFB3D\uFB3F\uFB42\uFB45\uFBC2-\uFBD2\uFD40-\uFD4F\uFD90\uFD91\uFDC8-\uFDEF\uFDFE\uFDFF\uFE1A-\uFE1F\uFE27-\uFE2F\uFE53\uFE67\uFE6C-\uFE6F\uFE75\uFEFD-\uFF00\uFFBF-\uFFC1\uFFC8\uFFC9\uFFD0\uFFD1\uFFD8\uFFD9\uFFDD-\uFFDF\uFFE7\uFFEF-\uFFFB\uFFFE\uFFFF]/g;
|
const re = /[\0-\x08\x0B-\x0C\x0E-\x1F\x7F-\x9F\xAD\u0378\u0379\u037F-\u0383\u038B\u038D\u03A2\u0528-\u0530\u0557\u0558\u0560\u0588\u058B-\u058E\u0590\u05C8-\u05CF\u05EB-\u05EF\u05F5-\u0605\u061C\u061D\u06DD\u070E\u070F\u074B\u074C\u07B2-\u07BF\u07FB-\u07FF\u082E\u082F\u083F\u085C\u085D\u085F-\u089F\u08A1\u08AD-\u08E3\u08FF\u0978\u0980\u0984\u098D\u098E\u0991\u0992\u09A9\u09B1\u09B3-\u09B5\u09BA\u09BB\u09C5\u09C6\u09C9\u09CA\u09CF-\u09D6\u09D8-\u09DB\u09DE\u09E4\u09E5\u09FC-\u0A00\u0A04\u0A0B-\u0A0E\u0A11\u0A12\u0A29\u0A31\u0A34\u0A37\u0A3A\u0A3B\u0A3D\u0A43-\u0A46\u0A49\u0A4A\u0A4E-\u0A50\u0A52-\u0A58\u0A5D\u0A5F-\u0A65\u0A76-\u0A80\u0A84\u0A8E\u0A92\u0AA9\u0AB1\u0AB4\u0ABA\u0ABB\u0AC6\u0ACA\u0ACE\u0ACF\u0AD1-\u0ADF\u0AE4\u0AE5\u0AF2-\u0B00\u0B04\u0B0D\u0B0E\u0B11\u0B12\u0B29\u0B31\u0B34\u0B3A\u0B3B\u0B45\u0B46\u0B49\u0B4A\u0B4E-\u0B55\u0B58-\u0B5B\u0B5E\u0B64\u0B65\u0B78-\u0B81\u0B84\u0B8B-\u0B8D\u0B91\u0B96-\u0B98\u0B9B\u0B9D\u0BA0-\u0BA2\u0BA5-\u0BA7\u0BAB-\u0BAD\u0BBA-\u0BBD\u0BC3-\u0BC5\u0BC9\u0BCE\u0BCF\u0BD1-\u0BD6\u0BD8-\u0BE5\u0BFB-\u0C00\u0C04\u0C0D\u0C11\u0C29\u0C34\u0C3A-\u0C3C\u0C45\u0C49\u0C4E-\u0C54\u0C57\u0C5A-\u0C5F\u0C64\u0C65\u0C70-\u0C77\u0C80\u0C81\u0C84\u0C8D\u0C91\u0CA9\u0CB4\u0CBA\u0CBB\u0CC5\u0CC9\u0CCE-\u0CD4\u0CD7-\u0CDD\u0CDF\u0CE4\u0CE5\u0CF0\u0CF3-\u0D01\u0D04\u0D0D\u0D11\u0D3B\u0D3C\u0D45\u0D49\u0D4F-\u0D56\u0D58-\u0D5F\u0D64\u0D65\u0D76-\u0D78\u0D80\u0D81\u0D84\u0D97-\u0D99\u0DB2\u0DBC\u0DBE\u0DBF\u0DC7-\u0DC9\u0DCB-\u0DCE\u0DD5\u0DD7\u0DE0-\u0DF1\u0DF5-\u0E00\u0E3B-\u0E3E\u0E5C-\u0E80\u0E83\u0E85\u0E86\u0E89\u0E8B\u0E8C\u0E8E-\u0E93\u0E98\u0EA0\u0EA4\u0EA6\u0EA8\u0EA9\u0EAC\u0EBA\u0EBE\u0EBF\u0EC5\u0EC7\u0ECE\u0ECF\u0EDA\u0EDB\u0EE0-\u0EFF\u0F48\u0F6D-\u0F70\u0F98\u0FBD\u0FCD\u0FDB-\u0FFF\u10C6\u10C8-\u10CC\u10CE\u10CF\u1249\u124E\u124F\u1257\u1259\u125E\u125F\u1289\u128E\u128F\u12B1\u12B6\u12B7\u12BF\u12C1\u12C6\u12C7\u12D7\u1311\u1316\u1317\u135B\u135C\u137D-\u137F\u139A-\u139F\u13F5-\u13FF\u169D-\u169F\u16F1-\u16FF\u170D\u1715-\u171F\u1737-\u173F\u1754-\u175F\u176D\u1771\u1774-\u177F\u17DE\u17DF\u17EA-\u17EF\u17FA-\u17FF\u180F\u181A-\u181F\u1878-\u187F\u18AB-\u18AF\u18F6-\u18FF\u191D-\u191F\u192C-\u192F\u193C-\u193F\u1941-\u1943\u196E\u196F\u1975-\u197F\u19AC-\u19AF\u19CA-\u19CF\u19DB-\u19DD\u1A1C\u1A1D\u1A5F\u1A7D\u1A7E\u1A8A-\u1A8F\u1A9A-\u1A9F\u1AAE-\u1AFF\u1B4C-\u1B4F\u1B7D-\u1B7F\u1BF4-\u1BFB\u1C38-\u1C3A\u1C4A-\u1C4C\u1C80-\u1CBF\u1CC8-\u1CCF\u1CF7-\u1CFF\u1DE7-\u1DFB\u1F16\u1F17\u1F1E\u1F1F\u1F46\u1F47\u1F4E\u1F4F\u1F58\u1F5A\u1F5C\u1F5E\u1F7E\u1F7F\u1FB5\u1FC5\u1FD4\u1FD5\u1FDC\u1FF0\u1FF1\u1FF5\u1FFF\u200B-\u200F\u202A-\u202E\u2060-\u206F\u2072\u2073\u208F\u209D-\u209F\u20BB-\u20CF\u20F1-\u20FF\u218A-\u218F\u23F4-\u23FF\u2427-\u243F\u244B-\u245F\u2700\u2B4D-\u2B4F\u2B5A-\u2BFF\u2C2F\u2C5F\u2CF4-\u2CF8\u2D26\u2D28-\u2D2C\u2D2E\u2D2F\u2D68-\u2D6E\u2D71-\u2D7E\u2D97-\u2D9F\u2DA7\u2DAF\u2DB7\u2DBF\u2DC7\u2DCF\u2DD7\u2DDF\u2E3C-\u2E7F\u2E9A\u2EF4-\u2EFF\u2FD6-\u2FEF\u2FFC-\u2FFF\u3040\u3097\u3098\u3100-\u3104\u312E-\u3130\u318F\u31BB-\u31BF\u31E4-\u31EF\u321F\u32FF\u4DB6-\u4DBF\u9FCD-\u9FFF\uA48D-\uA48F\uA4C7-\uA4CF\uA62C-\uA63F\uA698-\uA69E\uA6F8-\uA6FF\uA78F\uA794-\uA79F\uA7AB-\uA7F7\uA82C-\uA82F\uA83A-\uA83F\uA878-\uA87F\uA8C5-\uA8CD\uA8DA-\uA8DF\uA8FC-\uA8FF\uA954-\uA95E\uA97D-\uA97F\uA9CE\uA9DA-\uA9DD\uA9E0-\uA9FF\uAA37-\uAA3F\uAA4E\uAA4F\uAA5A\uAA5B\uAA7C-\uAA7F\uAAC3-\uAADA\uAAF7-\uAB00\uAB07\uAB08\uAB0F\uAB10\uAB17-\uAB1F\uAB27\uAB2F-\uABBF\uABEE\uABEF\uABFA-\uABFF\uD7A4-\uD7AF\uD7C7-\uD7CA\uD7FC-\uD7FF\uE000-\uF8FF\uFA6E\uFA6F\uFADA-\uFAFF\uFB07-\uFB12\uFB18-\uFB1C\uFB37\uFB3D\uFB3F\uFB42\uFB45\uFBC2-\uFBD2\uFD40-\uFD4F\uFD90\uFD91\uFDC8-\uFDEF\uFDFE\uFDFF\uFE1A-\uFE1F\uFE27-\uFE2F\uFE53\uFE67\uFE6C-\uFE6F\uFE75\uFEFD-\uFF00\uFFBF-\uFFC1\uFFC8\uFFC9\uFFD0\uFFD1\uFFD8\uFFD9\uFFDD-\uFFDF\uFFE7\uFFEF-\uFFFB\uFFFE\uFFFF]/g;
|
||||||
const wsRe = /[\x09-\x10\x0D\u2028\u2029]/g;
|
const wsRe = /[\x09-\x10\x0D\u2028\u2029]/g;
|
||||||
@@ -591,6 +596,44 @@ class Utils {
|
|||||||
return utf8 ? Utils.byteArrayToUtf8(arr) : Utils.byteArrayToChars(arr);
|
return utf8 ? Utils.byteArrayToUtf8(arr) : Utils.byteArrayToChars(arr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Calculates the Shannon entropy for a given set of data.
|
||||||
|
*
|
||||||
|
* @param {Uint8Array|ArrayBuffer} input
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
static calculateShannonEntropy(data) {
|
||||||
|
if (data instanceof ArrayBuffer) {
|
||||||
|
data = new Uint8Array(data);
|
||||||
|
}
|
||||||
|
const prob = [],
|
||||||
|
occurrences = new Array(256).fill(0);
|
||||||
|
|
||||||
|
// Count occurrences of each byte in the input
|
||||||
|
let i;
|
||||||
|
for (i = 0; i < data.length; i++) {
|
||||||
|
occurrences[data[i]]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store probability list
|
||||||
|
for (i = 0; i < occurrences.length; i++) {
|
||||||
|
if (occurrences[i] > 0) {
|
||||||
|
prob.push(occurrences[i] / data.length);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate Shannon entropy
|
||||||
|
let entropy = 0,
|
||||||
|
p;
|
||||||
|
|
||||||
|
for (i = 0; i < prob.length; i++) {
|
||||||
|
p = prob[i];
|
||||||
|
entropy += p * Math.log(p) / Math.log(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -entropy;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses CSV data and returns it as a two dimensional array or strings.
|
* Parses CSV data and returns it as a two dimensional array or strings.
|
||||||
@@ -666,8 +709,21 @@ class Utils {
|
|||||||
* Utils.stripHtmlTags("<div>Test</div>");
|
* Utils.stripHtmlTags("<div>Test</div>");
|
||||||
*/
|
*/
|
||||||
static stripHtmlTags(htmlStr, removeScriptAndStyle=false) {
|
static stripHtmlTags(htmlStr, removeScriptAndStyle=false) {
|
||||||
|
/**
|
||||||
|
* Recursively remove a pattern from a string until there are no more matches.
|
||||||
|
* Avoids incomplete sanitization e.g. "aabcbc".replace(/abc/g, "") === "abc"
|
||||||
|
*
|
||||||
|
* @param {RegExp} pattern
|
||||||
|
* @param {string} str
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function recursiveRemove(pattern, str) {
|
||||||
|
const newStr = str.replace(pattern, "");
|
||||||
|
return newStr.length === str.length ? newStr : recursiveRemove(pattern, newStr);
|
||||||
|
}
|
||||||
|
|
||||||
if (removeScriptAndStyle) {
|
if (removeScriptAndStyle) {
|
||||||
htmlStr = htmlStr.replace(/<(script|style)[^>]*>.*<\/(script|style)>/gmi, "");
|
htmlStr = recursiveRemove(/<(script|style)[^>]*>.*?<\/(script|style)>/gi, htmlStr);
|
||||||
}
|
}
|
||||||
return htmlStr.replace(/<[^>]+>/g, "");
|
return htmlStr.replace(/<[^>]+>/g, "");
|
||||||
}
|
}
|
||||||
@@ -691,11 +747,10 @@ class Utils {
|
|||||||
">": ">",
|
">": ">",
|
||||||
'"': """,
|
'"': """,
|
||||||
"'": "'", // ' not recommended because it's not in the HTML spec
|
"'": "'", // ' not recommended because it's not in the HTML spec
|
||||||
"/": "/", // forward slash is included as it helps end an HTML entity
|
|
||||||
"`": "`"
|
"`": "`"
|
||||||
};
|
};
|
||||||
|
|
||||||
return str.replace(/[&<>"'/`]/g, function (match) {
|
return str.replace(/[&<>"'`]/g, function (match) {
|
||||||
return HTML_CHARS[match];
|
return HTML_CHARS[match];
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -758,15 +813,15 @@ class Utils {
|
|||||||
"%7E": "~",
|
"%7E": "~",
|
||||||
"%21": "!",
|
"%21": "!",
|
||||||
"%24": "$",
|
"%24": "$",
|
||||||
//"%26": "&",
|
// "%26": "&",
|
||||||
"%27": "'",
|
"%27": "'",
|
||||||
"%28": "(",
|
"%28": "(",
|
||||||
"%29": ")",
|
"%29": ")",
|
||||||
"%2A": "*",
|
"%2A": "*",
|
||||||
//"%2B": "+",
|
// "%2B": "+",
|
||||||
"%2C": ",",
|
"%2C": ",",
|
||||||
"%3B": ";",
|
"%3B": ";",
|
||||||
//"%3D": "=",
|
// "%3D": "=",
|
||||||
"%3A": ":",
|
"%3A": ":",
|
||||||
"%40": "@",
|
"%40": "@",
|
||||||
"%2F": "/",
|
"%2F": "/",
|
||||||
@@ -841,7 +896,7 @@ class Utils {
|
|||||||
while ((m = recipeRegex.exec(recipe))) {
|
while ((m = recipeRegex.exec(recipe))) {
|
||||||
// Translate strings in args back to double-quotes
|
// Translate strings in args back to double-quotes
|
||||||
args = m[2]
|
args = m[2]
|
||||||
.replace(/"/g, '\\"') // Escape double quotes
|
.replace(/"/g, '\\"') // Escape double quotes lgtm [js/incomplete-sanitization]
|
||||||
.replace(/(^|,|{|:)'/g, '$1"') // Replace opening ' with "
|
.replace(/(^|,|{|:)'/g, '$1"') // Replace opening ' with "
|
||||||
.replace(/([^\\]|(?:\\\\)+)'(,|:|}|$)/g, '$1"$2') // Replace closing ' with "
|
.replace(/([^\\]|(?:\\\\)+)'(,|:|}|$)/g, '$1"$2') // Replace closing ' with "
|
||||||
.replace(/\\'/g, "'"); // Unescape single quotes
|
.replace(/\\'/g, "'"); // Unescape single quotes
|
||||||
@@ -1144,6 +1199,7 @@ class Utils {
|
|||||||
"CRLF": /\r\n/g,
|
"CRLF": /\r\n/g,
|
||||||
"Forward slash": /\//g,
|
"Forward slash": /\//g,
|
||||||
"Backslash": /\\/g,
|
"Backslash": /\\/g,
|
||||||
|
"0x with comma": /,?0x/g,
|
||||||
"0x": /0x/g,
|
"0x": /0x/g,
|
||||||
"\\x": /\\x/g,
|
"\\x": /\\x/g,
|
||||||
"None": /\s+/g // Included here to remove whitespace when there shouldn't be any
|
"None": /\s+/g // Included here to remove whitespace when there shouldn't be any
|
||||||
@@ -1297,7 +1353,7 @@ export function sendStatusMessage(msg) {
|
|||||||
self.sendStatusMessage(msg);
|
self.sendStatusMessage(msg);
|
||||||
else if (isWebEnvironment())
|
else if (isWebEnvironment())
|
||||||
app.alert(msg, 10000);
|
app.alert(msg, 10000);
|
||||||
else if (isNodeEnvironment())
|
else if (isNodeEnvironment() && !global.TESTING)
|
||||||
// eslint-disable-next-line no-console
|
// eslint-disable-next-line no-console
|
||||||
console.debug(msg);
|
console.debug(msg);
|
||||||
}
|
}
|
||||||
@@ -1335,14 +1391,14 @@ export function debounce(func, wait, id, scope, args) {
|
|||||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart
|
||||||
if (!String.prototype.padStart) {
|
if (!String.prototype.padStart) {
|
||||||
String.prototype.padStart = function padStart(targetLength, padString) {
|
String.prototype.padStart = function padStart(targetLength, padString) {
|
||||||
targetLength = targetLength>>0; //floor if number or convert non-number to 0;
|
targetLength = targetLength>>0; // floor if number or convert non-number to 0;
|
||||||
padString = String((typeof padString !== "undefined" ? padString : " "));
|
padString = String((typeof padString !== "undefined" ? padString : " "));
|
||||||
if (this.length > targetLength) {
|
if (this.length > targetLength) {
|
||||||
return String(this);
|
return String(this);
|
||||||
} else {
|
} else {
|
||||||
targetLength = targetLength-this.length;
|
targetLength = targetLength-this.length;
|
||||||
if (targetLength > padString.length) {
|
if (targetLength > padString.length) {
|
||||||
padString += padString.repeat(targetLength/padString.length); //append to original to ensure we are longer than needed
|
padString += padString.repeat(targetLength/padString.length); // append to original to ensure we are longer than needed
|
||||||
}
|
}
|
||||||
return padString.slice(0, targetLength) + String(this);
|
return padString.slice(0, targetLength) + String(this);
|
||||||
}
|
}
|
||||||
@@ -1354,14 +1410,14 @@ if (!String.prototype.padStart) {
|
|||||||
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padEnd
|
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padEnd
|
||||||
if (!String.prototype.padEnd) {
|
if (!String.prototype.padEnd) {
|
||||||
String.prototype.padEnd = function padEnd(targetLength, padString) {
|
String.prototype.padEnd = function padEnd(targetLength, padString) {
|
||||||
targetLength = targetLength>>0; //floor if number or convert non-number to 0;
|
targetLength = targetLength>>0; // floor if number or convert non-number to 0;
|
||||||
padString = String((typeof padString !== "undefined" ? padString : " "));
|
padString = String((typeof padString !== "undefined" ? padString : " "));
|
||||||
if (this.length > targetLength) {
|
if (this.length > targetLength) {
|
||||||
return String(this);
|
return String(this);
|
||||||
} else {
|
} else {
|
||||||
targetLength = targetLength-this.length;
|
targetLength = targetLength-this.length;
|
||||||
if (targetLength > padString.length) {
|
if (targetLength > padString.length) {
|
||||||
padString += padString.repeat(targetLength/padString.length); //append to original to ensure we are longer than needed
|
padString += padString.repeat(targetLength/padString.length); // append to original to ensure we are longer than needed
|
||||||
}
|
}
|
||||||
return String(this) + padString.slice(0, targetLength);
|
return String(this) + padString.slice(0, targetLength);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,15 +18,15 @@
|
|||||||
"From Binary",
|
"From Binary",
|
||||||
"To Octal",
|
"To Octal",
|
||||||
"From Octal",
|
"From Octal",
|
||||||
"To Base64",
|
|
||||||
"From Base64",
|
|
||||||
"Show Base64 offsets",
|
|
||||||
"To Base32",
|
"To Base32",
|
||||||
"From Base32",
|
"From Base32",
|
||||||
"To Base58",
|
"To Base58",
|
||||||
"From Base58",
|
"From Base58",
|
||||||
"To Base62",
|
"To Base62",
|
||||||
"From Base62",
|
"From Base62",
|
||||||
|
"To Base64",
|
||||||
|
"From Base64",
|
||||||
|
"Show Base64 offsets",
|
||||||
"To Base85",
|
"To Base85",
|
||||||
"From Base85",
|
"From Base85",
|
||||||
"To Base",
|
"To Base",
|
||||||
@@ -39,6 +39,7 @@
|
|||||||
"URL Decode",
|
"URL Decode",
|
||||||
"Escape Unicode Characters",
|
"Escape Unicode Characters",
|
||||||
"Unescape Unicode Characters",
|
"Unescape Unicode Characters",
|
||||||
|
"Normalise Unicode",
|
||||||
"To Quoted Printable",
|
"To Quoted Printable",
|
||||||
"From Quoted Printable",
|
"From Quoted Printable",
|
||||||
"To Punycode",
|
"To Punycode",
|
||||||
@@ -94,7 +95,11 @@
|
|||||||
"Affine Cipher Decode",
|
"Affine Cipher Decode",
|
||||||
"A1Z26 Cipher Encode",
|
"A1Z26 Cipher Encode",
|
||||||
"A1Z26 Cipher Decode",
|
"A1Z26 Cipher Decode",
|
||||||
|
"Rail Fence Cipher Encode",
|
||||||
|
"Rail Fence Cipher Decode",
|
||||||
"Atbash Cipher",
|
"Atbash Cipher",
|
||||||
|
"CipherSaber2 Encrypt",
|
||||||
|
"CipherSaber2 Decrypt",
|
||||||
"Substitute",
|
"Substitute",
|
||||||
"Derive PBKDF2 key",
|
"Derive PBKDF2 key",
|
||||||
"Derive EVP key",
|
"Derive EVP key",
|
||||||
@@ -110,7 +115,8 @@
|
|||||||
"Bombe",
|
"Bombe",
|
||||||
"Multiple Bombe",
|
"Multiple Bombe",
|
||||||
"Typex",
|
"Typex",
|
||||||
"Lorenz"
|
"Lorenz",
|
||||||
|
"Colossus"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -128,6 +134,11 @@
|
|||||||
"PGP Verify",
|
"PGP Verify",
|
||||||
"PGP Encrypt and Sign",
|
"PGP Encrypt and Sign",
|
||||||
"PGP Decrypt and Verify",
|
"PGP Decrypt and Verify",
|
||||||
|
"Generate RSA Key Pair",
|
||||||
|
"RSA Sign",
|
||||||
|
"RSA Verify",
|
||||||
|
"RSA Encrypt",
|
||||||
|
"RSA Decrypt",
|
||||||
"Parse SSH Host Key"
|
"Parse SSH Host Key"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -194,8 +205,10 @@
|
|||||||
"ops": [
|
"ops": [
|
||||||
"Encode text",
|
"Encode text",
|
||||||
"Decode text",
|
"Decode text",
|
||||||
|
"Unicode Text Format",
|
||||||
"Remove Diacritics",
|
"Remove Diacritics",
|
||||||
"Unescape Unicode Characters"
|
"Unescape Unicode Characters",
|
||||||
|
"Convert to NATO alphabet"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -235,6 +248,7 @@
|
|||||||
"Convert co-ordinate format",
|
"Convert co-ordinate format",
|
||||||
"Show on map",
|
"Show on map",
|
||||||
"Parse UNIX file permissions",
|
"Parse UNIX file permissions",
|
||||||
|
"Parse ObjectID timestamp",
|
||||||
"Swap endianness",
|
"Swap endianness",
|
||||||
"Parse colour code",
|
"Parse colour code",
|
||||||
"Escape string",
|
"Escape string",
|
||||||
@@ -253,6 +267,7 @@
|
|||||||
"Windows Filetime to UNIX Timestamp",
|
"Windows Filetime to UNIX Timestamp",
|
||||||
"UNIX Timestamp to Windows Filetime",
|
"UNIX Timestamp to Windows Filetime",
|
||||||
"Extract dates",
|
"Extract dates",
|
||||||
|
"Get Time",
|
||||||
"Sleep"
|
"Sleep"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -272,6 +287,7 @@
|
|||||||
"JPath expression",
|
"JPath expression",
|
||||||
"CSS selector",
|
"CSS selector",
|
||||||
"Extract EXIF",
|
"Extract EXIF",
|
||||||
|
"Extract ID3",
|
||||||
"Extract Files"
|
"Extract Files"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
@@ -305,6 +321,7 @@
|
|||||||
"SHA1",
|
"SHA1",
|
||||||
"SHA2",
|
"SHA2",
|
||||||
"SHA3",
|
"SHA3",
|
||||||
|
"SM3",
|
||||||
"Keccak",
|
"Keccak",
|
||||||
"Shake",
|
"Shake",
|
||||||
"RIPEMD",
|
"RIPEMD",
|
||||||
@@ -329,6 +346,7 @@
|
|||||||
"Fletcher-32 Checksum",
|
"Fletcher-32 Checksum",
|
||||||
"Fletcher-64 Checksum",
|
"Fletcher-64 Checksum",
|
||||||
"Adler-32 Checksum",
|
"Adler-32 Checksum",
|
||||||
|
"Luhn Checksum",
|
||||||
"CRC-8 Checksum",
|
"CRC-8 Checksum",
|
||||||
"CRC-16 Checksum",
|
"CRC-16 Checksum",
|
||||||
"CRC-32 Checksum",
|
"CRC-32 Checksum",
|
||||||
@@ -388,6 +406,7 @@
|
|||||||
"ops": [
|
"ops": [
|
||||||
"Render Image",
|
"Render Image",
|
||||||
"Play Media",
|
"Play Media",
|
||||||
|
"Generate Image",
|
||||||
"Optical Character Recognition",
|
"Optical Character Recognition",
|
||||||
"Remove EXIF",
|
"Remove EXIF",
|
||||||
"Extract EXIF",
|
"Extract EXIF",
|
||||||
|
|||||||
@@ -9,7 +9,7 @@
|
|||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*eslint no-console: ["off"] */
|
/* eslint no-console: ["off"] */
|
||||||
|
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
@@ -42,13 +42,10 @@ for (const opObj in Ops) {
|
|||||||
outputType: op.presentType,
|
outputType: op.presentType,
|
||||||
flowControl: op.flowControl,
|
flowControl: op.flowControl,
|
||||||
manualBake: op.manualBake,
|
manualBake: op.manualBake,
|
||||||
args: op.args
|
args: op.args,
|
||||||
|
checks: op.checks
|
||||||
};
|
};
|
||||||
|
|
||||||
if ("patterns" in op) {
|
|
||||||
operationConfig[op.name].patterns = op.patterns;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(op.module in modules))
|
if (!(op.module in modules))
|
||||||
modules[op.module] = {};
|
modules[op.module] = {};
|
||||||
modules[op.module][op.name] = opObj;
|
modules[op.module][op.name] = opObj;
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*eslint no-console: ["off"] */
|
/* eslint no-console: ["off"] */
|
||||||
|
|
||||||
import path from "path";
|
import path from "path";
|
||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
* @license Apache-2.0
|
* @license Apache-2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*eslint no-console: ["off"] */
|
/* eslint no-console: ["off"] */
|
||||||
|
|
||||||
import prompt from "prompt";
|
import prompt from "prompt";
|
||||||
import colors from "colors";
|
import colors from "colors";
|
||||||
@@ -121,7 +121,7 @@ prompt.get(schema, (err, result) => {
|
|||||||
|
|
||||||
const moduleName = result.opName.replace(/\w\S*/g, txt => {
|
const moduleName = result.opName.replace(/\w\S*/g, txt => {
|
||||||
return txt.charAt(0).toUpperCase() + txt.substr(1);
|
return txt.charAt(0).toUpperCase() + txt.substr(1);
|
||||||
}).replace(/[\s-()/./]/g, "");
|
}).replace(/[\s-()./]/g, "");
|
||||||
|
|
||||||
|
|
||||||
const template = `/**
|
const template = `/**
|
||||||
@@ -208,7 +208,7 @@ ${result.highlight ? `
|
|||||||
export default ${moduleName};
|
export default ${moduleName};
|
||||||
`;
|
`;
|
||||||
|
|
||||||
//console.log(template);
|
// console.log(template);
|
||||||
|
|
||||||
const filename = path.join(dir, `./${moduleName}.mjs`);
|
const filename = path.join(dir, `./${moduleName}.mjs`);
|
||||||
if (fs.existsSync(filename)) {
|
if (fs.existsSync(filename)) {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ class DishJSON extends DishType {
|
|||||||
*/
|
*/
|
||||||
static toArrayBuffer() {
|
static toArrayBuffer() {
|
||||||
DishJSON.checkForValue(this.value);
|
DishJSON.checkForValue(this.value);
|
||||||
this.value = this.value ? Utils.strToArrayBuffer(JSON.stringify(this.value, null, 4)) : new ArrayBuffer;
|
this.value = this.value !== undefined ? Utils.strToArrayBuffer(JSON.stringify(this.value, null, 4)) : new ArrayBuffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import DishType from "./DishType.mjs";
|
import DishType from "./DishType.mjs";
|
||||||
import { isNodeEnvironment } from "../Utils.mjs";
|
import Utils, { isNodeEnvironment } from "../Utils.mjs";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -16,13 +16,14 @@ class DishListFile extends DishType {
|
|||||||
/**
|
/**
|
||||||
* convert the given value to a ArrayBuffer
|
* convert the given value to a ArrayBuffer
|
||||||
*/
|
*/
|
||||||
static toArrayBuffer() {
|
static async toArrayBuffer() {
|
||||||
DishListFile.checkForValue(this.value);
|
DishListFile.checkForValue(this.value);
|
||||||
|
|
||||||
if (isNodeEnvironment()) {
|
if (isNodeEnvironment()) {
|
||||||
this.value = this.value.map(file => Uint8Array.from(file.data));
|
this.value = this.value.map(file => Uint8Array.from(file.data));
|
||||||
|
} else {
|
||||||
|
this.value = await DishListFile.concatenateTypedArraysWithTypedElements(...this.value);
|
||||||
}
|
}
|
||||||
this.value = DishListFile.concatenateTypedArrays(...this.value).buffer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -33,6 +34,27 @@ class DishListFile extends DishType {
|
|||||||
this.value = [new File(this.value, "unknown")];
|
this.value = [new File(this.value, "unknown")];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Concatenates a list of typed elements together.
|
||||||
|
*
|
||||||
|
* @param {Uint8Array[]} arrays
|
||||||
|
* @returns {Uint8Array}
|
||||||
|
*/
|
||||||
|
static async concatenateTypedArraysWithTypedElements(...arrays) {
|
||||||
|
let totalLength = 0;
|
||||||
|
for (const arr of arrays) {
|
||||||
|
totalLength += arr.size;
|
||||||
|
}
|
||||||
|
const myArray = new Uint8Array(totalLength);
|
||||||
|
|
||||||
|
let offset = 0;
|
||||||
|
for (const arr of arrays) {
|
||||||
|
const data = await Utils.readFile(arr);
|
||||||
|
myArray.set(data, offset);
|
||||||
|
offset += data.length;
|
||||||
|
}
|
||||||
|
return myArray;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Concatenates a list of Uint8Arrays together
|
* Concatenates a list of Uint8Arrays together
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ export const ALPHABET_OPTIONS = [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "IPv6",
|
name: "IPv6",
|
||||||
value: "0-9A-Za-z!#$%&()*+\\-;<=>?@^_`{|~}",
|
value: "0-9A-Za-z!#$%&()*+\\-;<=>?@^_`{|}~",
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -32,9 +32,9 @@ export const ALPHABET_OPTIONS = [
|
|||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
export function alphabetName(alphabet) {
|
export function alphabetName(alphabet) {
|
||||||
alphabet = alphabet.replace("'", "'");
|
alphabet = alphabet.replace(/'/g, "'");
|
||||||
alphabet = alphabet.replace("\"", """);
|
alphabet = alphabet.replace(/"/g, """);
|
||||||
alphabet = alphabet.replace("\\", "\");
|
alphabet = alphabet.replace(/\\/g, "\");
|
||||||
let name;
|
let name;
|
||||||
|
|
||||||
ALPHABET_OPTIONS.forEach(function(a) {
|
ALPHABET_OPTIONS.forEach(function(a) {
|
||||||
|
|||||||
@@ -38,7 +38,7 @@
|
|||||||
|
|
||||||
const crypto = {};
|
const crypto = {};
|
||||||
|
|
||||||
import forge from "node-forge/dist/forge.min.js";
|
import forge from "node-forge";
|
||||||
|
|
||||||
|
|
||||||
/* dojo-release-1.8.1/dojo/_base/lang.js.uncompressed.js */
|
/* dojo-release-1.8.1/dojo/_base/lang.js.uncompressed.js */
|
||||||
|
|||||||
@@ -86,8 +86,8 @@ export function getScatterValues(input, recordDelimiter, fieldDelimiter, columnH
|
|||||||
}
|
}
|
||||||
|
|
||||||
values = values.map(row => {
|
values = values.map(row => {
|
||||||
const x = parseFloat(row[0], 10),
|
const x = parseFloat(row[0]),
|
||||||
y = parseFloat(row[1], 10);
|
y = parseFloat(row[1]);
|
||||||
|
|
||||||
if (Number.isNaN(x)) throw new OperationError("Values must be numbers in base 10.");
|
if (Number.isNaN(x)) throw new OperationError("Values must be numbers in base 10.");
|
||||||
if (Number.isNaN(y)) throw new OperationError("Values must be numbers in base 10.");
|
if (Number.isNaN(y)) throw new OperationError("Values must be numbers in base 10.");
|
||||||
@@ -121,8 +121,8 @@ export function getScatterValuesWithColour(input, recordDelimiter, fieldDelimite
|
|||||||
}
|
}
|
||||||
|
|
||||||
values = values.map(row => {
|
values = values.map(row => {
|
||||||
const x = parseFloat(row[0], 10),
|
const x = parseFloat(row[0]),
|
||||||
y = parseFloat(row[1], 10),
|
y = parseFloat(row[1]),
|
||||||
colour = row[2];
|
colour = row[2];
|
||||||
|
|
||||||
if (Number.isNaN(x)) throw new OperationError("Values must be numbers in base 10.");
|
if (Number.isNaN(x)) throw new OperationError("Values must be numbers in base 10.");
|
||||||
@@ -157,7 +157,7 @@ export function getSeriesValues(input, recordDelimiter, fieldDelimiter, columnHe
|
|||||||
values.forEach(row => {
|
values.forEach(row => {
|
||||||
const serie = row[0],
|
const serie = row[0],
|
||||||
xVal = row[1],
|
xVal = row[1],
|
||||||
val = parseFloat(row[2], 10);
|
val = parseFloat(row[2]);
|
||||||
|
|
||||||
if (Number.isNaN(val)) throw new OperationError("Values must be numbers in base 10.");
|
if (Number.isNaN(val)) throw new OperationError("Values must be numbers in base 10.");
|
||||||
|
|
||||||
|
|||||||
@@ -164,3 +164,15 @@ export const IO_FORMAT = {
|
|||||||
"Simplified Chinese GB18030 (54936)": 54936,
|
"Simplified Chinese GB18030 (54936)": 54936,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unicode Normalisation Forms
|
||||||
|
*
|
||||||
|
* @author Matthieu [m@tthieu.xyz]
|
||||||
|
* @copyright Crown Copyright 2019
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Character encoding format mappings.
|
||||||
|
*/
|
||||||
|
export const UNICODE_NORMALISATION_FORMS = ["NFD", "NFC", "NFKD", "NFKC"];
|
||||||
|
|||||||
34
src/core/lib/CipherSaber2.mjs
Normal file
34
src/core/lib/CipherSaber2.mjs
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
/**
|
||||||
|
* @author n1073645 [n1073645@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2020
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
export function encode(tempIVP, key, rounds, input) {
|
||||||
|
const ivp = new Uint8Array(key.concat(tempIVP));
|
||||||
|
const state = new Array(256).fill(0);
|
||||||
|
let j = 0, i = 0;
|
||||||
|
const result = [];
|
||||||
|
|
||||||
|
// Mixing states based off of IV.
|
||||||
|
for (let i = 0; i < 256; i++)
|
||||||
|
state[i] = i;
|
||||||
|
const ivpLength = ivp.length;
|
||||||
|
for (let r = 0; r < rounds; r ++) {
|
||||||
|
for (let k = 0; k < 256; k++) {
|
||||||
|
j = (j + state[k] + ivp[k % ivpLength]) % 256;
|
||||||
|
[state[k], state[j]] = [state[j], state[k]];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
j = 0;
|
||||||
|
i = 0;
|
||||||
|
|
||||||
|
// XOR cipher with key.
|
||||||
|
for (let x = 0; x < input.length; x++) {
|
||||||
|
i = (++i) % 256;
|
||||||
|
j = (j + state[i]) % 256;
|
||||||
|
[state[i], state[j]] = [state[j], state[i]];
|
||||||
|
const n = (state[i] + state[j]) % 256;
|
||||||
|
result.push(state[n] ^ input[x]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
417
src/core/lib/Colossus.mjs
Normal file
417
src/core/lib/Colossus.mjs
Normal file
@@ -0,0 +1,417 @@
|
|||||||
|
/**
|
||||||
|
* Colossus - an emulation of the world's first electronic computer
|
||||||
|
*
|
||||||
|
* @author VirtualColossus [martin@virtualcolossus.co.uk]
|
||||||
|
* @copyright Crown Copyright 2019
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
import {INIT_PATTERNS, ITA2_TABLE, ROTOR_SIZES} from "../lib/Lorenz.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Colossus simulator class.
|
||||||
|
*/
|
||||||
|
export class ColossusComputer {
|
||||||
|
/**
|
||||||
|
* Construct a Colossus.
|
||||||
|
*
|
||||||
|
* @param {string} ciphertext
|
||||||
|
* @param {string} pattern - named pattern of Chi, Mu and Psi wheels
|
||||||
|
* @param {Object} qbusin - which data inputs are being sent to q bus - each can be null, plain or delta
|
||||||
|
* @param {Object[]} qbusswitches - Q bus calculation switches, multiple rows
|
||||||
|
* @param {Object} control - control switches which specify stepping modes
|
||||||
|
* @param {Object} starts - rotor start positions
|
||||||
|
*/
|
||||||
|
constructor(ciphertext, pattern, qbusin, qbusswitches, control, starts, settotal, limit) {
|
||||||
|
this.ITAlookup = ITA2_TABLE;
|
||||||
|
this.ReverseITAlookup = {};
|
||||||
|
for (const letter in this.ITAlookup) {
|
||||||
|
const code = this.ITAlookup[letter];
|
||||||
|
this.ReverseITAlookup[code] = letter;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.initThyratrons(pattern);
|
||||||
|
|
||||||
|
this.ciphertext = ciphertext;
|
||||||
|
this.qbusin = qbusin;
|
||||||
|
this.qbusswitches = qbusswitches;
|
||||||
|
this.control = control;
|
||||||
|
this.starts = starts;
|
||||||
|
this.settotal = settotal;
|
||||||
|
this.limitations = limit;
|
||||||
|
|
||||||
|
|
||||||
|
this.allCounters = [0, 0, 0, 0, 0];
|
||||||
|
|
||||||
|
this.Zbits = [0, 0, 0, 0, 0]; // Z input is the cipher tape
|
||||||
|
this.ZbitsOneBack = [0, 0, 0, 0, 0]; // for delta
|
||||||
|
this.Qbits = [0, 0, 0, 0, 0]; // input generated for placing onto the Q-bus (the logic processor)
|
||||||
|
|
||||||
|
this.Xbits = [0, 0, 0, 0, 0]; // X is the Chi wheel bits
|
||||||
|
this.Xptr = [0, 0, 0, 0, 0]; // pointers to the current X bits (Chi wheels)
|
||||||
|
this.XbitsOneBack = [0, 0, 0, 0, 0]; // the X bits one back (for delta)
|
||||||
|
|
||||||
|
this.Sbits = [0, 0, 0, 0, 0]; // S is the Psi wheel bits
|
||||||
|
this.Sptr = [0, 0, 0, 0, 0]; // pointers to the current S bits (Psi wheels)
|
||||||
|
this.SbitsOneBack = [0, 0, 0, 0, 0]; // the S bits one back (for delta)
|
||||||
|
|
||||||
|
this.Mptr = [0, 0];
|
||||||
|
|
||||||
|
this.rotorPtrs = {};
|
||||||
|
|
||||||
|
this.totalmotor = 0;
|
||||||
|
this.P5Zbit = [0, 0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Begin a run
|
||||||
|
*
|
||||||
|
* @returns {object}
|
||||||
|
*/
|
||||||
|
run() {
|
||||||
|
const result = {
|
||||||
|
printout: ""
|
||||||
|
};
|
||||||
|
|
||||||
|
// loop until our start positions are back to the beginning
|
||||||
|
this.rotorPtrs = {X1: this.starts.X1, X2: this.starts.X2, X3: this.starts.X3, X4: this.starts.X4, X5: this.starts.X5, M61: this.starts.M61, M37: this.starts.M37, S1: this.starts.S1, S2: this.starts.S2, S3: this.starts.S3, S4: this.starts.S4, S5: this.starts.S5};
|
||||||
|
// this.rotorPtrs = this.starts;
|
||||||
|
let runcount = 1;
|
||||||
|
|
||||||
|
const fast = this.control.fast;
|
||||||
|
const slow = this.control.slow;
|
||||||
|
|
||||||
|
// Print Headers
|
||||||
|
result.printout += fast + " " + slow + "\n";
|
||||||
|
|
||||||
|
do {
|
||||||
|
this.allCounters = [0, 0, 0, 0, 0];
|
||||||
|
this.ZbitsOneBack = [0, 0, 0, 0, 0];
|
||||||
|
this.XbitsOneBack = [0, 0, 0, 0, 0];
|
||||||
|
|
||||||
|
// Run full tape loop and process counters
|
||||||
|
this.runTape();
|
||||||
|
|
||||||
|
// Only print result if larger than set total
|
||||||
|
let fastRef = "00";
|
||||||
|
let slowRef = "00";
|
||||||
|
if (fast !== "") fastRef = this.rotorPtrs[fast].toString().padStart(2, "0");
|
||||||
|
if (slow !== "") slowRef = this.rotorPtrs[slow].toString().padStart(2, "0");
|
||||||
|
let printline = "";
|
||||||
|
for (let c=0;c<5;c++) {
|
||||||
|
if (this.allCounters[c] > this.settotal) {
|
||||||
|
printline += String.fromCharCode(c+97) + this.allCounters[c]+" ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (printline !== "") {
|
||||||
|
result.printout += fastRef + " " + slowRef + " : ";
|
||||||
|
result.printout += printline;
|
||||||
|
result.printout += "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step fast rotor if required
|
||||||
|
if (fast !== "") {
|
||||||
|
this.rotorPtrs[fast]++;
|
||||||
|
if (this.rotorPtrs[fast] > ROTOR_SIZES[fast]) this.rotorPtrs[fast] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step slow rotor if fast rotor has returned to initial start position
|
||||||
|
if (slow !== "" && this.rotorPtrs[fast] === this.starts[fast]) {
|
||||||
|
this.rotorPtrs[slow]++;
|
||||||
|
if (this.rotorPtrs[slow] > ROTOR_SIZES[slow]) this.rotorPtrs[slow] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
runcount++;
|
||||||
|
} while (JSON.stringify(this.rotorPtrs) !== JSON.stringify(this.starts));
|
||||||
|
|
||||||
|
result.counters = this.allCounters;
|
||||||
|
result.runcount = runcount;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Run tape loop
|
||||||
|
*/
|
||||||
|
runTape() {
|
||||||
|
let charZin = "";
|
||||||
|
|
||||||
|
this.Xptr = [this.rotorPtrs.X1, this.rotorPtrs.X2, this.rotorPtrs.X3, this.rotorPtrs.X4, this.rotorPtrs.X5];
|
||||||
|
this.Mptr = [this.rotorPtrs.M37, this.rotorPtrs.M61];
|
||||||
|
this.Sptr = [this.rotorPtrs.S1, this.rotorPtrs.S2, this.rotorPtrs.S3, this.rotorPtrs.S4, this.rotorPtrs.S5];
|
||||||
|
|
||||||
|
// Run full loop of all character on the input tape (Z)
|
||||||
|
for (let i=0; i<this.ciphertext.length; i++) {
|
||||||
|
charZin = this.ciphertext.charAt(i);
|
||||||
|
|
||||||
|
// Firstly, we check what inputs are specified on the Q-bus input switches
|
||||||
|
this.getQbusInputs(charZin);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Pattern conditions on individual impulses. Matching patterns of bits on the Q bus.
|
||||||
|
* This is the top section on Colussus K rack - the Q bus programming switches
|
||||||
|
*/
|
||||||
|
const tmpcnt = this.runQbusProcessingConditional();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Addition of impulses.
|
||||||
|
* This is the bottom section of Colossus K rack.
|
||||||
|
*/
|
||||||
|
this.runQbusProcessingAddition(tmpcnt);
|
||||||
|
|
||||||
|
// Store Z bit impulse 5 two back required for P5 limitation
|
||||||
|
this.P5Zbit[1] = this.P5Zbit[0];
|
||||||
|
this.P5Zbit[0] = this.ITAlookup[charZin].split("")[4];
|
||||||
|
|
||||||
|
// Step rotors
|
||||||
|
this.stepThyratrons();
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Step thyratron rings to simulate movement of Lorenz rotors
|
||||||
|
* Chi rotors all step one per character
|
||||||
|
* Motor M61 rotor steps one per character, M37 steps dependant on M61 setting
|
||||||
|
* Psi rotors only step dependant on M37 setting + limitation
|
||||||
|
*/
|
||||||
|
stepThyratrons() {
|
||||||
|
let X2bPtr = this.Xptr[1]-1;
|
||||||
|
if (X2bPtr===0) X2bPtr = ROTOR_SIZES.X2;
|
||||||
|
let S1bPtr = this.Sptr[0]-1;
|
||||||
|
if (S1bPtr===0) S1bPtr = ROTOR_SIZES.S1;
|
||||||
|
|
||||||
|
// Get Chi rotor 5 two back to calculate plaintext (Z+Chi+Psi=Plain)
|
||||||
|
let X5bPtr=this.Xptr[4]-1;
|
||||||
|
if (X5bPtr===0) X5bPtr=ROTOR_SIZES.X5;
|
||||||
|
X5bPtr=X5bPtr-1;
|
||||||
|
if (X5bPtr===0) X5bPtr=ROTOR_SIZES.X5;
|
||||||
|
// Get Psi rotor 5 two back to calculate plaintext (Z+Chi+Psi=Plain)
|
||||||
|
let S5bPtr=this.Sptr[4]-1;
|
||||||
|
if (S5bPtr===0) S5bPtr=ROTOR_SIZES.S5;
|
||||||
|
S5bPtr=S5bPtr-1;
|
||||||
|
if (S5bPtr===0) S5bPtr=ROTOR_SIZES.S5;
|
||||||
|
|
||||||
|
const x2sw = this.limitations.X2;
|
||||||
|
const s1sw = this.limitations.S1;
|
||||||
|
const p5sw = this.limitations.P5;
|
||||||
|
|
||||||
|
// Limitation calculations
|
||||||
|
let lim=1;
|
||||||
|
if (x2sw) lim = this.rings.X[2][X2bPtr-1];
|
||||||
|
if (s1sw) lim = lim ^ this.rings.S[1][S1bPtr-1];
|
||||||
|
|
||||||
|
// P5
|
||||||
|
if (p5sw) {
|
||||||
|
let p5lim = this.P5Zbit[1];
|
||||||
|
p5lim = p5lim ^ this.rings.X[5][X5bPtr-1];
|
||||||
|
p5lim = p5lim ^ this.rings.S[5][S5bPtr-1];
|
||||||
|
lim = lim ^ p5lim;
|
||||||
|
}
|
||||||
|
|
||||||
|
const basicmotor = this.rings.M[2][this.Mptr[0]-1];
|
||||||
|
this.totalmotor = basicmotor;
|
||||||
|
|
||||||
|
if (x2sw || s1sw) {
|
||||||
|
if (basicmotor===0 && lim===1) {
|
||||||
|
this.totalmotor = 0;
|
||||||
|
} else {
|
||||||
|
this.totalmotor = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Step Chi rotors
|
||||||
|
for (let r=0; r<5; r++) {
|
||||||
|
this.Xptr[r]++;
|
||||||
|
if (this.Xptr[r] > ROTOR_SIZES["X"+(r+1)]) this.Xptr[r] = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.totalmotor) {
|
||||||
|
// Step Psi rotors
|
||||||
|
for (let r=0; r<5; r++) {
|
||||||
|
this.Sptr[r]++;
|
||||||
|
if (this.Sptr[r] > ROTOR_SIZES["S"+(r+1)]) this.Sptr[r] = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move M37 rotor if M61 set
|
||||||
|
if (this.rings.M[1][this.Mptr[1]-1]===1) this.Mptr[0]++;
|
||||||
|
if (this.Mptr[0] > ROTOR_SIZES.M37) this.Mptr[0]=1;
|
||||||
|
|
||||||
|
// Always move M61 rotor
|
||||||
|
this.Mptr[1]++;
|
||||||
|
if (this.Mptr[1] > ROTOR_SIZES.M61) this.Mptr[1]=1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Q bus inputs
|
||||||
|
*/
|
||||||
|
getQbusInputs(charZin) {
|
||||||
|
// Zbits - the bits from the current character from the cipher tape.
|
||||||
|
this.Zbits = this.ITAlookup[charZin].split("");
|
||||||
|
if (this.qbusin.Z === "Z") {
|
||||||
|
// direct Z
|
||||||
|
this.Qbits = this.Zbits;
|
||||||
|
} else if (this.qbusin.Z === "ΔZ") {
|
||||||
|
// delta Z, the Bitwise XOR of this character Zbits + last character Zbits
|
||||||
|
for (let b=0;b<5;b++) {
|
||||||
|
this.Qbits[b] = this.Zbits[b] ^ this.ZbitsOneBack[b];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.ZbitsOneBack = this.Zbits.slice(); // copy value of object, not reference
|
||||||
|
|
||||||
|
// Xbits - the current Chi wheel bits
|
||||||
|
for (let b=0;b<5;b++) {
|
||||||
|
this.Xbits[b] = this.rings.X[b+1][this.Xptr[b]-1];
|
||||||
|
}
|
||||||
|
if (this.qbusin.Chi !== "") {
|
||||||
|
if (this.qbusin.Chi === "Χ") {
|
||||||
|
// direct X added to Qbits
|
||||||
|
for (let b=0;b<5;b++) {
|
||||||
|
this.Qbits[b] = this.Qbits[b] ^ this.Xbits[b];
|
||||||
|
}
|
||||||
|
} else if (this.qbusin.Chi === "ΔΧ") {
|
||||||
|
// delta X
|
||||||
|
for (let b=0;b<5;b++) {
|
||||||
|
this.Qbits[b] = this.Qbits[b] ^ this.Xbits[b];
|
||||||
|
this.Qbits[b] = this.Qbits[b] ^ this.XbitsOneBack[b];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.XbitsOneBack = this.Xbits.slice();
|
||||||
|
|
||||||
|
// Sbits - the current Psi wheel bits
|
||||||
|
for (let b=0;b<5;b++) {
|
||||||
|
this.Sbits[b] = this.rings.S[b+1][this.Sptr[b]-1];
|
||||||
|
}
|
||||||
|
if (this.qbusin.Psi !== "") {
|
||||||
|
if (this.qbusin.Psi === "Ψ") {
|
||||||
|
// direct S added to Qbits
|
||||||
|
for (let b=0;b<5;b++) {
|
||||||
|
this.Qbits[b] = this.Qbits[b] ^ this.Sbits[b];
|
||||||
|
}
|
||||||
|
} else if (this.qbusin.Psi === "ΔΨ") {
|
||||||
|
// delta S
|
||||||
|
for (let b=0;b<5;b++) {
|
||||||
|
this.Qbits[b] = this.Qbits[b] ^ this.Sbits[b];
|
||||||
|
this.Qbits[b] = this.Qbits[b] ^ this.SbitsOneBack[b];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.SbitsOneBack = this.Sbits.slice();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Conditional impulse Q bus section
|
||||||
|
*/
|
||||||
|
runQbusProcessingConditional() {
|
||||||
|
const cnt = [-1, -1, -1, -1, -1];
|
||||||
|
const numrows = this.qbusswitches.condition.length;
|
||||||
|
|
||||||
|
for (let r=0;r<numrows;r++) {
|
||||||
|
const row = this.qbusswitches.condition[r];
|
||||||
|
if (row.Counter !== "") {
|
||||||
|
let result = true;
|
||||||
|
const cPnt = row.Counter-1;
|
||||||
|
const Qswitch = this.readBusSwitches(row.Qswitches);
|
||||||
|
// Match switches to bit pattern
|
||||||
|
for (let s=0;s<5;s++) {
|
||||||
|
if (Qswitch[s] >= 0 && Qswitch[s] !== parseInt(this.Qbits[s], 10)) result = false;
|
||||||
|
}
|
||||||
|
// Check for NOT switch
|
||||||
|
if (row.Negate) result = !result;
|
||||||
|
|
||||||
|
// AND each row to get final result
|
||||||
|
if (cnt[cPnt] === -1) {
|
||||||
|
cnt[cPnt] = result;
|
||||||
|
} else if (!result) {
|
||||||
|
cnt[cPnt] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Negate the whole column, this allows A OR B by doing NOT(NOT A AND NOT B)
|
||||||
|
for (let c=0;c<5;c++) {
|
||||||
|
if (this.qbusswitches.condNegateAll && cnt[c] !== -1) cnt[c] = !cnt[c];
|
||||||
|
}
|
||||||
|
|
||||||
|
return cnt;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Addition of impulses Q bus section
|
||||||
|
*/
|
||||||
|
runQbusProcessingAddition(cnt) {
|
||||||
|
const row = this.qbusswitches.addition[0];
|
||||||
|
const Qswitch = row.Qswitches.slice();
|
||||||
|
|
||||||
|
// To save making the arguments of this operation any larger, limiting addition counter to first one only
|
||||||
|
// Colossus could actually add into any of the five counters.
|
||||||
|
if (row.C1) {
|
||||||
|
let addition = 0;
|
||||||
|
for (let s=0;s<5;s++) {
|
||||||
|
// XOR addition
|
||||||
|
if (Qswitch[s]) {
|
||||||
|
addition = addition ^ this.Qbits[s];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const equals = (row.Equals===""?-1:(row.Equals==="."?0:1));
|
||||||
|
if (addition === equals) {
|
||||||
|
// AND with conditional rows to get final result
|
||||||
|
if (cnt[0] === -1) cnt[0] = true;
|
||||||
|
} else {
|
||||||
|
cnt[0] = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Final check, check for addition section negate
|
||||||
|
// then, if any column set, from top to bottom of rack, add to counter.
|
||||||
|
for (let c=0;c<5;c++) {
|
||||||
|
if (this.qbusswitches.addNegateAll && cnt[c] !== -1) cnt[c] = !cnt[c];
|
||||||
|
|
||||||
|
if (this.qbusswitches.totalMotor === "" || (this.qbusswitches.totalMotor === "x" && this.totalmotor === 0) || (this.qbusswitches.totalMotor === "." && this.totalmotor === 1)) {
|
||||||
|
if (cnt[c] === true) this.allCounters[c]++;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialise thyratron rings
|
||||||
|
* These hold the pattern of 1s & 0s for each rotor on banks of thyraton GT1C valves which act as a one-bit store.
|
||||||
|
*/
|
||||||
|
initThyratrons(pattern) {
|
||||||
|
this.rings = {
|
||||||
|
X: {
|
||||||
|
1: INIT_PATTERNS[pattern].X[1].slice().reverse(),
|
||||||
|
2: INIT_PATTERNS[pattern].X[2].slice().reverse(),
|
||||||
|
3: INIT_PATTERNS[pattern].X[3].slice().reverse(),
|
||||||
|
4: INIT_PATTERNS[pattern].X[4].slice().reverse(),
|
||||||
|
5: INIT_PATTERNS[pattern].X[5].slice().reverse()
|
||||||
|
},
|
||||||
|
M: {
|
||||||
|
1: INIT_PATTERNS[pattern].M[1].slice().reverse(),
|
||||||
|
2: INIT_PATTERNS[pattern].M[2].slice().reverse(),
|
||||||
|
},
|
||||||
|
S: {
|
||||||
|
1: INIT_PATTERNS[pattern].S[1].slice().reverse(),
|
||||||
|
2: INIT_PATTERNS[pattern].S[2].slice().reverse(),
|
||||||
|
3: INIT_PATTERNS[pattern].S[3].slice().reverse(),
|
||||||
|
4: INIT_PATTERNS[pattern].S[4].slice().reverse(),
|
||||||
|
5: INIT_PATTERNS[pattern].S[5].slice().reverse()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read argument bus switches X & . and convert to 1 & 0
|
||||||
|
*/
|
||||||
|
readBusSwitches(row) {
|
||||||
|
const output = [-1, -1, -1, -1, -1];
|
||||||
|
for (let c=0;c<5;c++) {
|
||||||
|
if (row[c]===".") output[c] = 0;
|
||||||
|
if (row[c]==="x") output[c] = 1;
|
||||||
|
}
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
9
src/core/lib/Crypt.mjs
Normal file
9
src/core/lib/Crypt.mjs
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
/**
|
||||||
|
* Crypt resources.
|
||||||
|
*
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2021
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const cryptNotice = "WARNING: Cryptographic operations in CyberChef should not be relied upon to provide security in any situation. No guarantee is offered for their correctness. We advise you not to use keys generated from CyberChef in operational contexts.";
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -213,7 +213,7 @@ function locatePotentialSig(buf, sig, offset) {
|
|||||||
export function isType(type, buf) {
|
export function isType(type, buf) {
|
||||||
const types = detectFileType(buf);
|
const types = detectFileType(buf);
|
||||||
|
|
||||||
if (!(types && types.length)) return false;
|
if (!types.length) return false;
|
||||||
|
|
||||||
if (typeof type === "string") {
|
if (typeof type === "string") {
|
||||||
return types.reduce((acc, t) => {
|
return types.reduce((acc, t) => {
|
||||||
|
|||||||
219
src/core/lib/FuzzySearch.mjs
Normal file
219
src/core/lib/FuzzySearch.mjs
Normal file
@@ -0,0 +1,219 @@
|
|||||||
|
/**
|
||||||
|
* LICENSE
|
||||||
|
*
|
||||||
|
* This software is dual-licensed to the public domain and under the following
|
||||||
|
* license: you are granted a perpetual, irrevocable license to copy, modify,
|
||||||
|
* publish, and distribute this file as you see fit.
|
||||||
|
*
|
||||||
|
* VERSION
|
||||||
|
* 0.1.0 (2016-03-28) Initial release
|
||||||
|
*
|
||||||
|
* AUTHOR
|
||||||
|
* Forrest Smith
|
||||||
|
*
|
||||||
|
* CONTRIBUTORS
|
||||||
|
* J<>rgen Tjern<72> - async helper
|
||||||
|
* Anurag Awasthi - updated to 0.2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
const SEQUENTIAL_BONUS = 15; // bonus for adjacent matches
|
||||||
|
const SEPARATOR_BONUS = 30; // bonus if match occurs after a separator
|
||||||
|
const CAMEL_BONUS = 30; // bonus if match is uppercase and prev is lower
|
||||||
|
const FIRST_LETTER_BONUS = 15; // bonus if the first letter is matched
|
||||||
|
|
||||||
|
const LEADING_LETTER_PENALTY = -5; // penalty applied for every letter in str before the first match
|
||||||
|
const MAX_LEADING_LETTER_PENALTY = -15; // maximum penalty for leading letters
|
||||||
|
const UNMATCHED_LETTER_PENALTY = -1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Does a fuzzy search to find pattern inside a string.
|
||||||
|
* @param {*} pattern string pattern to search for
|
||||||
|
* @param {*} str string string which is being searched
|
||||||
|
* @returns [boolean, number] a boolean which tells if pattern was
|
||||||
|
* found or not and a search score
|
||||||
|
*/
|
||||||
|
export function fuzzyMatch(pattern, str) {
|
||||||
|
const recursionCount = 0;
|
||||||
|
const recursionLimit = 10;
|
||||||
|
const matches = [];
|
||||||
|
const maxMatches = 256;
|
||||||
|
|
||||||
|
return fuzzyMatchRecursive(
|
||||||
|
pattern,
|
||||||
|
str,
|
||||||
|
0 /* patternCurIndex */,
|
||||||
|
0 /* strCurrIndex */,
|
||||||
|
null /* srcMatces */,
|
||||||
|
matches,
|
||||||
|
maxMatches,
|
||||||
|
0 /* nextMatch */,
|
||||||
|
recursionCount,
|
||||||
|
recursionLimit
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Recursive helper function
|
||||||
|
*/
|
||||||
|
function fuzzyMatchRecursive(
|
||||||
|
pattern,
|
||||||
|
str,
|
||||||
|
patternCurIndex,
|
||||||
|
strCurrIndex,
|
||||||
|
srcMatches,
|
||||||
|
matches,
|
||||||
|
maxMatches,
|
||||||
|
nextMatch,
|
||||||
|
recursionCount,
|
||||||
|
recursionLimit
|
||||||
|
) {
|
||||||
|
let outScore = 0;
|
||||||
|
|
||||||
|
// Return if recursion limit is reached.
|
||||||
|
if (++recursionCount >= recursionLimit) {
|
||||||
|
return [false, outScore, []];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return if we reached ends of strings.
|
||||||
|
if (patternCurIndex === pattern.length || strCurrIndex === str.length) {
|
||||||
|
return [false, outScore, []];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursion params
|
||||||
|
let recursiveMatch = false;
|
||||||
|
let bestRecursiveMatches = [];
|
||||||
|
let bestRecursiveScore = 0;
|
||||||
|
|
||||||
|
// Loop through pattern and str looking for a match.
|
||||||
|
let firstMatch = true;
|
||||||
|
while (patternCurIndex < pattern.length && strCurrIndex < str.length) {
|
||||||
|
// Match found.
|
||||||
|
if (
|
||||||
|
pattern[patternCurIndex].toLowerCase() === str[strCurrIndex].toLowerCase()
|
||||||
|
) {
|
||||||
|
if (nextMatch >= maxMatches) {
|
||||||
|
return [false, outScore, []];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (firstMatch && srcMatches) {
|
||||||
|
matches = [...srcMatches];
|
||||||
|
firstMatch = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
const [matched, recursiveScore, recursiveMatches] = fuzzyMatchRecursive(
|
||||||
|
pattern,
|
||||||
|
str,
|
||||||
|
patternCurIndex,
|
||||||
|
strCurrIndex + 1,
|
||||||
|
matches,
|
||||||
|
recursiveMatches,
|
||||||
|
maxMatches,
|
||||||
|
nextMatch,
|
||||||
|
recursionCount,
|
||||||
|
recursionLimit
|
||||||
|
);
|
||||||
|
|
||||||
|
if (matched) {
|
||||||
|
// Pick best recursive score.
|
||||||
|
if (!recursiveMatch || recursiveScore > bestRecursiveScore) {
|
||||||
|
bestRecursiveMatches = [...recursiveMatches];
|
||||||
|
bestRecursiveScore = recursiveScore;
|
||||||
|
}
|
||||||
|
recursiveMatch = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
matches[nextMatch++] = strCurrIndex;
|
||||||
|
++patternCurIndex;
|
||||||
|
}
|
||||||
|
++strCurrIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
const matched = patternCurIndex === pattern.length;
|
||||||
|
|
||||||
|
if (matched) {
|
||||||
|
outScore = 100;
|
||||||
|
|
||||||
|
// Apply leading letter penalty
|
||||||
|
let penalty = LEADING_LETTER_PENALTY * matches[0];
|
||||||
|
penalty =
|
||||||
|
penalty < MAX_LEADING_LETTER_PENALTY ?
|
||||||
|
MAX_LEADING_LETTER_PENALTY :
|
||||||
|
penalty;
|
||||||
|
outScore += penalty;
|
||||||
|
|
||||||
|
// Apply unmatched penalty
|
||||||
|
const unmatched = str.length - nextMatch;
|
||||||
|
outScore += UNMATCHED_LETTER_PENALTY * unmatched;
|
||||||
|
|
||||||
|
// Apply ordering bonuses
|
||||||
|
for (let i = 0; i < nextMatch; i++) {
|
||||||
|
const currIdx = matches[i];
|
||||||
|
|
||||||
|
if (i > 0) {
|
||||||
|
const prevIdx = matches[i - 1];
|
||||||
|
if (currIdx === prevIdx + 1) {
|
||||||
|
outScore += SEQUENTIAL_BONUS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for bonuses based on neighbor character value.
|
||||||
|
if (currIdx > 0) {
|
||||||
|
// Camel case
|
||||||
|
const neighbor = str[currIdx - 1];
|
||||||
|
const curr = str[currIdx];
|
||||||
|
if (
|
||||||
|
neighbor !== neighbor.toUpperCase() &&
|
||||||
|
curr !== curr.toLowerCase()
|
||||||
|
) {
|
||||||
|
outScore += CAMEL_BONUS;
|
||||||
|
}
|
||||||
|
const isNeighbourSeparator = neighbor === "_" || neighbor === " ";
|
||||||
|
if (isNeighbourSeparator) {
|
||||||
|
outScore += SEPARATOR_BONUS;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// First letter
|
||||||
|
outScore += FIRST_LETTER_BONUS;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return best result
|
||||||
|
if (recursiveMatch && (!matched || bestRecursiveScore > outScore)) {
|
||||||
|
// Recursive score is better than "this"
|
||||||
|
matches = bestRecursiveMatches;
|
||||||
|
outScore = bestRecursiveScore;
|
||||||
|
return [true, outScore, matches];
|
||||||
|
} else if (matched) {
|
||||||
|
// "this" score is better than recursive
|
||||||
|
return [true, outScore, matches];
|
||||||
|
} else {
|
||||||
|
return [false, outScore, matches];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [false, outScore, matches];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Turns a list of match indexes into a list of match ranges
|
||||||
|
*
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @param [number] matches
|
||||||
|
* @returns [[number]]
|
||||||
|
*/
|
||||||
|
export function calcMatchRanges(matches) {
|
||||||
|
const ranges = [];
|
||||||
|
let start = matches[0],
|
||||||
|
curr = start;
|
||||||
|
|
||||||
|
matches.forEach(m => {
|
||||||
|
if (m === curr || m === curr + 1) curr = m;
|
||||||
|
else {
|
||||||
|
ranges.push([start, curr - start + 1]);
|
||||||
|
start = m;
|
||||||
|
curr = m;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ranges.push([start, curr - start + 1]);
|
||||||
|
return ranges;
|
||||||
|
}
|
||||||
@@ -23,25 +23,39 @@ import Utils from "../Utils.mjs";
|
|||||||
*
|
*
|
||||||
* // returns "0a:14:1e"
|
* // returns "0a:14:1e"
|
||||||
* toHex([10,20,30], ":");
|
* toHex([10,20,30], ":");
|
||||||
|
*
|
||||||
|
* // returns "0x0a,0x14,0x1e"
|
||||||
|
* toHex([10,20,30], "0x", 2, ",")
|
||||||
*/
|
*/
|
||||||
export function toHex(data, delim=" ", padding=2) {
|
export function toHex(data, delim=" ", padding=2, extraDelim="", lineSize=0) {
|
||||||
if (!data) return "";
|
if (!data) return "";
|
||||||
if (data instanceof ArrayBuffer) data = new Uint8Array(data);
|
if (data instanceof ArrayBuffer) data = new Uint8Array(data);
|
||||||
|
|
||||||
let output = "";
|
let output = "";
|
||||||
|
const prepend = (delim === "0x" || delim === "\\x");
|
||||||
|
|
||||||
for (let i = 0; i < data.length; i++) {
|
for (let i = 0; i < data.length; i++) {
|
||||||
output += data[i].toString(16).padStart(padding, "0") + delim;
|
const hex = data[i].toString(16).padStart(padding, "0");
|
||||||
|
output += prepend ? delim + hex : hex + delim;
|
||||||
|
|
||||||
|
if (extraDelim) {
|
||||||
|
output += extraDelim;
|
||||||
|
}
|
||||||
|
// Add LF after each lineSize amount of bytes but not at the end
|
||||||
|
if ((i !== data.length - 1) && ((i + 1) % lineSize === 0)) {
|
||||||
|
output += "\n";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add \x or 0x to beginning
|
// Remove the extraDelim at the end (if there is one)
|
||||||
if (delim === "0x") output = "0x" + output;
|
// and remove the delim at the end, but if it's prepended there's nothing to remove
|
||||||
if (delim === "\\x") output = "\\x" + output;
|
const rTruncLen = extraDelim.length + (prepend ? 0 : delim.length);
|
||||||
|
if (rTruncLen) {
|
||||||
if (delim.length)
|
// If rTruncLen === 0 then output.slice(0,0) will be returned, which is nothing
|
||||||
return output.slice(0, -delim.length);
|
return output.slice(0, -rTruncLen);
|
||||||
else
|
} else {
|
||||||
return output;
|
return output;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -87,7 +101,7 @@ export function toHexFast(data) {
|
|||||||
*/
|
*/
|
||||||
export function fromHex(data, delim="Auto", byteLen=2) {
|
export function fromHex(data, delim="Auto", byteLen=2) {
|
||||||
if (delim !== "None") {
|
if (delim !== "None") {
|
||||||
const delimRegex = delim === "Auto" ? /[^a-f\d]/gi : Utils.regexRep(delim);
|
const delimRegex = delim === "Auto" ? /[^a-f\d]|(0x)/gi : Utils.regexRep(delim);
|
||||||
data = data.replace(delimRegex, "");
|
data = data.replace(delimRegex, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +116,7 @@ export function fromHex(data, delim="Auto", byteLen=2) {
|
|||||||
/**
|
/**
|
||||||
* To Hexadecimal delimiters.
|
* To Hexadecimal delimiters.
|
||||||
*/
|
*/
|
||||||
export const TO_HEX_DELIM_OPTIONS = ["Space", "Percent", "Comma", "Semi-colon", "Colon", "Line feed", "CRLF", "0x", "\\x", "None"];
|
export const TO_HEX_DELIM_OPTIONS = ["Space", "Percent", "Comma", "Semi-colon", "Colon", "Line feed", "CRLF", "0x", "0x with comma", "\\x", "None"];
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export function ipv4CidrRange(cidr, includeNetworkInfo, enumerateAddresses, allo
|
|||||||
let output = "";
|
let output = "";
|
||||||
|
|
||||||
if (cidrRange < 0 || cidrRange > 31) {
|
if (cidrRange < 0 || cidrRange > 31) {
|
||||||
return "IPv4 CIDR must be less than 32";
|
throw new OperationError("IPv4 CIDR must be less than 32");
|
||||||
}
|
}
|
||||||
|
|
||||||
const mask = ~(0xFFFFFFFF >>> cidrRange),
|
const mask = ~(0xFFFFFFFF >>> cidrRange),
|
||||||
@@ -64,7 +64,7 @@ export function ipv6CidrRange(cidr, includeNetworkInfo) {
|
|||||||
cidrRange = parseInt(cidr[cidr.length-1], 10);
|
cidrRange = parseInt(cidr[cidr.length-1], 10);
|
||||||
|
|
||||||
if (cidrRange < 0 || cidrRange > 127) {
|
if (cidrRange < 0 || cidrRange > 127) {
|
||||||
return "IPv6 CIDR must be less than 128";
|
throw new OperationError("IPv6 CIDR must be less than 128");
|
||||||
}
|
}
|
||||||
|
|
||||||
const ip1 = new Array(8),
|
const ip1 = new Array(8),
|
||||||
@@ -211,7 +211,7 @@ export function ipv4ListedRange(match, includeNetworkInfo, enumerateAddresses, a
|
|||||||
const network = strToIpv4(ipv4CidrList[i].split("/")[0]);
|
const network = strToIpv4(ipv4CidrList[i].split("/")[0]);
|
||||||
const cidrRange = parseInt(ipv4CidrList[i].split("/")[1], 10);
|
const cidrRange = parseInt(ipv4CidrList[i].split("/")[1], 10);
|
||||||
if (cidrRange < 0 || cidrRange > 31) {
|
if (cidrRange < 0 || cidrRange > 31) {
|
||||||
return "IPv4 CIDR must be less than 32";
|
throw new OperationError("IPv4 CIDR must be less than 32");
|
||||||
}
|
}
|
||||||
const mask = ~(0xFFFFFFFF >>> cidrRange),
|
const mask = ~(0xFFFFFFFF >>> cidrRange),
|
||||||
cidrIp1 = network & mask,
|
cidrIp1 = network & mask,
|
||||||
@@ -254,7 +254,7 @@ export function ipv6ListedRange(match, includeNetworkInfo) {
|
|||||||
const cidrRange = parseInt(ipv6CidrList[i].split("/")[1], 10);
|
const cidrRange = parseInt(ipv6CidrList[i].split("/")[1], 10);
|
||||||
|
|
||||||
if (cidrRange < 0 || cidrRange > 127) {
|
if (cidrRange < 0 || cidrRange > 127) {
|
||||||
return "IPv6 CIDR must be less than 128";
|
throw new OperationError("IPv6 CIDR must be less than 128");
|
||||||
}
|
}
|
||||||
|
|
||||||
const cidrIp1 = new Array(8),
|
const cidrIp1 = new Array(8),
|
||||||
|
|||||||
24
src/core/lib/JWT.mjs
Normal file
24
src/core/lib/JWT.mjs
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
/**
|
||||||
|
* JWT resources
|
||||||
|
*
|
||||||
|
* @author mt3571 [mt3571@protonmail.com]
|
||||||
|
* @copyright Crown Copyright 2020
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* List of the JWT algorithms that can be used
|
||||||
|
*/
|
||||||
|
export const JWT_ALGORITHMS = [
|
||||||
|
"HS256",
|
||||||
|
"HS384",
|
||||||
|
"HS512",
|
||||||
|
"RS256",
|
||||||
|
"RS384",
|
||||||
|
"RS512",
|
||||||
|
"ES256",
|
||||||
|
"ES384",
|
||||||
|
"ES512",
|
||||||
|
"None"
|
||||||
|
];
|
||||||
156
src/core/lib/Lorenz.mjs
Normal file
156
src/core/lib/Lorenz.mjs
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
/**
|
||||||
|
* Resources required by the Lorenz SZ40/42 and Colossus
|
||||||
|
*
|
||||||
|
* @author VirtualColossus [martin@virtualcolossus.co.uk]
|
||||||
|
* @copyright Crown Copyright 2019
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const SWITCHES = [
|
||||||
|
{name: "Up (.)", value: "."},
|
||||||
|
{name: "Centre", value: ""},
|
||||||
|
{name: "Down (x)", value: "x"}
|
||||||
|
];
|
||||||
|
|
||||||
|
export const VALID_ITA2 = "ABCDEFGHIJKLMNOPQRSTUVWXYZ34589+-./";
|
||||||
|
|
||||||
|
export const ITA2_TABLE = {
|
||||||
|
"A": "11000",
|
||||||
|
"B": "10011",
|
||||||
|
"C": "01110",
|
||||||
|
"D": "10010",
|
||||||
|
"E": "10000",
|
||||||
|
"F": "10110",
|
||||||
|
"G": "01011",
|
||||||
|
"H": "00101",
|
||||||
|
"I": "01100",
|
||||||
|
"J": "11010",
|
||||||
|
"K": "11110",
|
||||||
|
"L": "01001",
|
||||||
|
"M": "00111",
|
||||||
|
"N": "00110",
|
||||||
|
"O": "00011",
|
||||||
|
"P": "01101",
|
||||||
|
"Q": "11101",
|
||||||
|
"R": "01010",
|
||||||
|
"S": "10100",
|
||||||
|
"T": "00001",
|
||||||
|
"U": "11100",
|
||||||
|
"V": "01111",
|
||||||
|
"W": "11001",
|
||||||
|
"X": "10111",
|
||||||
|
"Y": "10101",
|
||||||
|
"Z": "10001",
|
||||||
|
"3": "00010",
|
||||||
|
"4": "01000",
|
||||||
|
"9": "00100",
|
||||||
|
"/": "00000",
|
||||||
|
" ": "00100",
|
||||||
|
".": "00100",
|
||||||
|
"8": "11111",
|
||||||
|
"5": "11011",
|
||||||
|
"-": "11111",
|
||||||
|
"+": "11011"
|
||||||
|
};
|
||||||
|
|
||||||
|
export const ROTOR_SIZES = {
|
||||||
|
S1: 43,
|
||||||
|
S2: 47,
|
||||||
|
S3: 51,
|
||||||
|
S4: 53,
|
||||||
|
S5: 59,
|
||||||
|
M37: 37,
|
||||||
|
M61: 61,
|
||||||
|
X1: 41,
|
||||||
|
X2: 31,
|
||||||
|
X3: 29,
|
||||||
|
X4: 26,
|
||||||
|
X5: 23
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initial rotor patterns
|
||||||
|
*/
|
||||||
|
export const INIT_PATTERNS = {
|
||||||
|
"No Pattern": {
|
||||||
|
"X": {
|
||||||
|
1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
2: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
3: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
4: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
5: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
"S": {
|
||||||
|
1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
2: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
3: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
4: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
5: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||||
|
},
|
||||||
|
"M": {
|
||||||
|
1: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||||
|
2: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
|
"KH Pattern": {
|
||||||
|
"X": {
|
||||||
|
1: [0, 1, 0, 0, 0, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0],
|
||||||
|
2: [1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0],
|
||||||
|
3: [0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0],
|
||||||
|
4: [1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0],
|
||||||
|
5: [1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 0]
|
||||||
|
},
|
||||||
|
"S": {
|
||||||
|
1: [0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1],
|
||||||
|
2: [0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1],
|
||||||
|
3: [0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1],
|
||||||
|
4: [0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0],
|
||||||
|
5: [1, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 0, 1, 0]
|
||||||
|
},
|
||||||
|
"M": {
|
||||||
|
1: [0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0],
|
||||||
|
2: [1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 1, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ZMUG Pattern": {
|
||||||
|
"X": {
|
||||||
|
1: [0, 1, 1, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0],
|
||||||
|
2: [1, 1, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0],
|
||||||
|
3: [0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0],
|
||||||
|
4: [1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1],
|
||||||
|
5: [0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1]
|
||||||
|
},
|
||||||
|
"S": {
|
||||||
|
1: [1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0],
|
||||||
|
2: [0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 1, 1],
|
||||||
|
3: [0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1],
|
||||||
|
4: [0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 1],
|
||||||
|
5: [1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, 1, 0]
|
||||||
|
},
|
||||||
|
"M": {
|
||||||
|
1: [1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1],
|
||||||
|
2: [0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 0, 1, 1, 1, 0, 1, 1, 1]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"BREAM Pattern": {
|
||||||
|
"X": {
|
||||||
|
1: [0, 1, 1, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0],
|
||||||
|
2: [0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 1, 1],
|
||||||
|
3: [1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0],
|
||||||
|
4: [1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0],
|
||||||
|
5: [0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1, 0, 0, 0, 1, 0]
|
||||||
|
},
|
||||||
|
"S": {
|
||||||
|
1: [0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 0, 1, 1, 0, 1, 1, 0, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0],
|
||||||
|
2: [1, 1, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 0, 1, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 1, 0, 0],
|
||||||
|
3: [1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1],
|
||||||
|
4: [0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 0, 0, 1, 0, 1],
|
||||||
|
5: [1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0]
|
||||||
|
},
|
||||||
|
"M": {
|
||||||
|
1: [1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 1, 0, 1, 1, 1],
|
||||||
|
2: [0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 1, 1, 0, 1]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
@@ -2,7 +2,7 @@ import OperationConfig from "../config/OperationConfig.json";
|
|||||||
import Utils, { isWorkerEnvironment } from "../Utils.mjs";
|
import Utils, { isWorkerEnvironment } from "../Utils.mjs";
|
||||||
import Recipe from "../Recipe.mjs";
|
import Recipe from "../Recipe.mjs";
|
||||||
import Dish from "../Dish.mjs";
|
import Dish from "../Dish.mjs";
|
||||||
import {detectFileType} from "./FileType.mjs";
|
import {detectFileType, isType} from "./FileType.mjs";
|
||||||
import chiSquared from "chi-squared";
|
import chiSquared from "chi-squared";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -19,31 +19,38 @@ class Magic {
|
|||||||
* Magic constructor.
|
* Magic constructor.
|
||||||
*
|
*
|
||||||
* @param {ArrayBuffer} buf
|
* @param {ArrayBuffer} buf
|
||||||
* @param {Object[]} [opPatterns]
|
* @param {Object[]} [opCriteria]
|
||||||
|
* @param {Object} [prevOp]
|
||||||
*/
|
*/
|
||||||
constructor(buf, opPatterns) {
|
constructor(buf, opCriteria=Magic._generateOpCriteria(), prevOp=null) {
|
||||||
this.inputBuffer = new Uint8Array(buf);
|
this.inputBuffer = new Uint8Array(buf);
|
||||||
this.inputStr = Utils.arrayBufferToStr(buf);
|
this.inputStr = Utils.arrayBufferToStr(buf);
|
||||||
this.opPatterns = opPatterns || Magic._generateOpPatterns();
|
this.opCriteria = opCriteria;
|
||||||
|
this.prevOp = prevOp;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds operations that claim to be able to decode the input based on regular
|
* Finds operations that claim to be able to decode the input based on various criteria.
|
||||||
* expression matches.
|
|
||||||
*
|
*
|
||||||
* @returns {Object[]}
|
* @returns {Object[]}
|
||||||
*/
|
*/
|
||||||
findMatchingOps() {
|
findMatchingInputOps() {
|
||||||
const matches = [];
|
const matches = [],
|
||||||
|
inputEntropy = this.calcEntropy();
|
||||||
|
|
||||||
for (let i = 0; i < this.opPatterns.length; i++) {
|
this.opCriteria.forEach(check => {
|
||||||
const pattern = this.opPatterns[i],
|
// If the input doesn't lie in the required entropy range, move on
|
||||||
regex = new RegExp(pattern.match, pattern.flags);
|
if (check.entropyRange &&
|
||||||
|
(inputEntropy < check.entropyRange[0] ||
|
||||||
|
inputEntropy > check.entropyRange[1]))
|
||||||
|
return;
|
||||||
|
// If the input doesn't match the pattern, move on
|
||||||
|
if (check.pattern &&
|
||||||
|
!check.pattern.test(this.inputStr))
|
||||||
|
return;
|
||||||
|
|
||||||
if (regex.test(this.inputStr)) {
|
matches.push(check);
|
||||||
matches.push(pattern);
|
});
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return matches;
|
return matches;
|
||||||
}
|
}
|
||||||
@@ -185,8 +192,10 @@ class Magic {
|
|||||||
*
|
*
|
||||||
* @returns {number}
|
* @returns {number}
|
||||||
*/
|
*/
|
||||||
calcEntropy() {
|
calcEntropy(data=this.inputBuffer, standalone=false) {
|
||||||
const prob = this._freqDist();
|
if (!standalone && this.inputEntropy) return this.inputEntropy;
|
||||||
|
|
||||||
|
const prob = this._freqDist(data, standalone);
|
||||||
let entropy = 0,
|
let entropy = 0,
|
||||||
p;
|
p;
|
||||||
|
|
||||||
@@ -195,6 +204,8 @@ class Magic {
|
|||||||
if (p === 0) continue;
|
if (p === 0) continue;
|
||||||
entropy += p * Math.log(p) / Math.log(2);
|
entropy += p * Math.log(p) / Math.log(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!standalone) this.inputEntropy = -entropy;
|
||||||
return -entropy;
|
return -entropy;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,25 +275,59 @@ class Magic {
|
|||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether the data passes output criteria for an operation check
|
||||||
|
*
|
||||||
|
* @param {ArrayBuffer} data
|
||||||
|
* @param {Object} criteria
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
outputCheckPasses(data, criteria) {
|
||||||
|
if (criteria.pattern) {
|
||||||
|
const dataStr = Utils.arrayBufferToStr(data),
|
||||||
|
regex = new RegExp(criteria.pattern, criteria.flags);
|
||||||
|
if (!regex.test(dataStr))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (criteria.entropyRange) {
|
||||||
|
const dataEntropy = this.calcEntropy(data, true);
|
||||||
|
if (dataEntropy < criteria.entropyRange[0] || dataEntropy > criteria.entropyRange[1])
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (criteria.mime &&
|
||||||
|
!isType(criteria.mime, data))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Speculatively executes matching operations, recording metadata of each result.
|
* Speculatively executes matching operations, recording metadata of each result.
|
||||||
*
|
*
|
||||||
* @param {number} [depth=0] - How many levels to try to execute
|
* @param {number} [depth=0] - How many levels to try to execute
|
||||||
* @param {boolean} [extLang=false] - Extensive language support (false = only check the most
|
* @param {boolean} [extLang=false] - Extensive language support (false = only check the most
|
||||||
* common Internet languages)
|
* common Internet languages)
|
||||||
* @param {boolean} [intensive=false] - Run brute-forcing on each branch (significantly affects
|
* @param {boolean} [intensive=false] - Run brute-forcing on each branch (significantly affects
|
||||||
* performance)
|
* performance)
|
||||||
* @param {Object[]} [recipeConfig=[]] - The recipe configuration up to this point
|
* @param {Object[]} [recipeConfig=[]] - The recipe configuration up to this point
|
||||||
* @param {boolean} [useful=false] - Whether the current recipe should be scored highly
|
* @param {boolean} [useful=false] - Whether the current recipe should be scored highly
|
||||||
* @param {string} [crib=null] - The regex crib provided by the user, for filtering the operation output
|
* @param {string} [crib=null] - The regex crib provided by the user, for filtering the operation
|
||||||
|
* output
|
||||||
* @returns {Object[]} - A sorted list of the recipes most likely to result in correct decoding
|
* @returns {Object[]} - A sorted list of the recipes most likely to result in correct decoding
|
||||||
*/
|
*/
|
||||||
async speculativeExecution(depth=0, extLang=false, intensive=false, recipeConfig=[], useful=false, crib=null) {
|
async speculativeExecution(
|
||||||
|
depth=0,
|
||||||
|
extLang=false,
|
||||||
|
intensive=false,
|
||||||
|
recipeConfig=[],
|
||||||
|
useful=false,
|
||||||
|
crib=null) {
|
||||||
|
|
||||||
|
// If we have reached the recursion depth, return
|
||||||
if (depth < 0) return [];
|
if (depth < 0) return [];
|
||||||
|
|
||||||
// Find any operations that can be run on this data
|
// Find any operations that can be run on this data
|
||||||
const matchingOps = this.findMatchingOps();
|
const matchingOps = this.findMatchingInputOps();
|
||||||
|
|
||||||
let results = [];
|
let results = [];
|
||||||
|
|
||||||
// Record the properties of the current data
|
// Record the properties of the current data
|
||||||
@@ -308,17 +353,21 @@ class Magic {
|
|||||||
},
|
},
|
||||||
output = await this._runRecipe([opConfig]);
|
output = await this._runRecipe([opConfig]);
|
||||||
|
|
||||||
// If the recipe is repeating and returning the same data, do not continue
|
|
||||||
if (prevOp && op.op === prevOp.op && _buffersEqual(output, this.inputBuffer)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// If the recipe returned an empty buffer, do not continue
|
// If the recipe returned an empty buffer, do not continue
|
||||||
if (_buffersEqual(output, new ArrayBuffer())) {
|
if (_buffersEqual(output, new ArrayBuffer())) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const magic = new Magic(output, this.opPatterns),
|
// If the recipe is repeating and returning the same data, do not continue
|
||||||
|
if (prevOp && op.op === prevOp.op && _buffersEqual(output, this.inputBuffer)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the output criteria for this op doesn't match the output, do not continue
|
||||||
|
if (op.output && !this.outputCheckPasses(output, op.output))
|
||||||
|
return;
|
||||||
|
|
||||||
|
const magic = new Magic(output, this.opCriteria, OperationConfig[op.op]),
|
||||||
speculativeResults = await magic.speculativeExecution(
|
speculativeResults = await magic.speculativeExecution(
|
||||||
depth-1, extLang, intensive, [...recipeConfig, opConfig], op.useful, crib);
|
depth-1, extLang, intensive, [...recipeConfig, opConfig], op.useful, crib);
|
||||||
|
|
||||||
@@ -330,7 +379,7 @@ class Magic {
|
|||||||
const bfEncodings = await this.bruteForce();
|
const bfEncodings = await this.bruteForce();
|
||||||
|
|
||||||
await Promise.all(bfEncodings.map(async enc => {
|
await Promise.all(bfEncodings.map(async enc => {
|
||||||
const magic = new Magic(enc.data, this.opPatterns),
|
const magic = new Magic(enc.data, this.opCriteria, undefined),
|
||||||
bfResults = await magic.speculativeExecution(
|
bfResults = await magic.speculativeExecution(
|
||||||
depth-1, extLang, false, [...recipeConfig, enc.conf], false, crib);
|
depth-1, extLang, false, [...recipeConfig, enc.conf], false, crib);
|
||||||
|
|
||||||
@@ -345,7 +394,8 @@ class Magic {
|
|||||||
r.languageScores[0].probability > 0 || // Some kind of language was found
|
r.languageScores[0].probability > 0 || // Some kind of language was found
|
||||||
r.fileType || // A file was found
|
r.fileType || // A file was found
|
||||||
r.isUTF8 || // UTF-8 was found
|
r.isUTF8 || // UTF-8 was found
|
||||||
r.matchingOps.length // A matching op was found
|
r.matchingOps.length || // A matching op was found
|
||||||
|
r.matchesCrib // The crib matches
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -376,9 +426,10 @@ class Magic {
|
|||||||
bScore += b.entropy;
|
bScore += b.entropy;
|
||||||
|
|
||||||
// A result with no recipe but matching ops suggests there are better options
|
// A result with no recipe but matching ops suggests there are better options
|
||||||
if ((!a.recipe.length && a.matchingOps.length) &&
|
if ((!a.recipe.length && a.matchingOps.length) && b.recipe.length)
|
||||||
b.recipe.length)
|
|
||||||
return 1;
|
return 1;
|
||||||
|
if ((!b.recipe.length && b.matchingOps.length) && a.recipe.length)
|
||||||
|
return -1;
|
||||||
|
|
||||||
return aScore - bScore;
|
return aScore - bScore;
|
||||||
});
|
});
|
||||||
@@ -403,7 +454,7 @@ class Magic {
|
|||||||
await recipe.execute(dish);
|
await recipe.execute(dish);
|
||||||
// Return an empty buffer if the recipe did not run to completion
|
// Return an empty buffer if the recipe did not run to completion
|
||||||
if (recipe.lastRunOp === recipe.opList[recipe.opList.length - 1]) {
|
if (recipe.lastRunOp === recipe.opList[recipe.opList.length - 1]) {
|
||||||
return dish.get(Dish.ARRAY_BUFFER);
|
return await dish.get(Dish.ARRAY_BUFFER);
|
||||||
} else {
|
} else {
|
||||||
return new ArrayBuffer();
|
return new ArrayBuffer();
|
||||||
}
|
}
|
||||||
@@ -417,14 +468,16 @@ class Magic {
|
|||||||
* Calculates the number of times each byte appears in the input as a percentage
|
* Calculates the number of times each byte appears in the input as a percentage
|
||||||
*
|
*
|
||||||
* @private
|
* @private
|
||||||
|
* @param {ArrayBuffer} [data]
|
||||||
|
* @param {boolean} [standalone]
|
||||||
* @returns {number[]}
|
* @returns {number[]}
|
||||||
*/
|
*/
|
||||||
_freqDist() {
|
_freqDist(data=this.inputBuffer, standalone=false) {
|
||||||
if (this.freqDist) return this.freqDist;
|
if (!standalone && this.freqDist) return this.freqDist;
|
||||||
|
|
||||||
const len = this.inputBuffer.length;
|
const len = data.length,
|
||||||
|
counts = new Array(256).fill(0);
|
||||||
let i = len;
|
let i = len;
|
||||||
const counts = new Array(256).fill(0);
|
|
||||||
|
|
||||||
if (!len) {
|
if (!len) {
|
||||||
this.freqDist = counts;
|
this.freqDist = counts;
|
||||||
@@ -432,13 +485,15 @@ class Magic {
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (i--) {
|
while (i--) {
|
||||||
counts[this.inputBuffer[i]]++;
|
counts[data[i]]++;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.freqDist = counts.map(c => {
|
const result = counts.map(c => {
|
||||||
return c / len * 100;
|
return c / len * 100;
|
||||||
});
|
});
|
||||||
return this.freqDist;
|
|
||||||
|
if (!standalone) this.freqDist = result;
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -447,24 +502,29 @@ class Magic {
|
|||||||
* @private
|
* @private
|
||||||
* @returns {Object[]}
|
* @returns {Object[]}
|
||||||
*/
|
*/
|
||||||
static _generateOpPatterns() {
|
static _generateOpCriteria() {
|
||||||
const opPatterns = [];
|
const opCriteria = [];
|
||||||
|
|
||||||
for (const op in OperationConfig) {
|
for (const op in OperationConfig) {
|
||||||
if (!("patterns" in OperationConfig[op])) continue;
|
if (!("checks" in OperationConfig[op]))
|
||||||
|
continue;
|
||||||
|
|
||||||
OperationConfig[op].patterns.forEach(pattern => {
|
OperationConfig[op].checks.forEach(check => {
|
||||||
opPatterns.push({
|
// Add to the opCriteria list.
|
||||||
|
// Compile the regex here and cache the compiled version so we
|
||||||
|
// don't have to keep calculating it.
|
||||||
|
opCriteria.push({
|
||||||
op: op,
|
op: op,
|
||||||
match: pattern.match,
|
pattern: check.pattern ? new RegExp(check.pattern, check.flags) : null,
|
||||||
flags: pattern.flags,
|
args: check.args,
|
||||||
args: pattern.args,
|
useful: check.useful,
|
||||||
useful: pattern.useful || false
|
entropyRange: check.entropyRange,
|
||||||
|
output: check.output
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return opPatterns;
|
return opCriteria;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -9,8 +9,9 @@
|
|||||||
import OperationError from "../errors/OperationError.mjs";
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
import jsQR from "jsqr";
|
import jsQR from "jsqr";
|
||||||
import qr from "qr-image";
|
import qr from "qr-image";
|
||||||
import jimp from "jimp";
|
|
||||||
import Utils from "../Utils.mjs";
|
import Utils from "../Utils.mjs";
|
||||||
|
import jimplib from "jimp/es/index.js";
|
||||||
|
const jimp = jimplib.default ? jimplib.default : jimplib;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parses a QR code image from an image
|
* Parses a QR code image from an image
|
||||||
|
|||||||
17
src/core/lib/RSA.mjs
Normal file
17
src/core/lib/RSA.mjs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
/**
|
||||||
|
* RSA resources.
|
||||||
|
*
|
||||||
|
* @author Matt C [me@mitt.dev]
|
||||||
|
* @copyright Crown Copyright 2021
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import forge from "node-forge";
|
||||||
|
|
||||||
|
export const MD_ALGORITHMS = {
|
||||||
|
"SHA-1": forge.md.sha1,
|
||||||
|
"MD5": forge.md.md5,
|
||||||
|
"SHA-256": forge.md.sha256,
|
||||||
|
"SHA-384": forge.md.sha384,
|
||||||
|
"SHA-512": forge.md.sha512,
|
||||||
|
};
|
||||||
@@ -155,19 +155,69 @@ export default class Stream {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// val is an array
|
// val is an array
|
||||||
let found = false;
|
|
||||||
while (!found && this.position < this.length) {
|
/**
|
||||||
while (++this.position < this.length && this.bytes[this.position] !== val[0]) {
|
* Builds the skip forward table from the value to be searched.
|
||||||
continue;
|
*
|
||||||
}
|
* @param {Uint8Array} val
|
||||||
|
* @param {Number} len
|
||||||
|
* @returns {Uint8Array}
|
||||||
|
*/
|
||||||
|
function preprocess(val, len) {
|
||||||
|
const skiptable = new Array();
|
||||||
|
val.forEach((element, index) => {
|
||||||
|
skiptable[element] = len - index;
|
||||||
|
});
|
||||||
|
return skiptable;
|
||||||
|
}
|
||||||
|
|
||||||
|
const length = val.length;
|
||||||
|
const initial = val[length-1];
|
||||||
|
this.position = length;
|
||||||
|
|
||||||
|
// Get the skip table.
|
||||||
|
const skiptable = preprocess(val, length);
|
||||||
|
let found;
|
||||||
|
|
||||||
|
while (this.position < this.length) {
|
||||||
|
// Until we hit the final element of val in the stream.
|
||||||
|
while ((this.position < this.length) && (this.bytes[this.position++] !== initial));
|
||||||
|
|
||||||
found = true;
|
found = true;
|
||||||
for (let i = 1; i < val.length; i++) {
|
|
||||||
if (this.position + i > this.length || this.bytes[this.position + i] !== val[i])
|
// Loop through the elements comparing them to val.
|
||||||
|
for (let x = length-1; x >= 0; x--) {
|
||||||
|
if (this.bytes[this.position - length + x] !== val[x]) {
|
||||||
found = false;
|
found = false;
|
||||||
|
|
||||||
|
// If element is not equal to val's element then jump forward by the correct amount.
|
||||||
|
this.position += skiptable[val[x]];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (found) {
|
||||||
|
this.position -= length;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Consume bytes if they match the supplied value.
|
||||||
|
*
|
||||||
|
* @param {Number} val
|
||||||
|
*/
|
||||||
|
consumeWhile(val) {
|
||||||
|
while (this.position < this.length) {
|
||||||
|
if (this.bytes[this.position] !== val) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this.position++;
|
||||||
|
}
|
||||||
|
this.bitPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Consume the next byte if it matches the supplied value.
|
* Consume the next byte if it matches the supplied value.
|
||||||
*
|
*
|
||||||
@@ -253,11 +303,13 @@ export default class Stream {
|
|||||||
/**
|
/**
|
||||||
* Returns a slice of the stream up to the current position.
|
* Returns a slice of the stream up to the current position.
|
||||||
*
|
*
|
||||||
|
* @param {number} [start=0]
|
||||||
|
* @param {number} [finish=this.position]
|
||||||
* @returns {Uint8Array}
|
* @returns {Uint8Array}
|
||||||
*/
|
*/
|
||||||
carve() {
|
carve(start=0, finish=this.position) {
|
||||||
if (this.bitPos > 0) this.position++;
|
if (this.bitPos > 0) finish++;
|
||||||
return this.bytes.slice(0, this.position);
|
return this.bytes.slice(start, finish);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,38 @@ class A1Z26CipherDecode extends Operation {
|
|||||||
value: DELIM_OPTIONS
|
value: DELIM_OPTIONS
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
this.checks = [
|
||||||
|
{
|
||||||
|
pattern: "^\\s*([12]?[0-9] )+[12]?[0-9]\\s*$",
|
||||||
|
flags: "",
|
||||||
|
args: ["Space"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: "^\\s*([12]?[0-9],)+[12]?[0-9]\\s*$",
|
||||||
|
flags: "",
|
||||||
|
args: ["Comma"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: "^\\s*([12]?[0-9];)+[12]?[0-9]\\s*$",
|
||||||
|
flags: "",
|
||||||
|
args: ["Semi-colon"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: "^\\s*([12]?[0-9]:)+[12]?[0-9]\\s*$",
|
||||||
|
flags: "",
|
||||||
|
args: ["Colon"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: "^\\s*([12]?[0-9]\\n)+[12]?[0-9]\\s*$",
|
||||||
|
flags: "",
|
||||||
|
args: ["Line feed"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: "^\\s*([12]?[0-9]\\r\\n)+[12]?[0-9]\\s*$",
|
||||||
|
flags: "",
|
||||||
|
args: ["CRLF"]
|
||||||
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
import Operation from "../Operation.mjs";
|
import Operation from "../Operation.mjs";
|
||||||
import Utils from "../Utils.mjs";
|
import Utils from "../Utils.mjs";
|
||||||
import forge from "node-forge/dist/forge.min.js";
|
import forge from "node-forge";
|
||||||
import OperationError from "../errors/OperationError.mjs";
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -41,8 +41,33 @@ class AESDecrypt extends Operation {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Mode",
|
"name": "Mode",
|
||||||
"type": "option",
|
"type": "argSelector",
|
||||||
"value": ["CBC", "CFB", "OFB", "CTR", "GCM", "ECB"]
|
"value": [
|
||||||
|
{
|
||||||
|
name: "CBC",
|
||||||
|
off: [5, 6]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "CFB",
|
||||||
|
off: [5, 6]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "OFB",
|
||||||
|
off: [5, 6]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "CTR",
|
||||||
|
off: [5, 6]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "GCM",
|
||||||
|
on: [5, 6]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ECB",
|
||||||
|
off: [5, 6]
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Input",
|
"name": "Input",
|
||||||
@@ -59,6 +84,11 @@ class AESDecrypt extends Operation {
|
|||||||
"type": "toggleString",
|
"type": "toggleString",
|
||||||
"value": "",
|
"value": "",
|
||||||
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
|
"toggleValues": ["Hex", "UTF8", "Latin1", "Base64"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Additional Authenticated Data",
|
||||||
|
"type": "binaryString",
|
||||||
|
"value": ""
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -76,7 +106,8 @@ class AESDecrypt extends Operation {
|
|||||||
mode = args[2],
|
mode = args[2],
|
||||||
inputType = args[3],
|
inputType = args[3],
|
||||||
outputType = args[4],
|
outputType = args[4],
|
||||||
gcmTag = Utils.convertToByteString(args[5].string, args[5].option);
|
gcmTag = Utils.convertToByteString(args[5].string, args[5].option),
|
||||||
|
aad = args[6];
|
||||||
|
|
||||||
if ([16, 24, 32].indexOf(key.length) < 0) {
|
if ([16, 24, 32].indexOf(key.length) < 0) {
|
||||||
throw new OperationError(`Invalid key length: ${key.length} bytes
|
throw new OperationError(`Invalid key length: ${key.length} bytes
|
||||||
@@ -92,7 +123,8 @@ The following algorithms will be used based on the size of the key:
|
|||||||
const decipher = forge.cipher.createDecipher("AES-" + mode, key);
|
const decipher = forge.cipher.createDecipher("AES-" + mode, key);
|
||||||
decipher.start({
|
decipher.start({
|
||||||
iv: iv.length === 0 ? "" : iv,
|
iv: iv.length === 0 ? "" : iv,
|
||||||
tag: gcmTag
|
tag: mode === "GCM" ? gcmTag : undefined,
|
||||||
|
additionalData: mode === "GCM" ? aad : undefined
|
||||||
});
|
});
|
||||||
decipher.update(forge.util.createBuffer(input));
|
decipher.update(forge.util.createBuffer(input));
|
||||||
const result = decipher.finish();
|
const result = decipher.finish();
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
import Operation from "../Operation.mjs";
|
import Operation from "../Operation.mjs";
|
||||||
import Utils from "../Utils.mjs";
|
import Utils from "../Utils.mjs";
|
||||||
import forge from "node-forge/dist/forge.min.js";
|
import forge from "node-forge";
|
||||||
import OperationError from "../errors/OperationError.mjs";
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -41,8 +41,33 @@ class AESEncrypt extends Operation {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Mode",
|
"name": "Mode",
|
||||||
"type": "option",
|
"type": "argSelector",
|
||||||
"value": ["CBC", "CFB", "OFB", "CTR", "GCM", "ECB"]
|
"value": [
|
||||||
|
{
|
||||||
|
name: "CBC",
|
||||||
|
off: [5]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "CFB",
|
||||||
|
off: [5]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "OFB",
|
||||||
|
off: [5]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "CTR",
|
||||||
|
off: [5]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "GCM",
|
||||||
|
on: [5]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ECB",
|
||||||
|
off: [5]
|
||||||
|
}
|
||||||
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Input",
|
"name": "Input",
|
||||||
@@ -53,6 +78,11 @@ class AESEncrypt extends Operation {
|
|||||||
"name": "Output",
|
"name": "Output",
|
||||||
"type": "option",
|
"type": "option",
|
||||||
"value": ["Hex", "Raw"]
|
"value": ["Hex", "Raw"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Additional Authenticated Data",
|
||||||
|
"type": "binaryString",
|
||||||
|
"value": ""
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -69,7 +99,8 @@ class AESEncrypt extends Operation {
|
|||||||
iv = Utils.convertToByteString(args[1].string, args[1].option),
|
iv = Utils.convertToByteString(args[1].string, args[1].option),
|
||||||
mode = args[2],
|
mode = args[2],
|
||||||
inputType = args[3],
|
inputType = args[3],
|
||||||
outputType = args[4];
|
outputType = args[4],
|
||||||
|
aad = args[5];
|
||||||
|
|
||||||
if ([16, 24, 32].indexOf(key.length) < 0) {
|
if ([16, 24, 32].indexOf(key.length) < 0) {
|
||||||
throw new OperationError(`Invalid key length: ${key.length} bytes
|
throw new OperationError(`Invalid key length: ${key.length} bytes
|
||||||
@@ -83,7 +114,10 @@ The following algorithms will be used based on the size of the key:
|
|||||||
input = Utils.convertToByteString(input, inputType);
|
input = Utils.convertToByteString(input, inputType);
|
||||||
|
|
||||||
const cipher = forge.cipher.createCipher("AES-" + mode, key);
|
const cipher = forge.cipher.createCipher("AES-" + mode, key);
|
||||||
cipher.start({iv: iv});
|
cipher.start({
|
||||||
|
iv: iv,
|
||||||
|
additionalData: mode === "GCM" ? aad : undefined
|
||||||
|
});
|
||||||
cipher.update(forge.util.createBuffer(input));
|
cipher.update(forge.util.createBuffer(input));
|
||||||
cipher.finish();
|
cipher.finish();
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ import OperationError from "../errors/OperationError.mjs";
|
|||||||
import { isImage } from "../lib/FileType.mjs";
|
import { isImage } from "../lib/FileType.mjs";
|
||||||
import { toBase64 } from "../lib/Base64.mjs";
|
import { toBase64 } from "../lib/Base64.mjs";
|
||||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||||
import jimp from "jimp";
|
import jimplib from "jimp/es/index.js";
|
||||||
|
const jimp = jimplib.default ? jimplib.default : jimplib;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add Text To Image operation
|
* Add Text To Image operation
|
||||||
|
|||||||
@@ -44,6 +44,48 @@ class BaconCipherDecode extends Operation {
|
|||||||
"value": false
|
"value": false
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
this.checks = [
|
||||||
|
{
|
||||||
|
pattern: "^\\s*([01]{5}\\s?)+$",
|
||||||
|
flags: "",
|
||||||
|
args: ["Standard (I=J and U=V)", "0/1", false]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: "^\\s*([01]{5}\\s?)+$",
|
||||||
|
flags: "",
|
||||||
|
args: ["Standard (I=J and U=V)", "0/1", true]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: "^\\s*([AB]{5}\\s?)+$",
|
||||||
|
flags: "",
|
||||||
|
args: ["Standard (I=J and U=V)", "A/B", false]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: "^\\s*([AB]{5}\\s?)+$",
|
||||||
|
flags: "",
|
||||||
|
args: ["Standard (I=J and U=V)", "A/B", true]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: "^\\s*([01]{5}\\s?)+$",
|
||||||
|
flags: "",
|
||||||
|
args: ["Complete", "0/1", false]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: "^\\s*([01]{5}\\s?)+$",
|
||||||
|
flags: "",
|
||||||
|
args: ["Complete", "0/1", true]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: "^\\s*([AB]{5}\\s?)+$",
|
||||||
|
flags: "",
|
||||||
|
args: ["Complete", "A/B", false]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: "^\\s*([AB]{5}\\s?)+$",
|
||||||
|
flags: "",
|
||||||
|
args: ["Complete", "A/B", true]
|
||||||
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
import Operation from "../Operation.mjs";
|
import Operation from "../Operation.mjs";
|
||||||
import Utils from "../Utils.mjs";
|
import Utils from "../Utils.mjs";
|
||||||
import forge from "node-forge/dist/forge.min.js";
|
import forge from "node-forge";
|
||||||
import OperationError from "../errors/OperationError.mjs";
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
import { Blowfish } from "../lib/Blowfish.mjs";
|
import { Blowfish } from "../lib/Blowfish.mjs";
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
import Operation from "../Operation.mjs";
|
import Operation from "../Operation.mjs";
|
||||||
import Utils from "../Utils.mjs";
|
import Utils from "../Utils.mjs";
|
||||||
import forge from "node-forge/dist/forge.min.js";
|
import forge from "node-forge";
|
||||||
import OperationError from "../errors/OperationError.mjs";
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
import { Blowfish } from "../lib/Blowfish.mjs";
|
import { Blowfish } from "../lib/Blowfish.mjs";
|
||||||
|
|
||||||
|
|||||||
@@ -9,8 +9,9 @@ import OperationError from "../errors/OperationError.mjs";
|
|||||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||||
import { isImage } from "../lib/FileType.mjs";
|
import { isImage } from "../lib/FileType.mjs";
|
||||||
import { toBase64 } from "../lib/Base64.mjs";
|
import { toBase64 } from "../lib/Base64.mjs";
|
||||||
import jimp from "jimp";
|
|
||||||
import { gaussianBlur } from "../lib/ImageManipulation.mjs";
|
import { gaussianBlur } from "../lib/ImageManipulation.mjs";
|
||||||
|
import jimplib from "jimp/es/index.js";
|
||||||
|
const jimp = jimplib.default ? jimplib.default : jimplib;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Blur Image operation
|
* Blur Image operation
|
||||||
|
|||||||
@@ -33,9 +33,9 @@ class Bzip2Decompress extends Operation {
|
|||||||
value: false
|
value: false
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
this.patterns = [
|
this.checks = [
|
||||||
{
|
{
|
||||||
"match": "^\\x42\\x5a\\x68",
|
"pattern": "^\\x42\\x5a\\x68",
|
||||||
"flags": "",
|
"flags": "",
|
||||||
"args": []
|
"args": []
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class CTPH extends Operation {
|
|||||||
this.name = "CTPH";
|
this.name = "CTPH";
|
||||||
this.module = "Crypto";
|
this.module = "Crypto";
|
||||||
this.description = "Context Triggered Piecewise Hashing, also called Fuzzy Hashing, can match inputs that have homologies. Such inputs have sequences of identical bytes in the same order, although bytes in between these sequences may be different in both content and length.<br><br>CTPH was originally based on the work of Dr. Andrew Tridgell and a spam email detector called SpamSum. This method was adapted by Jesse Kornblum and published at the DFRWS conference in 2006 in a paper 'Identifying Almost Identical Files Using Context Triggered Piecewise Hashing'.";
|
this.description = "Context Triggered Piecewise Hashing, also called Fuzzy Hashing, can match inputs that have homologies. Such inputs have sequences of identical bytes in the same order, although bytes in between these sequences may be different in both content and length.<br><br>CTPH was originally based on the work of Dr. Andrew Tridgell and a spam email detector called SpamSum. This method was adapted by Jesse Kornblum and published at the DFRWS conference in 2006 in a paper 'Identifying Almost Identical Files Using Context Triggered Piecewise Hashing'.";
|
||||||
this.infoURL = "https://forensicswiki.org/wiki/Context_Triggered_Piecewise_Hashing";
|
this.infoURL = "https://forensicswiki.xyz/wiki/index.php?title=Context_Triggered_Piecewise_Hashing";
|
||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
this.outputType = "string";
|
this.outputType = "string";
|
||||||
this.args = [];
|
this.args = [];
|
||||||
|
|||||||
61
src/core/operations/CipherSaber2Decrypt.mjs
Normal file
61
src/core/operations/CipherSaber2Decrypt.mjs
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/**
|
||||||
|
* @author n1073645 [n1073645@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2020
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import { encode } from "../lib/CipherSaber2.mjs";
|
||||||
|
import Utils from "../Utils.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CipherSaber2 Decrypt operation
|
||||||
|
*/
|
||||||
|
class CipherSaber2Decrypt extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CipherSaber2Decrypt constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "CipherSaber2 Decrypt";
|
||||||
|
this.module = "Crypto";
|
||||||
|
this.description = "CipherSaber is a simple symmetric encryption protocol based on the RC4 stream cipher. It gives reasonably strong protection of message confidentiality, yet it's designed to be simple enough that even novice programmers can memorize the algorithm and implement it from scratch.";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/CipherSaber";
|
||||||
|
this.inputType = "ArrayBuffer";
|
||||||
|
this.outputType = "ArrayBuffer";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
name: "Key",
|
||||||
|
type: "toggleString",
|
||||||
|
value: "",
|
||||||
|
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Rounds",
|
||||||
|
type: "number",
|
||||||
|
value: 20
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {ArrayBuffer} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {ArrayBuffer}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
input = new Uint8Array(input);
|
||||||
|
const result = [],
|
||||||
|
key = Utils.convertToByteArray(args[0].string, args[0].option),
|
||||||
|
rounds = args[1];
|
||||||
|
|
||||||
|
const tempIVP = input.slice(0, 10);
|
||||||
|
input = input.slice(10);
|
||||||
|
return new Uint8Array(result.concat(encode(tempIVP, key, rounds, input))).buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CipherSaber2Decrypt;
|
||||||
65
src/core/operations/CipherSaber2Encrypt.mjs
Normal file
65
src/core/operations/CipherSaber2Encrypt.mjs
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
/**
|
||||||
|
* @author n1073645 [n1073645@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2020
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import crypto from "crypto";
|
||||||
|
import { encode } from "../lib/CipherSaber2.mjs";
|
||||||
|
import Utils from "../Utils.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CipherSaber2 Encrypt operation
|
||||||
|
*/
|
||||||
|
class CipherSaber2Encrypt extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CipherSaber2Encrypt constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "CipherSaber2 Encrypt";
|
||||||
|
this.module = "Crypto";
|
||||||
|
this.description = "CipherSaber is a simple symmetric encryption protocol based on the RC4 stream cipher. It gives reasonably strong protection of message confidentiality, yet it's designed to be simple enough that even novice programmers can memorize the algorithm and implement it from scratch.";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/CipherSaber";
|
||||||
|
this.inputType = "ArrayBuffer";
|
||||||
|
this.outputType = "ArrayBuffer";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
name: "Key",
|
||||||
|
type: "toggleString",
|
||||||
|
value: "",
|
||||||
|
toggleValues: ["Hex", "UTF8", "Latin1", "Base64"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Rounds",
|
||||||
|
type: "number",
|
||||||
|
value: 20
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {ArrayBuffer} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {ArrayBuffer}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
input = new Uint8Array(input);
|
||||||
|
const result = [],
|
||||||
|
key = Utils.convertToByteArray(args[0].string, args[0].option),
|
||||||
|
rounds = args[1];
|
||||||
|
|
||||||
|
// Assign into initialisation vector based on cipher mode.
|
||||||
|
const tempIVP = crypto.randomBytes(10);
|
||||||
|
for (let m = 0; m < 10; m++)
|
||||||
|
result.push(tempIVP[m]);
|
||||||
|
|
||||||
|
return new Uint8Array(result.concat(encode(tempIVP, key, rounds, input))).buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CipherSaber2Encrypt;
|
||||||
583
src/core/operations/Colossus.mjs
Normal file
583
src/core/operations/Colossus.mjs
Normal file
@@ -0,0 +1,583 @@
|
|||||||
|
/**
|
||||||
|
* Emulation of Colossus.
|
||||||
|
*
|
||||||
|
* @author VirtualColossus [martin@virtualcolossus.co.uk]
|
||||||
|
* @copyright Crown Copyright 2019
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
import { ColossusComputer } from "../lib/Colossus.mjs";
|
||||||
|
import { SWITCHES, VALID_ITA2 } from "../lib/Lorenz.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Colossus operation
|
||||||
|
*/
|
||||||
|
class Colossus extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Colossus constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this.name = "Colossus";
|
||||||
|
this.module = "Bletchley";
|
||||||
|
this.description = "Colossus is the name of the world's first electronic computer. Ten Colossi were designed by Tommy Flowers and built at the Post Office Research Labs at Dollis Hill in 1943 during World War 2. They assisted with the breaking of the German Lorenz cipher attachment, a machine created to encipher communications between Hitler and his generals on the front lines.<br><br>To learn more, Virtual Colossus, an online, browser based simulation of a Colossus computer is available at <a href='https://virtualcolossus.co.uk' target='_blank'>virtualcolossus.co.uk</a>.<br><br>A more detailed description of this operation can be found <a href='https://github.com/gchq/CyberChef/wiki/Colossus' target='_blank'>here</a>.";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/Colossus_computer";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "JSON";
|
||||||
|
this.presentType = "html";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
name: "Input",
|
||||||
|
type: "label"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Pattern",
|
||||||
|
type: "option",
|
||||||
|
value: ["KH Pattern", "ZMUG Pattern", "BREAM Pattern"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "QBusZ",
|
||||||
|
type: "option",
|
||||||
|
value: ["", "Z", "ΔZ"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "QBusΧ",
|
||||||
|
type: "option",
|
||||||
|
value: ["", "Χ", "ΔΧ"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "QBusΨ",
|
||||||
|
type: "option",
|
||||||
|
value: ["", "Ψ", "ΔΨ"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Limitation",
|
||||||
|
type: "option",
|
||||||
|
value: ["None", "Χ2", "Χ2 + P5", "X2 + Ψ1", "X2 + Ψ1 + P5"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "K Rack Option",
|
||||||
|
type: "argSelector",
|
||||||
|
value: [
|
||||||
|
{
|
||||||
|
name: "Select Program",
|
||||||
|
on: [7],
|
||||||
|
off: [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Top Section - Conditional",
|
||||||
|
on: [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30],
|
||||||
|
off: [7, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Bottom Section - Addition",
|
||||||
|
on: [31, 32, 33, 34, 35, 36, 37, 38, 39, 40],
|
||||||
|
off: [7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Advanced",
|
||||||
|
on: [8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40],
|
||||||
|
off: [7]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Program to run",
|
||||||
|
type: "option",
|
||||||
|
value: ["", "Letter Count", "1+2=. (1+2 Break In, Find X1,X2)", "4=5=/1=2 (Given X1,X2 find X4,X5)", "/,5,U (Count chars to find X3)"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "K Rack: Conditional",
|
||||||
|
type: "label"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R1-Q1",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES,
|
||||||
|
defaultIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R1-Q2",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES,
|
||||||
|
defaultIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R1-Q3",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES,
|
||||||
|
defaultIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R1-Q4",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES,
|
||||||
|
defaultIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R1-Q5",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES,
|
||||||
|
defaultIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R1-Negate",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R1-Counter",
|
||||||
|
type: "option",
|
||||||
|
value: ["", "1", "2", "3", "4", "5"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R2-Q1",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES,
|
||||||
|
defaultIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R2-Q2",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES,
|
||||||
|
defaultIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R2-Q3",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES,
|
||||||
|
defaultIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R2-Q4",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES,
|
||||||
|
defaultIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R2-Q5",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES,
|
||||||
|
defaultIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R2-Negate",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R2-Counter",
|
||||||
|
type: "option",
|
||||||
|
value: ["", "1", "2", "3", "4", "5"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R3-Q1",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES,
|
||||||
|
defaultIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R3-Q2",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES,
|
||||||
|
defaultIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R3-Q3",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES,
|
||||||
|
defaultIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R3-Q4",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES,
|
||||||
|
defaultIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R3-Q5",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES,
|
||||||
|
defaultIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R3-Negate",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "R3-Counter",
|
||||||
|
type: "option",
|
||||||
|
value: ["", "1", "2", "3", "4", "5"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Negate All",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "K Rack: Addition",
|
||||||
|
type: "label"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Add-Q1",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Add-Q2",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Add-Q3",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Add-Q4",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Add-Q5",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Add-Equals",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES,
|
||||||
|
defaultIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Add-Counter1",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Add Negate All",
|
||||||
|
type: "boolean",
|
||||||
|
value: false
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Total Motor",
|
||||||
|
type: "editableOptionShort",
|
||||||
|
value: SWITCHES,
|
||||||
|
defaultIndex: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Master Control Panel",
|
||||||
|
type: "label"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Set Total",
|
||||||
|
type: "number",
|
||||||
|
value: 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Fast Step",
|
||||||
|
type: "option",
|
||||||
|
value: ["", "X1", "X2", "X3", "X4", "X5", "M37", "M61", "S1", "S2", "S3", "S4", "S5"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Slow Step",
|
||||||
|
type: "option",
|
||||||
|
value: ["", "X1", "X2", "X3", "X4", "X5", "M37", "M61", "S1", "S2", "S3", "S4", "S5"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Start Χ1",
|
||||||
|
type: "number",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Start Χ2",
|
||||||
|
type: "number",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Start Χ3",
|
||||||
|
type: "number",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Start Χ4",
|
||||||
|
type: "number",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Start Χ5",
|
||||||
|
type: "number",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Start M61",
|
||||||
|
type: "number",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Start M37",
|
||||||
|
type: "number",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Start Ψ1",
|
||||||
|
type: "number",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Start Ψ2",
|
||||||
|
type: "number",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Start Ψ3",
|
||||||
|
type: "number",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Start Ψ4",
|
||||||
|
type: "number",
|
||||||
|
value: 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Start Ψ5",
|
||||||
|
type: "number",
|
||||||
|
value: 1
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {Object}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
input = input.toUpperCase();
|
||||||
|
for (const character of input) {
|
||||||
|
if (VALID_ITA2.indexOf(character) === -1) {
|
||||||
|
let errltr = character;
|
||||||
|
if (errltr === "\n") errltr = "Carriage Return";
|
||||||
|
if (errltr === " ") errltr = "Space";
|
||||||
|
throw new OperationError("Invalid ITA2 character : " + errltr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const pattern = args[1];
|
||||||
|
const qbusin = {
|
||||||
|
"Z": args[2],
|
||||||
|
"Chi": args[3],
|
||||||
|
"Psi": args[4],
|
||||||
|
};
|
||||||
|
|
||||||
|
const limitation = args[5];
|
||||||
|
const lm = [false, false, false];
|
||||||
|
if (limitation.includes("Χ2")) lm[0] = true;
|
||||||
|
if (limitation.includes("Ψ1")) lm[1] = true;
|
||||||
|
if (limitation.includes("P5")) lm[2] = true;
|
||||||
|
const limit = {
|
||||||
|
X2: lm[0], S1: lm[1], P5: lm[2]
|
||||||
|
};
|
||||||
|
|
||||||
|
const KRackOpt = args[6];
|
||||||
|
const setProgram = args[7];
|
||||||
|
|
||||||
|
if (KRackOpt === "Select Program" && setProgram !== "") {
|
||||||
|
args = this.selectProgram(setProgram, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
const re = new RegExp("^$|^[.x]$");
|
||||||
|
for (let qr=0;qr<3;qr++) {
|
||||||
|
for (let a=0;a<5;a++) {
|
||||||
|
if (!re.test(args[((qr*7)+(a+9))]))
|
||||||
|
throw new OperationError("Switch R"+(qr+1)+"-Q"+(a+1)+" can only be set to blank, . or x");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!re.test(args[37])) throw new OperationError("Switch Add-Equals can only be set to blank, . or x");
|
||||||
|
if (!re.test(args[40])) throw new OperationError("Switch Total Motor can only be set to blank, . or x");
|
||||||
|
|
||||||
|
// Q1,Q2,Q3,Q4,Q5,negate,counter1
|
||||||
|
const qbusswitches = {
|
||||||
|
condition: [
|
||||||
|
{Qswitches: [args[9], args[10], args[11], args[12], args[13]], Negate: args[14], Counter: args[15]},
|
||||||
|
{Qswitches: [args[16], args[17], args[18], args[19], args[20]], Negate: args[21], Counter: args[22]},
|
||||||
|
{Qswitches: [args[23], args[24], args[25], args[26], args[27]], Negate: args[28], Counter: args[29]}
|
||||||
|
],
|
||||||
|
condNegateAll: args[30],
|
||||||
|
addition: [
|
||||||
|
{Qswitches: [args[32], args[33], args[34], args[35], args[36]], Equals: args[37], C1: args[38]}
|
||||||
|
],
|
||||||
|
addNegateAll: args[39],
|
||||||
|
totalMotor: args[40]
|
||||||
|
};
|
||||||
|
|
||||||
|
const settotal = parseInt(args[42], 10);
|
||||||
|
if (settotal < 0 || settotal > 9999)
|
||||||
|
throw new OperationError("Set Total must be between 0000 and 9999");
|
||||||
|
|
||||||
|
// null|fast|slow for each of S1-5,M1-2,X1-5
|
||||||
|
const control = {
|
||||||
|
fast: args[43],
|
||||||
|
slow: args[44]
|
||||||
|
};
|
||||||
|
|
||||||
|
// Start positions
|
||||||
|
if (args[52]<1 || args[52]>43) throw new OperationError("Ψ1 start must be between 1 and 43");
|
||||||
|
if (args[53]<1 || args[53]>47) throw new OperationError("Ψ2 start must be between 1 and 47");
|
||||||
|
if (args[54]<1 || args[54]>51) throw new OperationError("Ψ3 start must be between 1 and 51");
|
||||||
|
if (args[55]<1 || args[55]>53) throw new OperationError("Ψ4 start must be between 1 and 53");
|
||||||
|
if (args[56]<1 || args[57]>59) throw new OperationError("Ψ5 start must be between 1 and 59");
|
||||||
|
if (args[51]<1 || args[51]>37) throw new OperationError("Μ37 start must be between 1 and 37");
|
||||||
|
if (args[50]<1 || args[50]>61) throw new OperationError("Μ61 start must be between 1 and 61");
|
||||||
|
if (args[45]<1 || args[45]>41) throw new OperationError("Χ1 start must be between 1 and 41");
|
||||||
|
if (args[46]<1 || args[46]>31) throw new OperationError("Χ2 start must be between 1 and 31");
|
||||||
|
if (args[47]<1 || args[47]>29) throw new OperationError("Χ3 start must be between 1 and 29");
|
||||||
|
if (args[48]<1 || args[48]>26) throw new OperationError("Χ4 start must be between 1 and 26");
|
||||||
|
if (args[49]<1 || args[49]>23) throw new OperationError("Χ5 start must be between 1 and 23");
|
||||||
|
|
||||||
|
const starts = {
|
||||||
|
X1: args[45], X2: args[46], X3: args[47], X4: args[48], X5: args[49],
|
||||||
|
M61: args[50], M37: args[51],
|
||||||
|
S1: args[52], S2: args[53], S3: args[54], S4: args[55], S5: args[56]
|
||||||
|
};
|
||||||
|
|
||||||
|
const colossus = new ColossusComputer(input, pattern, qbusin, qbusswitches, control, starts, settotal, limit);
|
||||||
|
const result = colossus.run();
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Select Program
|
||||||
|
*
|
||||||
|
* @param {string} progname
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {Object[]}
|
||||||
|
*/
|
||||||
|
selectProgram(progname, args) {
|
||||||
|
|
||||||
|
// Basic Letter Count
|
||||||
|
if (progname === "Letter Count") {
|
||||||
|
// Set Conditional R1 : count every character into counter 1
|
||||||
|
args[9] = "";
|
||||||
|
args[10] = "";
|
||||||
|
args[11] = "";
|
||||||
|
args[12] = "";
|
||||||
|
args[13] = "";
|
||||||
|
args[14] = false;
|
||||||
|
args[15] = "1";
|
||||||
|
// clear Conditional R2 & R3
|
||||||
|
args[22] = "";
|
||||||
|
args[29] = "";
|
||||||
|
// Clear Negate result
|
||||||
|
args[30] = false;
|
||||||
|
// Clear Addition row counter
|
||||||
|
args[38] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bill Tutte's 1+2 Break In
|
||||||
|
if (progname === "1+2=. (1+2 Break In, Find X1,X2)") {
|
||||||
|
// Clear any other counters
|
||||||
|
args[15] = ""; // Conditional R1
|
||||||
|
args[22] = ""; // Conditional R2
|
||||||
|
args[29] = ""; // Conditional R3
|
||||||
|
// Set Add Q1+Q2=. into Counter 1
|
||||||
|
args[32] = true;
|
||||||
|
args[33] = true;
|
||||||
|
args[34] = false;
|
||||||
|
args[35] = false;
|
||||||
|
args[36] = false;
|
||||||
|
args[37] = ".";
|
||||||
|
args[38] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4=3=/1=2 : Find X4 & X5 where X1 & X2 are known
|
||||||
|
if (progname === "4=5=/1=2 (Given X1,X2 find X4,X5)") {
|
||||||
|
// Set Conditional R1 : Match NOT ..?.. into counter 1
|
||||||
|
args[9] = ".";
|
||||||
|
args[10] = ".";
|
||||||
|
args[11] = "";
|
||||||
|
args[12] = ".";
|
||||||
|
args[13] = ".";
|
||||||
|
args[14] = true;
|
||||||
|
args[15] = "1";
|
||||||
|
// Set Conditional R2 : AND Match NOT xx?xx into counter 1
|
||||||
|
args[16] = "x";
|
||||||
|
args[17] = "x";
|
||||||
|
args[18] = "";
|
||||||
|
args[19] = "x";
|
||||||
|
args[20] = "x";
|
||||||
|
args[21] = true;
|
||||||
|
args[22] = "1";
|
||||||
|
// clear Conditional R3
|
||||||
|
args[29] = "";
|
||||||
|
// Negate result, giving NOT(NOT Q1 AND NOT Q2) which is equivalent to Q1 OR Q2
|
||||||
|
args[30] = true;
|
||||||
|
// Clear Addition row counter
|
||||||
|
args[38] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// /,5,U : Count number of matches of /, 5 & U to find X3
|
||||||
|
if (progname === "/,5,U (Count chars to find X3)") {
|
||||||
|
// Set Conditional R1 : Match / char, ITA2 = ..... into counter 1
|
||||||
|
args[9] = ".";
|
||||||
|
args[10] = ".";
|
||||||
|
args[11] = ".";
|
||||||
|
args[12] = ".";
|
||||||
|
args[13] = ".";
|
||||||
|
args[14] = false;
|
||||||
|
args[15] = "1";
|
||||||
|
// Set Conditional R2 : Match 5 char, ITA2 = xx.xx into counter 2
|
||||||
|
args[16] = "x";
|
||||||
|
args[17] = "x";
|
||||||
|
args[18] = ".";
|
||||||
|
args[19] = "x";
|
||||||
|
args[20] = "x";
|
||||||
|
args[21] = false;
|
||||||
|
args[22] = "2";
|
||||||
|
// Set Conditional R3 : Match U char, ITA2 = xxx.. into counter 3
|
||||||
|
args[23] = "x";
|
||||||
|
args[24] = "x";
|
||||||
|
args[25] = "x";
|
||||||
|
args[26] = ".";
|
||||||
|
args[27] = ".";
|
||||||
|
args[28] = false;
|
||||||
|
args[29] = "3";
|
||||||
|
// Clear Negate result
|
||||||
|
args[30] = false;
|
||||||
|
// Clear Addition row counter
|
||||||
|
args[38] = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return args;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays Colossus results in an HTML table
|
||||||
|
*
|
||||||
|
* @param {Object} output
|
||||||
|
* @param {Object[]} output.counters
|
||||||
|
* @returns {html}
|
||||||
|
*/
|
||||||
|
present(output) {
|
||||||
|
let html = "Colossus Printer\n\n";
|
||||||
|
html += output.printout + "\n\n";
|
||||||
|
html += "Colossus Counters\n\n";
|
||||||
|
html += "<table class='table table-hover table-sm table-bordered table-nonfluid'><tr><th>C1</th> <th>C2</th> <th>C3</th> <th>C4</th> <th>C5</th></tr>\n";
|
||||||
|
html += "<tr>";
|
||||||
|
for (const ct of output.counters) {
|
||||||
|
html += `<td>${ct}</td>\n`;
|
||||||
|
}
|
||||||
|
html += "</tr>";
|
||||||
|
html += "</table>";
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Colossus;
|
||||||
@@ -24,7 +24,7 @@ class CompareCTPHHashes extends Operation {
|
|||||||
this.name = "Compare CTPH hashes";
|
this.name = "Compare CTPH hashes";
|
||||||
this.module = "Crypto";
|
this.module = "Crypto";
|
||||||
this.description = "Compares two Context Triggered Piecewise Hashing (CTPH) fuzzy hashes to determine the similarity between them on a scale of 0 to 100.";
|
this.description = "Compares two Context Triggered Piecewise Hashing (CTPH) fuzzy hashes to determine the similarity between them on a scale of 0 to 100.";
|
||||||
this.infoURL = "https://forensicswiki.org/wiki/Context_Triggered_Piecewise_Hashing";
|
this.infoURL = "https://forensicswiki.xyz/wiki/index.php?title=Context_Triggered_Piecewise_Hashing";
|
||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
this.outputType = "Number";
|
this.outputType = "Number";
|
||||||
this.args = [
|
this.args = [
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class CompareSSDEEPHashes extends Operation {
|
|||||||
this.name = "Compare SSDEEP hashes";
|
this.name = "Compare SSDEEP hashes";
|
||||||
this.module = "Crypto";
|
this.module = "Crypto";
|
||||||
this.description = "Compares two SSDEEP fuzzy hashes to determine the similarity between them on a scale of 0 to 100.";
|
this.description = "Compares two SSDEEP fuzzy hashes to determine the similarity between them on a scale of 0 to 100.";
|
||||||
this.infoURL = "https://forensicswiki.org/wiki/Ssdeep";
|
this.infoURL = "https://forensicswiki.xyz/wiki/index.php?title=Ssdeep";
|
||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
this.outputType = "Number";
|
this.outputType = "Number";
|
||||||
this.args = [
|
this.args = [
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ import OperationError from "../errors/OperationError.mjs";
|
|||||||
import { isImage } from "../lib/FileType.mjs";
|
import { isImage } from "../lib/FileType.mjs";
|
||||||
import { toBase64 } from "../lib/Base64.mjs";
|
import { toBase64 } from "../lib/Base64.mjs";
|
||||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||||
import jimp from "jimp";
|
import jimplib from "jimp/es/index.js";
|
||||||
|
const jimp = jimplib.default ? jimplib.default : jimplib;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Contain Image operation
|
* Contain Image operation
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ import Operation from "../Operation.mjs";
|
|||||||
import OperationError from "../errors/OperationError.mjs";
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
import { isImage } from "../lib/FileType.mjs";
|
import { isImage } from "../lib/FileType.mjs";
|
||||||
import { toBase64 } from "../lib/Base64.mjs";
|
import { toBase64 } from "../lib/Base64.mjs";
|
||||||
import jimp from "jimp";
|
import jimplib from "jimp/es/index.js";
|
||||||
|
const jimp = jimplib.default ? jimplib.default : jimplib;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert Image Format operation
|
* Convert Image Format operation
|
||||||
@@ -88,7 +89,7 @@ class ConvertImageFormat extends Operation {
|
|||||||
"Sub": jimp.PNG_FILTER_SUB,
|
"Sub": jimp.PNG_FILTER_SUB,
|
||||||
"Up": jimp.PNG_FILTER_UP,
|
"Up": jimp.PNG_FILTER_UP,
|
||||||
"Average": jimp.PNG_FILTER_AVERAGE,
|
"Average": jimp.PNG_FILTER_AVERAGE,
|
||||||
"Paeth": jimp.PNG_FILTER_PATH // Incorrect spelling in Jimp library
|
"Paeth": jimp.PNG_FILTER_PATH
|
||||||
};
|
};
|
||||||
|
|
||||||
const mime = formatMap[format];
|
const mime = formatMap[format];
|
||||||
|
|||||||
82
src/core/operations/ConvertToNATOAlphabet.mjs
Normal file
82
src/core/operations/ConvertToNATOAlphabet.mjs
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
/**
|
||||||
|
* @author MarvinJWendt [git@marvinjwendt.com]
|
||||||
|
* @copyright Crown Copyright 2019
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert to NATO alphabet operation
|
||||||
|
*/
|
||||||
|
class ConvertToNATOAlphabet extends Operation {
|
||||||
|
/**
|
||||||
|
* ConvertToNATOAlphabet constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Convert to NATO alphabet";
|
||||||
|
this.module = "Default";
|
||||||
|
this.description = "Converts characters to their representation in the NATO phonetic alphabet.";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/NATO_phonetic_alphabet";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
return input.replace(/[a-z0-9,/.]/ig, letter => {
|
||||||
|
return lookup[letter.toUpperCase()];
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const lookup = {
|
||||||
|
"A": "Alfa ",
|
||||||
|
"B": "Bravo ",
|
||||||
|
"C": "Charlie ",
|
||||||
|
"D": "Delta ",
|
||||||
|
"E": "Echo ",
|
||||||
|
"F": "Foxtrot ",
|
||||||
|
"G": "Golf ",
|
||||||
|
"H": "Hotel ",
|
||||||
|
"I": "India ",
|
||||||
|
"J": "Juliett ",
|
||||||
|
"K": "Kilo ",
|
||||||
|
"L": "Lima ",
|
||||||
|
"M": "Mike ",
|
||||||
|
"N": "November ",
|
||||||
|
"O": "Oscar ",
|
||||||
|
"P": "Papa ",
|
||||||
|
"Q": "Quebec ",
|
||||||
|
"R": "Romeo ",
|
||||||
|
"S": "Sierra ",
|
||||||
|
"T": "Tango ",
|
||||||
|
"U": "Uniform ",
|
||||||
|
"V": "Victor ",
|
||||||
|
"W": "Whiskey ",
|
||||||
|
"X": "X-ray ",
|
||||||
|
"Y": "Yankee ",
|
||||||
|
"Z": "Zulu ",
|
||||||
|
"0": "Zero ",
|
||||||
|
"1": "One ",
|
||||||
|
"2": "Two ",
|
||||||
|
"3": "Three ",
|
||||||
|
"4": "Four ",
|
||||||
|
"5": "Five ",
|
||||||
|
"6": "Six ",
|
||||||
|
"7": "Seven ",
|
||||||
|
"8": "Eight ",
|
||||||
|
"9": "Nine ",
|
||||||
|
",": "Comma ",
|
||||||
|
"/": "Fraction bar ",
|
||||||
|
".": "Full stop ",
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ConvertToNATOAlphabet;
|
||||||
@@ -9,7 +9,8 @@ import OperationError from "../errors/OperationError.mjs";
|
|||||||
import { isImage } from "../lib/FileType.mjs";
|
import { isImage } from "../lib/FileType.mjs";
|
||||||
import { toBase64 } from "../lib/Base64.mjs";
|
import { toBase64 } from "../lib/Base64.mjs";
|
||||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||||
import jimp from "jimp";
|
import jimplib from "jimp/es/index.js";
|
||||||
|
const jimp = jimplib.default ? jimplib.default : jimplib;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cover Image operation
|
* Cover Image operation
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ import OperationError from "../errors/OperationError.mjs";
|
|||||||
import { isImage } from "../lib/FileType.mjs";
|
import { isImage } from "../lib/FileType.mjs";
|
||||||
import { toBase64 } from "../lib/Base64.mjs";
|
import { toBase64 } from "../lib/Base64.mjs";
|
||||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||||
import jimp from "jimp";
|
import jimplib from "jimp/es/index.js";
|
||||||
|
const jimp = jimplib.default ? jimplib.default : jimplib;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Crop Image operation
|
* Crop Image operation
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
import Operation from "../Operation.mjs";
|
import Operation from "../Operation.mjs";
|
||||||
import Utils from "../Utils.mjs";
|
import Utils from "../Utils.mjs";
|
||||||
import OperationError from "../errors/OperationError.mjs";
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
import forge from "node-forge/dist/forge.min.js";
|
import forge from "node-forge";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DES Decrypt operation
|
* DES Decrypt operation
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
import Operation from "../Operation.mjs";
|
import Operation from "../Operation.mjs";
|
||||||
import Utils from "../Utils.mjs";
|
import Utils from "../Utils.mjs";
|
||||||
import OperationError from "../errors/OperationError.mjs";
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
import forge from "node-forge/dist/forge.min.js";
|
import forge from "node-forge";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DES Encrypt operation
|
* DES Encrypt operation
|
||||||
|
|||||||
@@ -63,9 +63,9 @@ class DNSOverHTTPS extends Operation {
|
|||||||
value: false
|
value: false
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Validate DNSSEC",
|
name: "Disable DNSSEC validation",
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
value: true
|
value: false
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,13 @@ class DechunkHTTPResponse extends Operation {
|
|||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
this.outputType = "string";
|
this.outputType = "string";
|
||||||
this.args = [];
|
this.args = [];
|
||||||
|
this.checks = [
|
||||||
|
{
|
||||||
|
pattern: "^[0-9A-F]+\r\n",
|
||||||
|
flags: "i",
|
||||||
|
args: []
|
||||||
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -30,6 +30,13 @@ class DecodeNetBIOSName extends Operation {
|
|||||||
"value": 65
|
"value": 65
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
this.checks = [
|
||||||
|
{
|
||||||
|
pattern: "^\\s*\\S{32}$",
|
||||||
|
flags: "",
|
||||||
|
args: [65]
|
||||||
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -25,7 +25,17 @@ class DefangIPAddresses extends Operation {
|
|||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
this.outputType = "string";
|
this.outputType = "string";
|
||||||
this.args = [];
|
this.args = [];
|
||||||
|
this.checks = [
|
||||||
|
{
|
||||||
|
pattern: "^\\s*(([0-9]{1,3}\\.){3}[0-9]{1,3}|([0-9a-f]{4}:){7}[0-9a-f]{4})\\s*$",
|
||||||
|
flags: "i",
|
||||||
|
args: [],
|
||||||
|
output: {
|
||||||
|
pattern: "^\\s*(([0-9]{1,3}\\[\\.\\]){3}[0-9]{1,3}|([0-9a-f]{4}\\[\\:\\]){7}[0-9a-f]{4})\\s*$",
|
||||||
|
flags: "i"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
|
|
||||||
import Operation from "../Operation.mjs";
|
import Operation from "../Operation.mjs";
|
||||||
import Utils from "../Utils.mjs";
|
import Utils from "../Utils.mjs";
|
||||||
import forge from "node-forge/dist/forge.min.js";
|
import forge from "node-forge";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Derive PBKDF2 key operation
|
* Derive PBKDF2 key operation
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ import OperationError from "../errors/OperationError.mjs";
|
|||||||
import { isImage } from "../lib/FileType.mjs";
|
import { isImage } from "../lib/FileType.mjs";
|
||||||
import { toBase64 } from "../lib/Base64.mjs";
|
import { toBase64 } from "../lib/Base64.mjs";
|
||||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||||
import jimp from "jimp";
|
import jimplib from "jimp/es/index.js";
|
||||||
|
const jimp = jimplib.default ? jimplib.default : jimplib;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Image Dither operation
|
* Image Dither operation
|
||||||
|
|||||||
@@ -44,22 +44,22 @@ class EscapeUnicodeCharacters extends Operation {
|
|||||||
"value": true
|
"value": true
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
this.patterns = [
|
this.checks = [
|
||||||
{
|
{
|
||||||
match: "\\\\u(?:[\\da-f]{4,6})",
|
pattern: "\\\\u(?:[\\da-f]{4,6})",
|
||||||
flags: "i",
|
flags: "i",
|
||||||
args: ["\\u"]
|
args: ["\\u"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "%u(?:[\\da-f]{4,6})",
|
pattern: "%u(?:[\\da-f]{4,6})",
|
||||||
flags: "i",
|
flags: "i",
|
||||||
args: ["%u"]
|
args: ["%u"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "U\\+(?:[\\da-f]{4,6})",
|
pattern: "U\\+(?:[\\da-f]{4,6})",
|
||||||
flags: "i",
|
flags: "i",
|
||||||
args: ["U+"]
|
args: ["U+"]
|
||||||
},
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ class ExtractDomains extends Operation {
|
|||||||
{
|
{
|
||||||
"name": "Display total",
|
"name": "Display total",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"value": "Extract.DISPLAY_TOTAL"
|
"value": true
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,8 +39,8 @@ class ExtractEmailAddresses extends Operation {
|
|||||||
*/
|
*/
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
const displayTotal = args[0],
|
const displayTotal = args[0],
|
||||||
// email regex from: https://www.regextester.com/98066
|
// email regex from: https://www.regextester.com/98066
|
||||||
regex = /(?:[\u00A0-\uD7FF\uE000-\uFFFF-a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[\u00A0-\uD7FF\uE000-\uFFFF-a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[\u00A0-\uD7FF\uE000-\uFFFF-a-z0-9](?:[\u00A0-\uD7FF\uE000-\uFFFF-a-z0-9-]*[\u00A0-\uD7FF\uE000-\uFFFF-a-z0-9])?\.)+[\u00A0-\uD7FF\uE000-\uFFFF-a-z0-9](?:[\u00A0-\uD7FF\uE000-\uFFFF-a-z0-9-]*[\u00A0-\uD7FF\uE000-\uFFFF-a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\])/ig;
|
regex = /(?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9](?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9-]*[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9])?\.)+[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9](?:[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9-]*[\u00A0-\uD7FF\uE000-\uFFFFa-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}\])/ig;
|
||||||
return search(input, regex, null, displayTotal);
|
return search(input, regex, null, displayTotal);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class ExtractFiles extends Operation {
|
|||||||
this.name = "Extract Files";
|
this.name = "Extract Files";
|
||||||
this.module = "Default";
|
this.module = "Default";
|
||||||
this.description = "Performs file carving to attempt to extract files from the input.<br><br>This operation is currently capable of carving out the following formats:<ul><li>JPG</li><li>EXE</li><li>ZIP</li><li>PDF</li><li>PNG</li><li>BMP</li><li>FLV</li><li>RTF</li><li>DOCX, PPTX, XLSX</li><li>EPUB</li><li>GZIP</li><li>ZLIB</li><li>ELF, BIN, AXF, O, PRX, SO</li></ul>";
|
this.description = "Performs file carving to attempt to extract files from the input.<br><br>This operation is currently capable of carving out the following formats:<ul><li>JPG</li><li>EXE</li><li>ZIP</li><li>PDF</li><li>PNG</li><li>BMP</li><li>FLV</li><li>RTF</li><li>DOCX, PPTX, XLSX</li><li>EPUB</li><li>GZIP</li><li>ZLIB</li><li>ELF, BIN, AXF, O, PRX, SO</li></ul>";
|
||||||
this.infoURL = "https://forensicswiki.org/wiki/File_Carving";
|
this.infoURL = "https://forensicswiki.xyz/wiki/index.php?title=File_Carving";
|
||||||
this.inputType = "ArrayBuffer";
|
this.inputType = "ArrayBuffer";
|
||||||
this.outputType = "List<File>";
|
this.outputType = "List<File>";
|
||||||
this.presentType = "html";
|
this.presentType = "html";
|
||||||
@@ -38,7 +38,7 @@ class ExtractFiles extends Operation {
|
|||||||
{
|
{
|
||||||
name: "Ignore failed extractions",
|
name: "Ignore failed extractions",
|
||||||
type: "boolean",
|
type: "boolean",
|
||||||
value: "true"
|
value: true
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|||||||
324
src/core/operations/ExtractID3.mjs
Normal file
324
src/core/operations/ExtractID3.mjs
Normal file
@@ -0,0 +1,324 @@
|
|||||||
|
/**
|
||||||
|
* @author n1073645 [n1073645@gmail.com]
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2020
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
import Utils from "../Utils.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extract ID3 operation
|
||||||
|
*/
|
||||||
|
class ExtractID3 extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ExtractID3 constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Extract ID3";
|
||||||
|
this.module = "Default";
|
||||||
|
this.description = "This operation extracts ID3 metadata from an MP3 file.<br><br>ID3 is a metadata container most often used in conjunction with the MP3 audio file format. It allows information such as the title, artist, album, track number, and other information about the file to be stored in the file itself.";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/ID3";
|
||||||
|
this.inputType = "ArrayBuffer";
|
||||||
|
this.outputType = "JSON";
|
||||||
|
this.presentType = "html";
|
||||||
|
this.args = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {ArrayBuffer} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {JSON}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
input = new Uint8Array(input);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extracts the ID3 header fields.
|
||||||
|
*/
|
||||||
|
function extractHeader() {
|
||||||
|
if (!Array.from(input.slice(0, 3)).equals([0x49, 0x44, 0x33]))
|
||||||
|
throw new OperationError("No valid ID3 header.");
|
||||||
|
|
||||||
|
const header = {
|
||||||
|
"Type": "ID3",
|
||||||
|
// Tag version
|
||||||
|
"Version": input[3].toString() + "." + input[4].toString(),
|
||||||
|
// Header version
|
||||||
|
"Flags": input[5].toString()
|
||||||
|
};
|
||||||
|
|
||||||
|
input = input.slice(6);
|
||||||
|
return header;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts the size fields to a single integer.
|
||||||
|
*
|
||||||
|
* @param {number} num
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function readSize(num) {
|
||||||
|
let result = 0;
|
||||||
|
|
||||||
|
// The sizes are 7 bit numbers stored in 8 bit locations
|
||||||
|
for (let i = (num) * 7; i; i -= 7) {
|
||||||
|
result = (result << i) | input[0];
|
||||||
|
input = input.slice(1);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads frame header based on ID.
|
||||||
|
*
|
||||||
|
* @param {string} id
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
function readFrame(id) {
|
||||||
|
const frame = {};
|
||||||
|
|
||||||
|
// Size of frame
|
||||||
|
const size = readSize(4);
|
||||||
|
frame.Size = size.toString();
|
||||||
|
frame.Description = FRAME_DESCRIPTIONS[id];
|
||||||
|
input = input.slice(2);
|
||||||
|
|
||||||
|
// Read data from frame
|
||||||
|
let data = "";
|
||||||
|
for (let i = 1; i < size; i++)
|
||||||
|
data += String.fromCharCode(input[i]);
|
||||||
|
frame.Data = data;
|
||||||
|
|
||||||
|
// Move to next Frame
|
||||||
|
input = input.slice(size);
|
||||||
|
|
||||||
|
return [frame, size];
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = extractHeader();
|
||||||
|
|
||||||
|
const headerTagSize = readSize(4);
|
||||||
|
result.Size = headerTagSize.toString();
|
||||||
|
|
||||||
|
const tags = {};
|
||||||
|
let pos = 10;
|
||||||
|
|
||||||
|
// While the current element is in the header
|
||||||
|
while (pos < headerTagSize) {
|
||||||
|
|
||||||
|
// Frame Identifier of frame
|
||||||
|
let id = String.fromCharCode(input[0]) + String.fromCharCode(input[1]) + String.fromCharCode(input[2]);
|
||||||
|
input = input.slice(3);
|
||||||
|
|
||||||
|
// If the next character is non-zero it is an identifier
|
||||||
|
if (input[0] !== 0) {
|
||||||
|
id += String.fromCharCode(input[0]);
|
||||||
|
}
|
||||||
|
input = input.slice(1);
|
||||||
|
|
||||||
|
if (id in FRAME_DESCRIPTIONS) {
|
||||||
|
const [frame, size] = readFrame(id);
|
||||||
|
tags[id] = frame;
|
||||||
|
pos += 10 + size;
|
||||||
|
} else if (id === "\x00\x00\x00") { // end of header
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
throw new OperationError("Unknown Frame Identifier: " + id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.Tags = tags;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays the extracted data in a more accessible format for web apps.
|
||||||
|
* @param {JSON} data
|
||||||
|
* @returns {html}
|
||||||
|
*/
|
||||||
|
present(data) {
|
||||||
|
if (!data || !Object.prototype.hasOwnProperty.call(data, "Tags"))
|
||||||
|
return JSON.stringify(data, null, 4);
|
||||||
|
|
||||||
|
let output = `<table class="table table-hover table-sm table-bordered table-nonfluid">
|
||||||
|
<tr><th>Tag</th><th>Description</th><th>Data</th></tr>`;
|
||||||
|
|
||||||
|
for (const tagID in data.Tags) {
|
||||||
|
const description = data.Tags[tagID].Description,
|
||||||
|
contents = data.Tags[tagID].Data;
|
||||||
|
output += `<tr><td>${tagID}</td><td>${Utils.escapeHtml(description)}</td><td>${Utils.escapeHtml(contents)}</td></tr>`;
|
||||||
|
}
|
||||||
|
output += "</table>";
|
||||||
|
return output;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Borrowed from https://github.com/aadsm/jsmediatags
|
||||||
|
const FRAME_DESCRIPTIONS = {
|
||||||
|
// v2.2
|
||||||
|
"BUF": "Recommended buffer size",
|
||||||
|
"CNT": "Play counter",
|
||||||
|
"COM": "Comments",
|
||||||
|
"CRA": "Audio encryption",
|
||||||
|
"CRM": "Encrypted meta frame",
|
||||||
|
"ETC": "Event timing codes",
|
||||||
|
"EQU": "Equalization",
|
||||||
|
"GEO": "General encapsulated object",
|
||||||
|
"IPL": "Involved people list",
|
||||||
|
"LNK": "Linked information",
|
||||||
|
"MCI": "Music CD Identifier",
|
||||||
|
"MLL": "MPEG location lookup table",
|
||||||
|
"PIC": "Attached picture",
|
||||||
|
"POP": "Popularimeter",
|
||||||
|
"REV": "Reverb",
|
||||||
|
"RVA": "Relative volume adjustment",
|
||||||
|
"SLT": "Synchronized lyric/text",
|
||||||
|
"STC": "Synced tempo codes",
|
||||||
|
"TAL": "Album/Movie/Show title",
|
||||||
|
"TBP": "BPM (Beats Per Minute)",
|
||||||
|
"TCM": "Composer",
|
||||||
|
"TCO": "Content type",
|
||||||
|
"TCR": "Copyright message",
|
||||||
|
"TDA": "Date",
|
||||||
|
"TDY": "Playlist delay",
|
||||||
|
"TEN": "Encoded by",
|
||||||
|
"TFT": "File type",
|
||||||
|
"TIM": "Time",
|
||||||
|
"TKE": "Initial key",
|
||||||
|
"TLA": "Language(s)",
|
||||||
|
"TLE": "Length",
|
||||||
|
"TMT": "Media type",
|
||||||
|
"TOA": "Original artist(s)/performer(s)",
|
||||||
|
"TOF": "Original filename",
|
||||||
|
"TOL": "Original Lyricist(s)/text writer(s)",
|
||||||
|
"TOR": "Original release year",
|
||||||
|
"TOT": "Original album/Movie/Show title",
|
||||||
|
"TP1": "Lead artist(s)/Lead performer(s)/Soloist(s)/Performing group",
|
||||||
|
"TP2": "Band/Orchestra/Accompaniment",
|
||||||
|
"TP3": "Conductor/Performer refinement",
|
||||||
|
"TP4": "Interpreted, remixed, or otherwise modified by",
|
||||||
|
"TPA": "Part of a set",
|
||||||
|
"TPB": "Publisher",
|
||||||
|
"TRC": "ISRC (International Standard Recording Code)",
|
||||||
|
"TRD": "Recording dates",
|
||||||
|
"TRK": "Track number/Position in set",
|
||||||
|
"TSI": "Size",
|
||||||
|
"TSS": "Software/hardware and settings used for encoding",
|
||||||
|
"TT1": "Content group description",
|
||||||
|
"TT2": "Title/Songname/Content description",
|
||||||
|
"TT3": "Subtitle/Description refinement",
|
||||||
|
"TXT": "Lyricist/text writer",
|
||||||
|
"TXX": "User defined text information frame",
|
||||||
|
"TYE": "Year",
|
||||||
|
"UFI": "Unique file identifier",
|
||||||
|
"ULT": "Unsychronized lyric/text transcription",
|
||||||
|
"WAF": "Official audio file webpage",
|
||||||
|
"WAR": "Official artist/performer webpage",
|
||||||
|
"WAS": "Official audio source webpage",
|
||||||
|
"WCM": "Commercial information",
|
||||||
|
"WCP": "Copyright/Legal information",
|
||||||
|
"WPB": "Publishers official webpage",
|
||||||
|
"WXX": "User defined URL link frame",
|
||||||
|
// v2.3
|
||||||
|
"AENC": "Audio encryption",
|
||||||
|
"APIC": "Attached picture",
|
||||||
|
"ASPI": "Audio seek point index",
|
||||||
|
"CHAP": "Chapter",
|
||||||
|
"CTOC": "Table of contents",
|
||||||
|
"COMM": "Comments",
|
||||||
|
"COMR": "Commercial frame",
|
||||||
|
"ENCR": "Encryption method registration",
|
||||||
|
"EQU2": "Equalisation (2)",
|
||||||
|
"EQUA": "Equalization",
|
||||||
|
"ETCO": "Event timing codes",
|
||||||
|
"GEOB": "General encapsulated object",
|
||||||
|
"GRID": "Group identification registration",
|
||||||
|
"IPLS": "Involved people list",
|
||||||
|
"LINK": "Linked information",
|
||||||
|
"MCDI": "Music CD identifier",
|
||||||
|
"MLLT": "MPEG location lookup table",
|
||||||
|
"OWNE": "Ownership frame",
|
||||||
|
"PRIV": "Private frame",
|
||||||
|
"PCNT": "Play counter",
|
||||||
|
"POPM": "Popularimeter",
|
||||||
|
"POSS": "Position synchronisation frame",
|
||||||
|
"RBUF": "Recommended buffer size",
|
||||||
|
"RVA2": "Relative volume adjustment (2)",
|
||||||
|
"RVAD": "Relative volume adjustment",
|
||||||
|
"RVRB": "Reverb",
|
||||||
|
"SEEK": "Seek frame",
|
||||||
|
"SYLT": "Synchronized lyric/text",
|
||||||
|
"SYTC": "Synchronized tempo codes",
|
||||||
|
"TALB": "Album/Movie/Show title",
|
||||||
|
"TBPM": "BPM (beats per minute)",
|
||||||
|
"TCOM": "Composer",
|
||||||
|
"TCON": "Content type",
|
||||||
|
"TCOP": "Copyright message",
|
||||||
|
"TDAT": "Date",
|
||||||
|
"TDLY": "Playlist delay",
|
||||||
|
"TDRC": "Recording time",
|
||||||
|
"TDRL": "Release time",
|
||||||
|
"TDTG": "Tagging time",
|
||||||
|
"TENC": "Encoded by",
|
||||||
|
"TEXT": "Lyricist/Text writer",
|
||||||
|
"TFLT": "File type",
|
||||||
|
"TIME": "Time",
|
||||||
|
"TIPL": "Involved people list",
|
||||||
|
"TIT1": "Content group description",
|
||||||
|
"TIT2": "Title/songname/content description",
|
||||||
|
"TIT3": "Subtitle/Description refinement",
|
||||||
|
"TKEY": "Initial key",
|
||||||
|
"TLAN": "Language(s)",
|
||||||
|
"TLEN": "Length",
|
||||||
|
"TMCL": "Musician credits list",
|
||||||
|
"TMED": "Media type",
|
||||||
|
"TMOO": "Mood",
|
||||||
|
"TOAL": "Original album/movie/show title",
|
||||||
|
"TOFN": "Original filename",
|
||||||
|
"TOLY": "Original lyricist(s)/text writer(s)",
|
||||||
|
"TOPE": "Original artist(s)/performer(s)",
|
||||||
|
"TORY": "Original release year",
|
||||||
|
"TOWN": "File owner/licensee",
|
||||||
|
"TPE1": "Lead performer(s)/Soloist(s)",
|
||||||
|
"TPE2": "Band/orchestra/accompaniment",
|
||||||
|
"TPE3": "Conductor/performer refinement",
|
||||||
|
"TPE4": "Interpreted, remixed, or otherwise modified by",
|
||||||
|
"TPOS": "Part of a set",
|
||||||
|
"TPRO": "Produced notice",
|
||||||
|
"TPUB": "Publisher",
|
||||||
|
"TRCK": "Track number/Position in set",
|
||||||
|
"TRDA": "Recording dates",
|
||||||
|
"TRSN": "Internet radio station name",
|
||||||
|
"TRSO": "Internet radio station owner",
|
||||||
|
"TSOA": "Album sort order",
|
||||||
|
"TSOP": "Performer sort order",
|
||||||
|
"TSOT": "Title sort order",
|
||||||
|
"TSIZ": "Size",
|
||||||
|
"TSRC": "ISRC (international standard recording code)",
|
||||||
|
"TSSE": "Software/Hardware and settings used for encoding",
|
||||||
|
"TSST": "Set subtitle",
|
||||||
|
"TYER": "Year",
|
||||||
|
"TXXX": "User defined text information frame",
|
||||||
|
"UFID": "Unique file identifier",
|
||||||
|
"USER": "Terms of use",
|
||||||
|
"USLT": "Unsychronized lyric/text transcription",
|
||||||
|
"WCOM": "Commercial information",
|
||||||
|
"WCOP": "Copyright/Legal information",
|
||||||
|
"WOAF": "Official audio file webpage",
|
||||||
|
"WOAR": "Official artist/performer webpage",
|
||||||
|
"WOAS": "Official audio source webpage",
|
||||||
|
"WORS": "Official internet radio station homepage",
|
||||||
|
"WPAY": "Payment",
|
||||||
|
"WPUB": "Publishers official webpage",
|
||||||
|
"WXXX": "User defined URL link frame"
|
||||||
|
};
|
||||||
|
|
||||||
|
export default ExtractID3;
|
||||||
@@ -9,7 +9,8 @@ import OperationError from "../errors/OperationError.mjs";
|
|||||||
import Utils from "../Utils.mjs";
|
import Utils from "../Utils.mjs";
|
||||||
import { fromBinary } from "../lib/Binary.mjs";
|
import { fromBinary } from "../lib/Binary.mjs";
|
||||||
import { isImage } from "../lib/FileType.mjs";
|
import { isImage } from "../lib/FileType.mjs";
|
||||||
import jimp from "jimp";
|
import jimplib from "jimp/es/index.js";
|
||||||
|
const jimp = jimplib.default ? jimplib.default : jimplib;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extract LSB operation
|
* Extract LSB operation
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
import Operation from "../Operation.mjs";
|
import Operation from "../Operation.mjs";
|
||||||
import OperationError from "../errors/OperationError.mjs";
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
import { isImage } from "../lib/FileType.mjs";
|
import { isImage } from "../lib/FileType.mjs";
|
||||||
import jimp from "jimp";
|
import jimplib from "jimp/es/index.js";
|
||||||
|
const jimp = jimplib.default ? jimplib.default : jimplib;
|
||||||
|
|
||||||
import {RGBA_DELIM_OPTIONS} from "../lib/Delim.mjs";
|
import {RGBA_DELIM_OPTIONS} from "../lib/Delim.mjs";
|
||||||
|
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ import OperationError from "../errors/OperationError.mjs";
|
|||||||
import { isImage } from "../lib/FileType.mjs";
|
import { isImage } from "../lib/FileType.mjs";
|
||||||
import { toBase64 } from "../lib/Base64.mjs";
|
import { toBase64 } from "../lib/Base64.mjs";
|
||||||
import { isWorkerEnvironment } from "../Utils.mjs";
|
import { isWorkerEnvironment } from "../Utils.mjs";
|
||||||
import jimp from "jimp";
|
import jimplib from "jimp/es/index.js";
|
||||||
|
const jimp = jimplib.default ? jimplib.default : jimplib;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flip Image operation
|
* Flip Image operation
|
||||||
|
|||||||
@@ -30,7 +30,12 @@ class FrequencyDistribution extends Operation {
|
|||||||
{
|
{
|
||||||
"name": "Show 0%s",
|
"name": "Show 0%s",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"value": "Entropy.FREQ_ZEROS"
|
"value": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Show ASCII",
|
||||||
|
"type": "boolean",
|
||||||
|
"value": true
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -76,14 +81,14 @@ class FrequencyDistribution extends Operation {
|
|||||||
* @returns {html}
|
* @returns {html}
|
||||||
*/
|
*/
|
||||||
present(freq, args) {
|
present(freq, args) {
|
||||||
const showZeroes = args[0];
|
const [showZeroes, showAscii] = args;
|
||||||
|
|
||||||
// Print
|
// Print
|
||||||
let output = `<canvas id='chart-area'></canvas><br>
|
let output = `<canvas id='chart-area'></canvas><br>
|
||||||
Total data length: ${freq.dataLength}
|
Total data length: ${freq.dataLength}
|
||||||
Number of bytes represented: ${freq.bytesRepresented}
|
Number of bytes represented: ${freq.bytesRepresented}
|
||||||
Number of bytes not represented: ${256 - freq.bytesRepresented}
|
Number of bytes not represented: ${256 - freq.bytesRepresented}
|
||||||
|
|
||||||
Byte Percentage
|
|
||||||
<script>
|
<script>
|
||||||
var canvas = document.getElementById("chart-area"),
|
var canvas = document.getElementById("chart-area"),
|
||||||
parentRect = canvas.parentNode.getBoundingClientRect(),
|
parentRect = canvas.parentNode.getBoundingClientRect(),
|
||||||
@@ -93,16 +98,32 @@ Byte Percentage
|
|||||||
canvas.height = parentRect.height * 0.9;
|
canvas.height = parentRect.height * 0.9;
|
||||||
|
|
||||||
CanvasComponents.drawBarChart(canvas, scores, "Byte", "Frequency %", 16, 6);
|
CanvasComponents.drawBarChart(canvas, scores, "Byte", "Frequency %", 16, 6);
|
||||||
</script>`;
|
</script>
|
||||||
|
<table class="table table-hover table-sm">
|
||||||
|
<tr><th>Byte</th>${showAscii ? "<th>ASCII</th>" : ""}<th>Percentage</th><th></th></tr>`;
|
||||||
|
|
||||||
for (let i = 0; i < 256; i++) {
|
for (let i = 0; i < 256; i++) {
|
||||||
if (freq.distribution[i] || showZeroes) {
|
if (freq.distribution[i] || showZeroes) {
|
||||||
output += " " + Utils.hex(i, 2) + " (" +
|
let c = "";
|
||||||
(freq.percentages[i].toFixed(2).replace(".00", "") + "%)").padEnd(8, " ") +
|
if (showAscii) {
|
||||||
Array(Math.ceil(freq.percentages[i])+1).join("|") + "\n";
|
if (i <= 32) {
|
||||||
|
c = String.fromCharCode(0x2400 + i);
|
||||||
|
} else if (i === 127) {
|
||||||
|
c = String.fromCharCode(0x2421);
|
||||||
|
} else {
|
||||||
|
c = String.fromCharCode(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const bite = `<td>${Utils.hex(i, 2)}</td>`,
|
||||||
|
ascii = showAscii ? `<td>${c}</td>` : "",
|
||||||
|
percentage = `<td>${(freq.percentages[i].toFixed(2).replace(".00", "") + "%").padEnd(8, " ")}</td>`,
|
||||||
|
bars = `<td>${Array(Math.ceil(freq.percentages[i])+1).join("|")}</td>`;
|
||||||
|
|
||||||
|
output += `<tr>${bite}${ascii}${percentage}${bars}</tr>`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
output += "</table>";
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -49,9 +49,9 @@ class FromBCD extends Operation {
|
|||||||
"value": FORMAT
|
"value": FORMAT
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
this.patterns = [
|
this.checks = [
|
||||||
{
|
{
|
||||||
match: "^(?:\\d{4} ){3,}\\d{4}$",
|
pattern: "^(?:\\d{4} ){3,}\\d{4}$",
|
||||||
flags: "",
|
flags: "",
|
||||||
args: ["8 4 2 1", true, false, "Nibbles"]
|
args: ["8 4 2 1", true, false, "Nibbles"]
|
||||||
},
|
},
|
||||||
@@ -95,7 +95,7 @@ class FromBCD extends Operation {
|
|||||||
if (!packed) {
|
if (!packed) {
|
||||||
// Discard each high nibble
|
// Discard each high nibble
|
||||||
for (let i = 0; i < nibbles.length; i++) {
|
for (let i = 0; i < nibbles.length; i++) {
|
||||||
nibbles.splice(i, 1);
|
nibbles.splice(i, 1); // lgtm [js/loop-iteration-skipped-due-to-shifting]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ class FromBase extends Operation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const number = input.replace(/\s/g, "").split(".");
|
const number = input.replace(/\s/g, "").split(".");
|
||||||
let result = new BigNumber(number[0], radix) || 0;
|
let result = new BigNumber(number[0], radix);
|
||||||
|
|
||||||
if (number.length === 1) return result;
|
if (number.length === 1) return result;
|
||||||
|
|
||||||
|
|||||||
@@ -36,12 +36,12 @@ class FromBase32 extends Operation {
|
|||||||
value: true
|
value: true
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
this.patterns = [
|
this.checks = [
|
||||||
{
|
{
|
||||||
match: "^(?:[A-Z2-7]{8})+(?:[A-Z2-7]{2}={6}|[A-Z2-7]{4}={4}|[A-Z2-7]{5}={3}|[A-Z2-7]{7}={1})?$",
|
pattern: "^(?:[A-Z2-7]{8})+(?:[A-Z2-7]{2}={6}|[A-Z2-7]{4}={4}|[A-Z2-7]{5}={3}|[A-Z2-7]{7}={1})?$",
|
||||||
flags: "",
|
flags: "",
|
||||||
args: ["A-Z2-7=", false]
|
args: ["A-Z2-7=", false]
|
||||||
},
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -84,10 +84,10 @@ class FromBase32 extends Operation {
|
|||||||
chr5 = ((enc7 & 7) << 5) | enc8;
|
chr5 = ((enc7 & 7) << 5) | enc8;
|
||||||
|
|
||||||
output.push(chr1);
|
output.push(chr1);
|
||||||
if (enc2 & 3 !== 0 || enc3 !== 32) output.push(chr2);
|
if ((enc2 & 3) !== 0 || enc3 !== 32) output.push(chr2);
|
||||||
if (enc4 & 15 !== 0 || enc5 !== 32) output.push(chr3);
|
if ((enc4 & 15) !== 0 || enc5 !== 32) output.push(chr3);
|
||||||
if (enc5 & 1 !== 0 || enc6 !== 32) output.push(chr4);
|
if ((enc5 & 1) !== 0 || enc6 !== 32) output.push(chr4);
|
||||||
if (enc7 & 7 !== 0 || enc8 !== 32) output.push(chr5);
|
if ((enc7 & 7) !== 0 || enc8 !== 32) output.push(chr5);
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
|
|||||||
@@ -38,14 +38,14 @@ class FromBase58 extends Operation {
|
|||||||
"value": true
|
"value": true
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
this.patterns = [
|
this.checks = [
|
||||||
{
|
{
|
||||||
match: "^[1-9A-HJ-NP-Za-km-z]{20,}$",
|
pattern: "^[1-9A-HJ-NP-Za-km-z]{20,}$",
|
||||||
flags: "",
|
flags: "",
|
||||||
args: ["123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz", false]
|
args: ["123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz", false]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^[1-9A-HJ-NP-Za-km-z]{20,}$",
|
pattern: "^[1-9A-HJ-NP-Za-km-z]{20,}$",
|
||||||
flags: "",
|
flags: "",
|
||||||
args: ["rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz", false]
|
args: ["rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz", false]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -42,15 +42,22 @@ class FromBase62 extends Operation {
|
|||||||
*/
|
*/
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
if (input.length < 1) return [];
|
if (input.length < 1) return [];
|
||||||
const ALPHABET = Utils.expandAlphRange(args[0]).join("");
|
const alphabet = Utils.expandAlphRange(args[0]).join("");
|
||||||
const BN = BigNumber.clone({ ALPHABET });
|
const BN62 = BigNumber.clone({ ALPHABET: alphabet });
|
||||||
|
|
||||||
const re = new RegExp("[^" + ALPHABET.replace(/[[\]\\\-^$]/g, "\\$&") + "]", "g");
|
const re = new RegExp("[^" + alphabet.replace(/[[\]\\\-^$]/g, "\\$&") + "]", "g");
|
||||||
input = input.replace(re, "");
|
input = input.replace(re, "");
|
||||||
|
|
||||||
const number = new BN(input, 62);
|
// Read number in using Base62 alphabet
|
||||||
|
const number = new BN62(input, 62);
|
||||||
|
// Copy to new BigNumber object that uses the default alphabet
|
||||||
|
const normalized = new BigNumber(number);
|
||||||
|
|
||||||
return Utils.convertToByteArray(number.toString(16), "Hex");
|
// Convert to hex and add leading 0 if required
|
||||||
|
let hex = normalized.toString(16);
|
||||||
|
if (hex.length % 2 !== 0) hex = "0" + hex;
|
||||||
|
|
||||||
|
return Utils.convertToByteArray(hex, "Hex");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,69 +36,69 @@ class FromBase64 extends Operation {
|
|||||||
value: true
|
value: true
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
this.patterns = [
|
this.checks = [
|
||||||
{
|
{
|
||||||
match: "^\\s*(?:[A-Z\\d+/]{4})+(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
|
pattern: "^\\s*(?:[A-Z\\d+/]{4})+(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
|
||||||
flags: "i",
|
flags: "i",
|
||||||
args: ["A-Za-z0-9+/=", true]
|
args: ["A-Za-z0-9+/=", true]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^\\s*[A-Z\\d\\-_]{20,}\\s*$",
|
pattern: "^\\s*[A-Z\\d\\-_]{20,}\\s*$",
|
||||||
flags: "i",
|
flags: "i",
|
||||||
args: ["A-Za-z0-9-_", true]
|
args: ["A-Za-z0-9-_", true]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^\\s*(?:[A-Z\\d+\\-]{4}){5,}(?:[A-Z\\d+\\-]{2}==|[A-Z\\d+\\-]{3}=)?\\s*$",
|
pattern: "^\\s*(?:[A-Z\\d+\\-]{4}){5,}(?:[A-Z\\d+\\-]{2}==|[A-Z\\d+\\-]{3}=)?\\s*$",
|
||||||
flags: "i",
|
flags: "i",
|
||||||
args: ["A-Za-z0-9+\\-=", true]
|
args: ["A-Za-z0-9+\\-=", true]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^\\s*(?:[A-Z\\d./]{4}){5,}(?:[A-Z\\d./]{2}==|[A-Z\\d./]{3}=)?\\s*$",
|
pattern: "^\\s*(?:[A-Z\\d./]{4}){5,}(?:[A-Z\\d./]{2}==|[A-Z\\d./]{3}=)?\\s*$",
|
||||||
flags: "i",
|
flags: "i",
|
||||||
args: ["./0-9A-Za-z=", true]
|
args: ["./0-9A-Za-z=", true]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^\\s*[A-Z\\d_.]{20,}\\s*$",
|
pattern: "^\\s*[A-Z\\d_.]{20,}\\s*$",
|
||||||
flags: "i",
|
flags: "i",
|
||||||
args: ["A-Za-z0-9_.", true]
|
args: ["A-Za-z0-9_.", true]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^\\s*(?:[A-Z\\d._]{4}){5,}(?:[A-Z\\d._]{2}--|[A-Z\\d._]{3}-)?\\s*$",
|
pattern: "^\\s*(?:[A-Z\\d._]{4}){5,}(?:[A-Z\\d._]{2}--|[A-Z\\d._]{3}-)?\\s*$",
|
||||||
flags: "i",
|
flags: "i",
|
||||||
args: ["A-Za-z0-9._-", true]
|
args: ["A-Za-z0-9._-", true]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^\\s*(?:[A-Z\\d+/]{4}){5,}(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
|
pattern: "^\\s*(?:[A-Z\\d+/]{4}){5,}(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
|
||||||
flags: "i",
|
flags: "i",
|
||||||
args: ["0-9a-zA-Z+/=", true]
|
args: ["0-9a-zA-Z+/=", true]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^\\s*(?:[A-Z\\d+/]{4}){5,}(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
|
pattern: "^\\s*(?:[A-Z\\d+/]{4}){5,}(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
|
||||||
flags: "i",
|
flags: "i",
|
||||||
args: ["0-9A-Za-z+/=", true]
|
args: ["0-9A-Za-z+/=", true]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^[ !\"#$%&'()*+,\\-./\\d:;<=>?@A-Z[\\\\\\]^_]{20,}$",
|
pattern: "^[ !\"#$%&'()*+,\\-./\\d:;<=>?@A-Z[\\\\\\]^_]{20,}$",
|
||||||
flags: "",
|
flags: "",
|
||||||
args: [" -_", false]
|
args: [" -_", false]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^\\s*[A-Z\\d+\\-]{20,}\\s*$",
|
pattern: "^\\s*[A-Z\\d+\\-]{20,}\\s*$",
|
||||||
flags: "i",
|
flags: "i",
|
||||||
args: ["+\\-0-9A-Za-z", true]
|
args: ["+\\-0-9A-Za-z", true]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^\\s*[!\"#$%&'()*+,\\-0-689@A-NP-VX-Z[`a-fh-mp-r]{20,}\\s*$",
|
pattern: "^\\s*[!\"#$%&'()*+,\\-0-689@A-NP-VX-Z[`a-fh-mp-r]{20,}\\s*$",
|
||||||
flags: "",
|
flags: "",
|
||||||
args: ["!-,-0-689@A-NP-VX-Z[`a-fh-mp-r", true]
|
args: ["!-,-0-689@A-NP-VX-Z[`a-fh-mp-r", true]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^\\s*(?:[N-ZA-M\\d+/]{4}){5,}(?:[N-ZA-M\\d+/]{2}==|[N-ZA-M\\d+/]{3}=)?\\s*$",
|
pattern: "^\\s*(?:[N-ZA-M\\d+/]{4}){5,}(?:[N-ZA-M\\d+/]{2}==|[N-ZA-M\\d+/]{3}=)?\\s*$",
|
||||||
flags: "i",
|
flags: "i",
|
||||||
args: ["N-ZA-Mn-za-m0-9+/=", true]
|
args: ["N-ZA-Mn-za-m0-9+/=", true]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^\\s*[A-Z\\d./]{20,}\\s*$",
|
pattern: "^\\s*[A-Z\\d./]{20,}\\s*$",
|
||||||
flags: "i",
|
flags: "i",
|
||||||
args: ["./0-9A-Za-z", true]
|
args: ["./0-9A-Za-z", true]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -31,41 +31,46 @@ class FromBinary extends Operation {
|
|||||||
"name": "Delimiter",
|
"name": "Delimiter",
|
||||||
"type": "option",
|
"type": "option",
|
||||||
"value": BIN_DELIM_OPTIONS
|
"value": BIN_DELIM_OPTIONS
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Byte Length",
|
||||||
|
"type": "number",
|
||||||
|
"value": 8
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
this.patterns = [
|
this.checks = [
|
||||||
{
|
{
|
||||||
match: "^(?:[01]{8})+$",
|
pattern: "^(?:[01]{8})+$",
|
||||||
flags: "",
|
flags: "",
|
||||||
args: ["None"]
|
args: ["None"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^(?:[01]{8})(?: [01]{8})*$",
|
pattern: "^(?:[01]{8})(?: [01]{8})*$",
|
||||||
flags: "",
|
flags: "",
|
||||||
args: ["Space"]
|
args: ["Space"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^(?:[01]{8})(?:,[01]{8})*$",
|
pattern: "^(?:[01]{8})(?:,[01]{8})*$",
|
||||||
flags: "",
|
flags: "",
|
||||||
args: ["Comma"]
|
args: ["Comma"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^(?:[01]{8})(?:;[01]{8})*$",
|
pattern: "^(?:[01]{8})(?:;[01]{8})*$",
|
||||||
flags: "",
|
flags: "",
|
||||||
args: ["Semi-colon"]
|
args: ["Semi-colon"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^(?:[01]{8})(?::[01]{8})*$",
|
pattern: "^(?:[01]{8})(?::[01]{8})*$",
|
||||||
flags: "",
|
flags: "",
|
||||||
args: ["Colon"]
|
args: ["Colon"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^(?:[01]{8})(?:\\n[01]{8})*$",
|
pattern: "^(?:[01]{8})(?:\\n[01]{8})*$",
|
||||||
flags: "",
|
flags: "",
|
||||||
args: ["Line feed"]
|
args: ["Line feed"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^(?:[01]{8})(?:\\r\\n[01]{8})*$",
|
pattern: "^(?:[01]{8})(?:\\r\\n[01]{8})*$",
|
||||||
flags: "",
|
flags: "",
|
||||||
args: ["CRLF"]
|
args: ["CRLF"]
|
||||||
},
|
},
|
||||||
@@ -78,7 +83,8 @@ class FromBinary extends Operation {
|
|||||||
* @returns {byteArray}
|
* @returns {byteArray}
|
||||||
*/
|
*/
|
||||||
run(input, args) {
|
run(input, args) {
|
||||||
return fromBinary(input, args[0]);
|
const byteLen = args[1] ? args[1] : 8;
|
||||||
|
return fromBinary(input, args[0], byteLen);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -36,37 +36,37 @@ class FromDecimal extends Operation {
|
|||||||
"value": false
|
"value": false
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
this.patterns = [
|
this.checks = [
|
||||||
{
|
{
|
||||||
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?: (?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
pattern: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?: (?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
||||||
flags: "",
|
flags: "",
|
||||||
args: ["Space", false]
|
args: ["Space", false]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:,(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
pattern: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:,(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
||||||
flags: "",
|
flags: "",
|
||||||
args: ["Comma", false]
|
args: ["Comma", false]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:;(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
pattern: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:;(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
||||||
flags: "",
|
flags: "",
|
||||||
args: ["Semi-colon", false]
|
args: ["Semi-colon", false]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?::(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
pattern: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?::(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
||||||
flags: "",
|
flags: "",
|
||||||
args: ["Colon", false]
|
args: ["Colon", false]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:\\n(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
pattern: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:\\n(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
||||||
flags: "",
|
flags: "",
|
||||||
args: ["Line feed", false]
|
args: ["Line feed", false]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:\\r\\n(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
pattern: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:\\r\\n(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
|
||||||
flags: "",
|
flags: "",
|
||||||
args: ["CRLF", false]
|
args: ["CRLF", false]
|
||||||
},
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,12 +25,12 @@ class FromHTMLEntity extends Operation {
|
|||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
this.outputType = "string";
|
this.outputType = "string";
|
||||||
this.args = [];
|
this.args = [];
|
||||||
this.patterns = [
|
this.checks = [
|
||||||
{
|
{
|
||||||
match: "&(?:#\\d{2,3}|#x[\\da-f]{2}|[a-z]{2,6});",
|
pattern: "&(?:#\\d{2,3}|#x[\\da-f]{2}|[a-z]{2,6});",
|
||||||
flags: "i",
|
flags: "i",
|
||||||
args: []
|
args: []
|
||||||
},
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,49 +32,54 @@ class FromHex extends Operation {
|
|||||||
value: FROM_HEX_DELIM_OPTIONS
|
value: FROM_HEX_DELIM_OPTIONS
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
this.patterns = [
|
this.checks = [
|
||||||
{
|
{
|
||||||
match: "^(?:[\\dA-F]{2})+$",
|
pattern: "^(?:[\\dA-F]{2})+$",
|
||||||
flags: "i",
|
flags: "i",
|
||||||
args: ["None"]
|
args: ["None"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^[\\dA-F]{2}(?: [\\dA-F]{2})*$",
|
pattern: "^[\\dA-F]{2}(?: [\\dA-F]{2})*$",
|
||||||
flags: "i",
|
flags: "i",
|
||||||
args: ["Space"]
|
args: ["Space"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^[\\dA-F]{2}(?:,[\\dA-F]{2})*$",
|
pattern: "^[\\dA-F]{2}(?:,[\\dA-F]{2})*$",
|
||||||
flags: "i",
|
flags: "i",
|
||||||
args: ["Comma"]
|
args: ["Comma"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^[\\dA-F]{2}(?:;[\\dA-F]{2})*$",
|
pattern: "^[\\dA-F]{2}(?:;[\\dA-F]{2})*$",
|
||||||
flags: "i",
|
flags: "i",
|
||||||
args: ["Semi-colon"]
|
args: ["Semi-colon"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^[\\dA-F]{2}(?::[\\dA-F]{2})*$",
|
pattern: "^[\\dA-F]{2}(?::[\\dA-F]{2})*$",
|
||||||
flags: "i",
|
flags: "i",
|
||||||
args: ["Colon"]
|
args: ["Colon"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^[\\dA-F]{2}(?:\\n[\\dA-F]{2})*$",
|
pattern: "^[\\dA-F]{2}(?:\\n[\\dA-F]{2})*$",
|
||||||
flags: "i",
|
flags: "i",
|
||||||
args: ["Line feed"]
|
args: ["Line feed"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^[\\dA-F]{2}(?:\\r\\n[\\dA-F]{2})*$",
|
pattern: "^[\\dA-F]{2}(?:\\r\\n[\\dA-F]{2})*$",
|
||||||
flags: "i",
|
flags: "i",
|
||||||
args: ["CRLF"]
|
args: ["CRLF"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^[\\dA-F]{2}(?:0x[\\dA-F]{2})*$",
|
pattern: "^(?:0x[\\dA-F]{2})+$",
|
||||||
flags: "i",
|
flags: "i",
|
||||||
args: ["0x"]
|
args: ["0x"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^[\\dA-F]{2}(?:\\\\x[\\dA-F]{2})*$",
|
pattern: "^0x[\\dA-F]{2}(?:,0x[\\dA-F]{2})*$",
|
||||||
|
flags: "i",
|
||||||
|
args: ["0x with comma"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
pattern: "^(?:\\\\x[\\dA-F]{2})+$",
|
||||||
flags: "i",
|
flags: "i",
|
||||||
args: ["\\x"]
|
args: ["\\x"]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,13 @@ class FromHexContent extends Operation {
|
|||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
this.outputType = "byteArray";
|
this.outputType = "byteArray";
|
||||||
this.args = [];
|
this.args = [];
|
||||||
|
this.checks = [
|
||||||
|
{
|
||||||
|
pattern: "\\|([\\da-f]{2} ?)+\\|",
|
||||||
|
flags: "i",
|
||||||
|
args: []
|
||||||
|
}
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -27,9 +27,9 @@ class FromHexdump extends Operation {
|
|||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
this.outputType = "byteArray";
|
this.outputType = "byteArray";
|
||||||
this.args = [];
|
this.args = [];
|
||||||
this.patterns = [
|
this.checks = [
|
||||||
{
|
{
|
||||||
match: "^(?:(?:[\\dA-F]{4,16}h?:?)?[ \\t]*((?:[\\dA-F]{2} ){1,8}(?:[ \\t]|[\\dA-F]{2}-)(?:[\\dA-F]{2} ){1,8}|(?:[\\dA-F]{4} )*[\\dA-F]{4}|(?:[\\dA-F]{2} )*[\\dA-F]{2})[^\\n]*\\n?){2,}$",
|
pattern: "^(?:(?:[\\dA-F]{4,16}h?:?)?[ \\t]*((?:[\\dA-F]{2} ){1,8}(?:[ \\t]|[\\dA-F]{2}-)(?:[\\dA-F]{2} ){1,8}|(?:[\\dA-F]{4} )*[\\dA-F]{4}|(?:[\\dA-F]{2} )*[\\dA-F]{2})[^\\n]*\\n?){2,}$",
|
||||||
flags: "i",
|
flags: "i",
|
||||||
args: []
|
args: []
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -37,12 +37,12 @@ class FromMorseCode extends Operation {
|
|||||||
"value": WORD_DELIM_OPTIONS
|
"value": WORD_DELIM_OPTIONS
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
this.patterns = [
|
this.checks = [
|
||||||
{
|
{
|
||||||
match: "(?:^[-. \\n]{5,}$|^[_. \\n]{5,}$|^(?:dash|dot| |\\n){5,}$)",
|
pattern: "(?:^[-. \\n]{5,}$|^[_. \\n]{5,}$|^(?:dash|dot| |\\n){5,}$)",
|
||||||
flags: "i",
|
flags: "i",
|
||||||
args: ["Space", "Line feed"]
|
args: ["Space", "Line feed"]
|
||||||
},
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ class FromMorseCode extends Operation {
|
|||||||
const letterDelim = Utils.charRep(args[0]);
|
const letterDelim = Utils.charRep(args[0]);
|
||||||
const wordDelim = Utils.charRep(args[1]);
|
const wordDelim = Utils.charRep(args[1]);
|
||||||
|
|
||||||
input = input.replace(/-|‐|−|_|–|—|dash/ig, "<dash>"); //hyphen-minus|hyphen|minus-sign|undersore|en-dash|em-dash
|
input = input.replace(/-|‐|−|_|–|—|dash/ig, "<dash>"); // hyphen-minus|hyphen|minus-sign|undersore|en-dash|em-dash
|
||||||
input = input.replace(/\.|·|dot/ig, "<dot>");
|
input = input.replace(/\.|·|dot/ig, "<dot>");
|
||||||
|
|
||||||
let words = input.split(wordDelim);
|
let words = input.split(wordDelim);
|
||||||
@@ -147,7 +147,8 @@ const MORSE_TABLE = {
|
|||||||
"=": "<dash><dot><dot><dot><dash>",
|
"=": "<dash><dot><dot><dot><dash>",
|
||||||
"&": "<dot><dash><dot><dot><dot>",
|
"&": "<dot><dash><dot><dot><dot>",
|
||||||
"_": "<dot><dot><dash><dash><dot><dash>",
|
"_": "<dot><dot><dash><dash><dot><dash>",
|
||||||
"$": "<dot><dot><dot><dash><dot><dot><dash>"
|
"$": "<dot><dot><dot><dash><dot><dot><dash>",
|
||||||
|
" ": "<dot><dot><dot><dot><dot><dot><dot>"
|
||||||
};
|
};
|
||||||
|
|
||||||
export default FromMorseCode;
|
export default FromMorseCode;
|
||||||
|
|||||||
@@ -32,37 +32,37 @@ class FromOctal extends Operation {
|
|||||||
"value": DELIM_OPTIONS
|
"value": DELIM_OPTIONS
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
this.patterns = [
|
this.checks = [
|
||||||
{
|
{
|
||||||
match: "^(?:[0-7]{1,2}|[123][0-7]{2})(?: (?:[0-7]{1,2}|[123][0-7]{2}))*$",
|
pattern: "^(?:[0-7]{1,2}|[123][0-7]{2})(?: (?:[0-7]{1,2}|[123][0-7]{2}))*$",
|
||||||
flags: "",
|
flags: "",
|
||||||
args: ["Space"]
|
args: ["Space"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^(?:[0-7]{1,2}|[123][0-7]{2})(?:,(?:[0-7]{1,2}|[123][0-7]{2}))*$",
|
pattern: "^(?:[0-7]{1,2}|[123][0-7]{2})(?:,(?:[0-7]{1,2}|[123][0-7]{2}))*$",
|
||||||
flags: "",
|
flags: "",
|
||||||
args: ["Comma"]
|
args: ["Comma"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^(?:[0-7]{1,2}|[123][0-7]{2})(?:;(?:[0-7]{1,2}|[123][0-7]{2}))*$",
|
pattern: "^(?:[0-7]{1,2}|[123][0-7]{2})(?:;(?:[0-7]{1,2}|[123][0-7]{2}))*$",
|
||||||
flags: "",
|
flags: "",
|
||||||
args: ["Semi-colon"]
|
args: ["Semi-colon"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^(?:[0-7]{1,2}|[123][0-7]{2})(?::(?:[0-7]{1,2}|[123][0-7]{2}))*$",
|
pattern: "^(?:[0-7]{1,2}|[123][0-7]{2})(?::(?:[0-7]{1,2}|[123][0-7]{2}))*$",
|
||||||
flags: "",
|
flags: "",
|
||||||
args: ["Colon"]
|
args: ["Colon"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^(?:[0-7]{1,2}|[123][0-7]{2})(?:\\n(?:[0-7]{1,2}|[123][0-7]{2}))*$",
|
pattern: "^(?:[0-7]{1,2}|[123][0-7]{2})(?:\\n(?:[0-7]{1,2}|[123][0-7]{2}))*$",
|
||||||
flags: "",
|
flags: "",
|
||||||
args: ["Line feed"]
|
args: ["Line feed"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^(?:[0-7]{1,2}|[123][0-7]{2})(?:\\r\\n(?:[0-7]{1,2}|[123][0-7]{2}))*$",
|
pattern: "^(?:[0-7]{1,2}|[123][0-7]{2})(?:\\r\\n(?:[0-7]{1,2}|[123][0-7]{2}))*$",
|
||||||
flags: "",
|
flags: "",
|
||||||
args: ["CRLF"]
|
args: ["CRLF"]
|
||||||
},
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -28,9 +28,9 @@ class FromQuotedPrintable extends Operation {
|
|||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
this.outputType = "byteArray";
|
this.outputType = "byteArray";
|
||||||
this.args = [];
|
this.args = [];
|
||||||
this.patterns = [
|
this.checks = [
|
||||||
{
|
{
|
||||||
match: "^[\\x21-\\x3d\\x3f-\\x7e \\t]{0,76}(?:=[\\da-f]{2}|=\\r?\\n)(?:[\\x21-\\x3d\\x3f-\\x7e \\t]|=[\\da-f]{2}|=\\r?\\n)*$",
|
pattern: "^[\\x21-\\x3d\\x3f-\\x7e \\t]{0,76}(?:=[\\da-f]{2}|=\\r?\\n)(?:[\\x21-\\x3d\\x3f-\\x7e \\t]|=[\\da-f]{2}|=\\r?\\n)*$",
|
||||||
flags: "i",
|
flags: "i",
|
||||||
args: []
|
args: []
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -33,27 +33,27 @@ class FromUNIXTimestamp extends Operation {
|
|||||||
"value": UNITS
|
"value": UNITS
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
this.patterns = [
|
this.checks = [
|
||||||
{
|
{
|
||||||
match: "^1?\\d{9}$",
|
pattern: "^1?\\d{9}$",
|
||||||
flags: "",
|
flags: "",
|
||||||
args: ["Seconds (s)"]
|
args: ["Seconds (s)"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^1?\\d{12}$",
|
pattern: "^1?\\d{12}$",
|
||||||
flags: "",
|
flags: "",
|
||||||
args: ["Milliseconds (ms)"]
|
args: ["Milliseconds (ms)"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^1?\\d{15}$",
|
pattern: "^1?\\d{15}$",
|
||||||
flags: "",
|
flags: "",
|
||||||
args: ["Microseconds (μs)"]
|
args: ["Microseconds (μs)"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
match: "^1?\\d{18}$",
|
pattern: "^1?\\d{18}$",
|
||||||
flags: "",
|
flags: "",
|
||||||
args: ["Nanoseconds (ns)"]
|
args: ["Nanoseconds (ns)"]
|
||||||
},
|
}
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ class GenerateHOTP extends Operation {
|
|||||||
|
|
||||||
this.name = "Generate HOTP";
|
this.name = "Generate HOTP";
|
||||||
this.module = "Default";
|
this.module = "Default";
|
||||||
this.description = "The HMAC-based One-Time Password algorithm (HOTP) is an algorithm that computes a one-time password from a shared secret key and an incrementing counter. It has been adopted as Internet Engineering Task Force standard RFC 4226, is the cornerstone of Initiative For Open Authentication (OATH), and is used in a number of two-factor authentication systems.<br><br>Enter the secret as the input or leave it blank for a random secret to be generated.";
|
this.description = "The HMAC-based One-Time Password algorithm (HOTP) is an algorithm that computes a one-time password from a shared secret key and an incrementing counter. It has been adopted as Internet Engineering Task Force standard RFC 4226, is the cornerstone of Initiative For Open Authentication (OAUTH), and is used in a number of two-factor authentication systems.<br><br>Enter the secret as the input or leave it blank for a random secret to be generated.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/HMAC-based_One-time_Password_algorithm";
|
this.infoURL = "https://wikipedia.org/wiki/HMAC-based_One-time_Password_algorithm";
|
||||||
this.inputType = "ArrayBuffer";
|
this.inputType = "ArrayBuffer";
|
||||||
this.outputType = "string";
|
this.outputType = "string";
|
||||||
@@ -59,7 +59,7 @@ class GenerateHOTP extends Operation {
|
|||||||
name: args[0],
|
name: args[0],
|
||||||
keySize: args[1],
|
keySize: args[1],
|
||||||
codeLength: args[2],
|
codeLength: args[2],
|
||||||
secret: (new ToBase32).run(input, []),
|
secret: (new ToBase32).run(input, []).split("=")[0],
|
||||||
});
|
});
|
||||||
const counter = args[3];
|
const counter = args[3];
|
||||||
return `URI: ${otpObj.hotpURL}\n\nPassword: ${otpObj.hotp(counter)}`;
|
return `URI: ${otpObj.hotpURL}\n\nPassword: ${otpObj.hotp(counter)}`;
|
||||||
|
|||||||
185
src/core/operations/GenerateImage.mjs
Normal file
185
src/core/operations/GenerateImage.mjs
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
/**
|
||||||
|
* @author pointhi [thomas.pointhuber@gmx.at]
|
||||||
|
* @copyright Crown Copyright 2019
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
import Utils from "../Utils.mjs";
|
||||||
|
import {isImage} from "../lib/FileType.mjs";
|
||||||
|
import {toBase64} from "../lib/Base64.mjs";
|
||||||
|
import {isWorkerEnvironment} from "../Utils.mjs";
|
||||||
|
import jimplib from "jimp/es/index.js";
|
||||||
|
const jimp = jimplib.default ? jimplib.default : jimplib;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate Image operation
|
||||||
|
*/
|
||||||
|
class GenerateImage extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GenerateImage constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Generate Image";
|
||||||
|
this.module = "Image";
|
||||||
|
this.description = "Generates an image using the input as pixel values.";
|
||||||
|
this.infoURL = "";
|
||||||
|
this.inputType = "ArrayBuffer";
|
||||||
|
this.outputType = "ArrayBuffer";
|
||||||
|
this.presentType = "html";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
"name": "Mode",
|
||||||
|
"type": "option",
|
||||||
|
"value": ["Greyscale", "RG", "RGB", "RGBA", "Bits"]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pixel Scale Factor",
|
||||||
|
"type": "number",
|
||||||
|
"value": 8,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Pixels per row",
|
||||||
|
"type": "number",
|
||||||
|
"value": 64,
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {byteArray} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {ArrayBuffer}
|
||||||
|
*/
|
||||||
|
async run(input, args) {
|
||||||
|
const [mode, scale, width] = args;
|
||||||
|
input = new Uint8Array(input);
|
||||||
|
|
||||||
|
if (scale <= 0) {
|
||||||
|
throw new OperationError("Pixel Scale Factor needs to be > 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (width <= 0) {
|
||||||
|
throw new OperationError("Pixels per Row needs to be > 0");
|
||||||
|
}
|
||||||
|
|
||||||
|
const bytePerPixelMap = {
|
||||||
|
"Greyscale": 1,
|
||||||
|
"RG": 2,
|
||||||
|
"RGB": 3,
|
||||||
|
"RGBA": 4,
|
||||||
|
"Bits": 1/8,
|
||||||
|
};
|
||||||
|
|
||||||
|
const bytesPerPixel = bytePerPixelMap[mode];
|
||||||
|
|
||||||
|
if (bytesPerPixel > 0 && input.length % bytesPerPixel !== 0) {
|
||||||
|
throw new OperationError(`Number of bytes is not a divisor of ${bytesPerPixel}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
const height = Math.ceil(input.length / bytesPerPixel / width);
|
||||||
|
const image = await new jimp(width, height, (err, image) => {});
|
||||||
|
|
||||||
|
if (isWorkerEnvironment())
|
||||||
|
self.sendStatusMessage("Generating image from data...");
|
||||||
|
|
||||||
|
if (mode === "Bits") {
|
||||||
|
let index = 0;
|
||||||
|
for (let j = 0; j < input.length; j++) {
|
||||||
|
const curByte = Utils.bin(input[j]);
|
||||||
|
for (let k = 0; k < 8; k++, index++) {
|
||||||
|
const x = index % width;
|
||||||
|
const y = Math.floor(index / width);
|
||||||
|
|
||||||
|
const value = curByte[k] === "0" ? 0xFF : 0x00;
|
||||||
|
const pixel = jimp.rgbaToInt(value, value, value, 0xFF);
|
||||||
|
image.setPixelColor(pixel, x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let i = 0;
|
||||||
|
while (i < input.length) {
|
||||||
|
const index = i / bytesPerPixel;
|
||||||
|
const x = index % width;
|
||||||
|
const y = Math.floor(index / width);
|
||||||
|
|
||||||
|
let red = 0x00;
|
||||||
|
let green = 0x00;
|
||||||
|
let blue = 0x00;
|
||||||
|
let alpha = 0xFF;
|
||||||
|
|
||||||
|
switch (mode) {
|
||||||
|
case "Greyscale":
|
||||||
|
red = green = blue = input[i++];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "RG":
|
||||||
|
red = input[i++];
|
||||||
|
green = input[i++];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "RGB":
|
||||||
|
red = input[i++];
|
||||||
|
green = input[i++];
|
||||||
|
blue = input[i++];
|
||||||
|
break;
|
||||||
|
|
||||||
|
case "RGBA":
|
||||||
|
red = input[i++];
|
||||||
|
green = input[i++];
|
||||||
|
blue = input[i++];
|
||||||
|
alpha = input[i++];
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new OperationError(`Unsupported Mode: (${mode})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const pixel = jimp.rgbaToInt(red, green, blue, alpha);
|
||||||
|
image.setPixelColor(pixel, x, y);
|
||||||
|
} catch (err) {
|
||||||
|
throw new OperationError(`Error while generating image from pixel values. (${err})`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (scale !== 1) {
|
||||||
|
if (isWorkerEnvironment())
|
||||||
|
self.sendStatusMessage("Scaling image...");
|
||||||
|
|
||||||
|
image.scaleToFit(width*scale, height*scale, jimp.RESIZE_NEAREST_NEIGHBOR);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const imageBuffer = await image.getBufferAsync(jimp.MIME_PNG);
|
||||||
|
return imageBuffer.buffer;
|
||||||
|
} catch (err) {
|
||||||
|
throw new OperationError(`Error generating image. (${err})`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays the generated image using HTML for web apps
|
||||||
|
* @param {ArrayBuffer} data
|
||||||
|
* @returns {html}
|
||||||
|
*/
|
||||||
|
present(data) {
|
||||||
|
if (!data.byteLength) return "";
|
||||||
|
const dataArray = new Uint8Array(data);
|
||||||
|
|
||||||
|
const type = isImage(dataArray);
|
||||||
|
if (!type) {
|
||||||
|
throw new OperationError("Invalid file type.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return `<img src="data:${type};base64,${toBase64(dataArray)}">`;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GenerateImage;
|
||||||
@@ -9,9 +9,11 @@
|
|||||||
import Operation from "../Operation.mjs";
|
import Operation from "../Operation.mjs";
|
||||||
import kbpgp from "kbpgp";
|
import kbpgp from "kbpgp";
|
||||||
import { getSubkeySize, ASP } from "../lib/PGP.mjs";
|
import { getSubkeySize, ASP } from "../lib/PGP.mjs";
|
||||||
|
import { cryptNotice } from "../lib/Crypt.mjs";
|
||||||
import * as es6promisify from "es6-promisify";
|
import * as es6promisify from "es6-promisify";
|
||||||
const promisify = es6promisify.default ? es6promisify.default.promisify : es6promisify.promisify;
|
const promisify = es6promisify.default ? es6promisify.default.promisify : es6promisify.promisify;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generate PGP Key Pair operation
|
* Generate PGP Key Pair operation
|
||||||
*/
|
*/
|
||||||
@@ -25,7 +27,7 @@ class GeneratePGPKeyPair extends Operation {
|
|||||||
|
|
||||||
this.name = "Generate PGP Key Pair";
|
this.name = "Generate PGP Key Pair";
|
||||||
this.module = "PGP";
|
this.module = "PGP";
|
||||||
this.description = "Generates a new public/private PGP key pair. Supports RSA and Eliptic Curve (EC) keys.";
|
this.description = `Generates a new public/private PGP key pair. Supports RSA and Eliptic Curve (EC) keys.<br><br>${cryptNotice}`;
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Pretty_Good_Privacy";
|
this.infoURL = "https://wikipedia.org/wiki/Pretty_Good_Privacy";
|
||||||
this.inputType = "string";
|
this.inputType = "string";
|
||||||
this.outputType = "string";
|
this.outputType = "string";
|
||||||
@@ -33,7 +35,7 @@ class GeneratePGPKeyPair extends Operation {
|
|||||||
{
|
{
|
||||||
"name": "Key type",
|
"name": "Key type",
|
||||||
"type": "option",
|
"type": "option",
|
||||||
"value": ["RSA-1024", "RSA-2048", "RSA-4096", "ECC-256", "ECC-384"]
|
"value": ["RSA-1024", "RSA-2048", "RSA-4096", "ECC-256", "ECC-384", "ECC-521"]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "Password (optional)",
|
"name": "Password (optional)",
|
||||||
@@ -59,12 +61,15 @@ class GeneratePGPKeyPair extends Operation {
|
|||||||
* @returns {string}
|
* @returns {string}
|
||||||
*/
|
*/
|
||||||
async run(input, args) {
|
async run(input, args) {
|
||||||
const [keyType, keySize] = args[0].split("-"),
|
let [keyType, keySize] = args[0].split("-");
|
||||||
password = args[1],
|
const password = args[1],
|
||||||
name = args[2],
|
name = args[2],
|
||||||
email = args[3];
|
email = args[3];
|
||||||
let userIdentifier = "";
|
let userIdentifier = "";
|
||||||
|
|
||||||
|
keyType = keyType.toLowerCase();
|
||||||
|
keySize = parseInt(keySize, 10);
|
||||||
|
|
||||||
if (name) userIdentifier += name;
|
if (name) userIdentifier += name;
|
||||||
if (email) userIdentifier += ` <${email}>`;
|
if (email) userIdentifier += ` <${email}>`;
|
||||||
|
|
||||||
|
|||||||
88
src/core/operations/GenerateRSAKeyPair.mjs
Normal file
88
src/core/operations/GenerateRSAKeyPair.mjs
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
/**
|
||||||
|
* @author Matt C [me@mitt.dev]
|
||||||
|
* @author gchq77703 []
|
||||||
|
* @copyright Crown Copyright 2018
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import forge from "node-forge";
|
||||||
|
import { cryptNotice } from "../lib/Crypt.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generate RSA Key Pair operation
|
||||||
|
*/
|
||||||
|
class GenerateRSAKeyPair extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GenerateRSAKeyPair constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Generate RSA Key Pair";
|
||||||
|
this.module = "Ciphers";
|
||||||
|
this.description = `Generate an RSA key pair with a given number of bits.<br><br>${cryptNotice}`;
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/RSA_(cryptosystem)";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "string";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
name: "RSA Key Length",
|
||||||
|
type: "option",
|
||||||
|
value: [
|
||||||
|
"1024",
|
||||||
|
"2048",
|
||||||
|
"4096"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Output Format",
|
||||||
|
type: "option",
|
||||||
|
value: [
|
||||||
|
"PEM",
|
||||||
|
"JSON",
|
||||||
|
"DER"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
async run(input, args) {
|
||||||
|
const [keyLength, outputFormat] = args;
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
forge.pki.rsa.generateKeyPair({
|
||||||
|
bits: Number(keyLength),
|
||||||
|
workers: -1,
|
||||||
|
workerScript: "assets/forge/prime.worker.min.js"
|
||||||
|
}, (err, keypair) => {
|
||||||
|
if (err) return reject(err);
|
||||||
|
|
||||||
|
let result;
|
||||||
|
|
||||||
|
switch (outputFormat) {
|
||||||
|
case "PEM":
|
||||||
|
result = forge.pki.publicKeyToPem(keypair.publicKey) + "\n" + forge.pki.privateKeyToPem(keypair.privateKey);
|
||||||
|
break;
|
||||||
|
case "JSON":
|
||||||
|
result = JSON.stringify(keypair);
|
||||||
|
break;
|
||||||
|
case "DER":
|
||||||
|
result = forge.asn1.toDer(forge.pki.privateKeyToAsn1(keypair.privateKey)).getBytes();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
resolve(result);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GenerateRSAKeyPair;
|
||||||
@@ -21,7 +21,7 @@ class GenerateTOTP extends Operation {
|
|||||||
|
|
||||||
this.name = "Generate TOTP";
|
this.name = "Generate TOTP";
|
||||||
this.module = "Default";
|
this.module = "Default";
|
||||||
this.description = "The Time-based One-Time Password algorithm (TOTP) is an algorithm that computes a one-time password from a shared secret key and the current time. It has been adopted as Internet Engineering Task Force standard RFC 6238, is the cornerstone of Initiative For Open Authentication (OATH), and is used in a number of two-factor authentication systems. A TOTP is an HOTP where the counter is the current time.<br><br>Enter the secret as the input or leave it blank for a random secret to be generated. T0 and T1 are in seconds.";
|
this.description = "The Time-based One-Time Password algorithm (TOTP) is an algorithm that computes a one-time password from a shared secret key and the current time. It has been adopted as Internet Engineering Task Force standard RFC 6238, is the cornerstone of Initiative For Open Authentication (OAUTH), and is used in a number of two-factor authentication systems. A TOTP is an HOTP where the counter is the current time.<br><br>Enter the secret as the input or leave it blank for a random secret to be generated. T0 and T1 are in seconds.";
|
||||||
this.infoURL = "https://wikipedia.org/wiki/Time-based_One-time_Password_algorithm";
|
this.infoURL = "https://wikipedia.org/wiki/Time-based_One-time_Password_algorithm";
|
||||||
this.inputType = "ArrayBuffer";
|
this.inputType = "ArrayBuffer";
|
||||||
this.outputType = "string";
|
this.outputType = "string";
|
||||||
@@ -64,7 +64,7 @@ class GenerateTOTP extends Operation {
|
|||||||
name: args[0],
|
name: args[0],
|
||||||
keySize: args[1],
|
keySize: args[1],
|
||||||
codeLength: args[2],
|
codeLength: args[2],
|
||||||
secret: (new ToBase32).run(input, []),
|
secret: (new ToBase32).run(input, []).split("=")[0],
|
||||||
epoch: args[3],
|
epoch: args[3],
|
||||||
timeSlice: args[4]
|
timeSlice: args[4]
|
||||||
});
|
});
|
||||||
|
|||||||
63
src/core/operations/GetTime.mjs
Normal file
63
src/core/operations/GetTime.mjs
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/**
|
||||||
|
* @author n1073645 [n1073645@gmail.com]
|
||||||
|
* @author n1474335 [n1474335@gmail.com]
|
||||||
|
* @copyright Crown Copyright 2020
|
||||||
|
* @license Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
import Operation from "../Operation.mjs";
|
||||||
|
import OperationError from "../errors/OperationError.mjs";
|
||||||
|
import {UNITS} from "../lib/DateTime.mjs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get Time operation
|
||||||
|
*/
|
||||||
|
class GetTime extends Operation {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GetTime constructor
|
||||||
|
*/
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
|
||||||
|
this.name = "Get Time";
|
||||||
|
this.module = "Default";
|
||||||
|
this.description = "Generates a timestamp showing the amount of time since the UNIX epoch (1970-01-01 00:00:00 UTC). Uses the W3C High Resolution Time API.";
|
||||||
|
this.infoURL = "https://wikipedia.org/wiki/Unix_time";
|
||||||
|
this.inputType = "string";
|
||||||
|
this.outputType = "number";
|
||||||
|
this.args = [
|
||||||
|
{
|
||||||
|
name: "Granularity",
|
||||||
|
type: "option",
|
||||||
|
value: UNITS
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} input
|
||||||
|
* @param {Object[]} args
|
||||||
|
* @returns {number}
|
||||||
|
*/
|
||||||
|
run(input, args) {
|
||||||
|
const nowMs = (performance.timeOrigin + performance.now()),
|
||||||
|
granularity = args[0];
|
||||||
|
|
||||||
|
switch (granularity) {
|
||||||
|
case "Nanoseconds (ns)":
|
||||||
|
return Math.round(nowMs * 1000 * 1000);
|
||||||
|
case "Microseconds (μs)":
|
||||||
|
return Math.round(nowMs * 1000);
|
||||||
|
case "Milliseconds (ms)":
|
||||||
|
return Math.round(nowMs);
|
||||||
|
case "Seconds (s)":
|
||||||
|
return Math.round(nowMs / 1000);
|
||||||
|
default:
|
||||||
|
throw new OperationError("Unknown granularity value: " + granularity);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default GetTime;
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user