mirror of
https://github.com/gchq/CyberChef
synced 2025-12-05 23:53:27 +00:00
Compare commits
229 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d2325306db | ||
|
|
dfe31980b7 | ||
|
|
9734b78aeb | ||
|
|
4ee0800990 | ||
|
|
387008bd9c | ||
|
|
bf24547202 | ||
|
|
c2f6b8df66 | ||
|
|
d0e428b728 | ||
|
|
ae5128a33a | ||
|
|
ed25017e2d | ||
|
|
e5b2b84073 | ||
|
|
1953d9a4c8 | ||
|
|
b3113c109b | ||
|
|
8c3569ea63 | ||
|
|
ae28d476de | ||
|
|
01c4cfdc8d | ||
|
|
8c6c3a1c01 | ||
|
|
f367c1f78b | ||
|
|
13d87d397d | ||
|
|
ed2c886359 | ||
|
|
6337e84708 | ||
|
|
ae20a951be | ||
|
|
866dd546c8 | ||
|
|
2070e1a96b | ||
|
|
952f49e2e1 | ||
|
|
f600571c6d | ||
|
|
5d4c7244e1 | ||
|
|
b6bdcaa71f | ||
|
|
c8eab5d218 | ||
|
|
8ab56a29ac | ||
|
|
973b5f3f5c | ||
|
|
076a1f97c2 | ||
|
|
d96ef37d81 | ||
|
|
56f8302402 | ||
|
|
97e6a7cbd8 | ||
|
|
d89d79116c | ||
|
|
367d79e820 | ||
|
|
283d7f2159 | ||
|
|
dacb3ef6c3 | ||
|
|
22454ae842 | ||
|
|
79b9b63982 | ||
|
|
2f68bf30a4 | ||
|
|
50f078cc45 | ||
|
|
47a410d6ab | ||
|
|
31cbf8cccc | ||
|
|
88bd321e3e | ||
|
|
b4a586c0b9 | ||
|
|
63593f1b6c | ||
|
|
dcff8971e8 | ||
|
|
3f7059a235 | ||
|
|
71c743ff5a | ||
|
|
15fbe5a459 | ||
|
|
cd47394709 | ||
|
|
6f4ee8b7b6 | ||
|
|
8c5d05b611 | ||
|
|
3bdcf4d851 | ||
|
|
1d1c69ca51 | ||
|
|
c4c679021d | ||
|
|
c16d13e2c9 | ||
|
|
97613eb3c7 | ||
|
|
a946d04a72 | ||
|
|
cc35ec82eb | ||
|
|
d6604e0008 | ||
|
|
b9e63efc37 | ||
|
|
b458707921 | ||
|
|
6ec52c6cd2 | ||
|
|
79d7a5dd87 | ||
|
|
1653d0212a | ||
|
|
c378bcb00b | ||
|
|
215e7a5f5d | ||
|
|
6b686681d5 | ||
|
|
20ea050728 | ||
|
|
4b6132a2d7 | ||
|
|
4cf80e3ebb | ||
|
|
045747f543 | ||
|
|
b10c5e3256 | ||
|
|
69df2e4183 | ||
|
|
12ebd35c4d | ||
|
|
30c5f76cf0 | ||
|
|
3a979b6cda | ||
|
|
863bdffa84 | ||
|
|
42b956e402 | ||
|
|
4acf7b4e4f | ||
|
|
42e881326f | ||
|
|
3c4893d7c7 | ||
|
|
027aca4ab2 | ||
|
|
2d471f551f | ||
|
|
5c598b69b0 | ||
|
|
037300de79 | ||
|
|
6990dcae89 | ||
|
|
6e81d6dfcd | ||
|
|
cea30465d8 | ||
|
|
b301d16cb2 | ||
|
|
19c002fcdd | ||
|
|
ab3a73fe58 | ||
|
|
91fc2c28dc | ||
|
|
ca47ba3c7c | ||
|
|
e1b456c01c | ||
|
|
5eb7e00eac | ||
|
|
8bcf68c8a1 | ||
|
|
520eaedd9a | ||
|
|
4c5e664ce0 | ||
|
|
53c500eb1b | ||
|
|
253346a201 | ||
|
|
c5d82a76ab | ||
|
|
18a9dfffc7 | ||
|
|
38838e4dca | ||
|
|
5c151d727b | ||
|
|
2d5b157c91 | ||
|
|
10d3d27a33 | ||
|
|
1614442bd7 | ||
|
|
a3c5b1e107 | ||
|
|
3f0af9cdea | ||
|
|
f4de4de8c1 | ||
|
|
69033a7343 | ||
|
|
5a22106731 | ||
|
|
5155d0ed56 | ||
|
|
9be674103f | ||
|
|
ba24e12454 | ||
|
|
b76aa16143 | ||
|
|
8f7bb3a7c9 | ||
|
|
be2b466376 | ||
|
|
f957925aac | ||
|
|
1bf8d63d1a | ||
|
|
8875144307 | ||
|
|
d5c01f387a | ||
|
|
32709cd60f | ||
|
|
aaf0a91975 | ||
|
|
6cc6230b91 | ||
|
|
dd630f20f8 | ||
|
|
0c6efd95fa | ||
|
|
a276378887 | ||
|
|
98d861a639 | ||
|
|
3b3c27072f | ||
|
|
3089c39369 | ||
|
|
0cbb17f7ce | ||
|
|
54793f2b78 | ||
|
|
f1ffe19ec8 | ||
|
|
e638fb69b5 | ||
|
|
718a94b5e0 | ||
|
|
3079059ce3 | ||
|
|
d6c6981bc0 | ||
|
|
8aeb7b60a7 | ||
|
|
9197ac6510 | ||
|
|
b67ad3073c | ||
|
|
4a4f37f888 | ||
|
|
c55331f220 | ||
|
|
757ec98554 | ||
|
|
14309f2069 | ||
|
|
e6b89d571e | ||
|
|
d957198fd6 | ||
|
|
903bd22999 | ||
|
|
04ee2fb3e4 | ||
|
|
ac2466a304 | ||
|
|
ab4c9ef0d6 | ||
|
|
a69063de9b | ||
|
|
62b76777c0 | ||
|
|
32a91bda0a | ||
|
|
a15af602e0 | ||
|
|
ec9dfd2918 | ||
|
|
016086ef4e | ||
|
|
2e5ea968ee | ||
|
|
5dde1c1c04 | ||
|
|
be14d56eae | ||
|
|
100b097ace | ||
|
|
3833c5f9fe | ||
|
|
3470dd9f3b | ||
|
|
c5e8649284 | ||
|
|
a95f43aa4d | ||
|
|
0420aa8edb | ||
|
|
806b43dfec | ||
|
|
98f4fe4c2b | ||
|
|
0d63b3cbae | ||
|
|
7061c05f77 | ||
|
|
9b9a182f9f | ||
|
|
2d9e7fcc6d | ||
|
|
56946a66aa | ||
|
|
c9242e32fe | ||
|
|
22e8883934 | ||
|
|
552a18d89a | ||
|
|
6b725e9114 | ||
|
|
415beaa0b0 | ||
|
|
e9fe227ed7 | ||
|
|
c1be109592 | ||
|
|
88e603bbf1 | ||
|
|
c7b2095bb4 | ||
|
|
7396117d89 | ||
|
|
fd96bf345b | ||
|
|
2820660264 | ||
|
|
86145dbf67 | ||
|
|
135b17186e | ||
|
|
ce494339ef | ||
|
|
dd5af7eb10 | ||
|
|
3abe99078e | ||
|
|
edbd540c68 | ||
|
|
06d9302d96 | ||
|
|
032b4bed7f | ||
|
|
8559f5c8ea | ||
|
|
91133172d5 | ||
|
|
001f3f30cd | ||
|
|
a1b1059ad1 | ||
|
|
69a0122fea | ||
|
|
3d505b4248 | ||
|
|
70d4e3394c | ||
|
|
3905c01a0d | ||
|
|
2a49af1ec3 | ||
|
|
3d4f54e8bc | ||
|
|
61f2f2d2e3 | ||
|
|
00058bd5c7 | ||
|
|
383fe50fc9 | ||
|
|
e4fdadc573 | ||
|
|
032f8808ef | ||
|
|
10cf0d13c2 | ||
|
|
6c9fea97ef | ||
|
|
4c2d612bdd | ||
|
|
8e9fece77d | ||
|
|
c818370123 | ||
|
|
bf2643802a | ||
|
|
1ad079fbd4 | ||
|
|
2d9e8773f5 | ||
|
|
5aa13f2428 | ||
|
|
38f5fcde86 | ||
|
|
f99ab87ca1 | ||
|
|
d3d230a76d | ||
|
|
e7c6a05e9f | ||
|
|
36e16d9925 | ||
|
|
84eaaf4819 | ||
|
|
821dd9c48c | ||
|
|
0c06e64051 |
19
.babelrc
19
.babelrc
@@ -1,19 +0,0 @@
|
||||
{
|
||||
"presets": [
|
||||
["env", {
|
||||
"targets": {
|
||||
"chrome": 40,
|
||||
"firefox": 35,
|
||||
"edge": 14,
|
||||
"node": "6.5"
|
||||
},
|
||||
"modules": false,
|
||||
"useBuiltIns": true
|
||||
}]
|
||||
],
|
||||
"plugins": [
|
||||
["babel-plugin-transform-builtin-extend", {
|
||||
"globals": ["Error"]
|
||||
}]
|
||||
]
|
||||
}
|
||||
@@ -36,7 +36,7 @@ deploy:
|
||||
skip_cleanup: true
|
||||
email: "n1474335@gmail.com"
|
||||
api_key:
|
||||
secure: "Z3FK6bm4RfQEIRXZ1lBNzQkVIoHpivThr9U+XBHmsBgIfdrK/XUnzs/slugo+NIz8nPiGmMx4gxyJonBCLHDGb1ysky2aEWTl26c0teaF4DeQEjWC1ZaGzv8MV1/GkUamnr1qouXjyUhyEAp33rd8ccN9Rq3QNYB/qLDcA9/FCme7JCW6sCd4zWO0LGEYMJEMc2FzAUkqhqsI05hegGhSDgKXRn5PmLARek4yHD+Hx7pstaTeQIy0WoGJjdzoB3iJIMmo/hWZGzZafktUOh223c5qzx4zMpDRNmMngBUw6R94nKd4KvplYRgB87Y3L/aiVU4CF+axwLmK8RPaC1wbJnlHf06zxHPdiFmsY/zKPpNel+nOnxzRrF5l2KMU4TU6gug3s9Jnzp9T5UMfhp0jW3YkxHGeuOPOeE1i0lTUWUGWrPHLQquAhLfkr2zxaU4ETk/y85hq9W4LAy0ENEDVXX2jP7FnI4Z1fdpmljpmVNJR+outPg6t+Coqgvil7v7XpMtDm8lKQanVYuxwmkb/ncOWFRWuM2j5zIEg3CHnFDcJ9bYrfKRg0b0tb/2BWD14pQnV76goVwzJQYVzdPc8TKIYJw2BZ1Nh9c0iruQVebe/6l1FX9fDCkz8VMmltni61/LxZrf8y0NT1YaU1raeNY2dH5UWvEa9p72FPMI6Eg="
|
||||
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
|
||||
|
||||
148
CHANGELOG.md
148
CHANGELOG.md
@@ -1,40 +1,102 @@
|
||||
# Changelog
|
||||
All notable changes to this project will be documented in this file.
|
||||
All major and minor version changes will be documented in this file. Details of patch-level version changes can be found in [commit messages](https://github.com/gchq/CyberChef/commits/master).
|
||||
|
||||
|
||||
### [8.17.0] - 2018-12-25
|
||||
- 'Generate QR Code' and 'Parse QR Code' operations added [@j433866] | [#448]
|
||||
|
||||
### [8.16.0] - 2018-12-19
|
||||
- 'Play Media' operation added [@anthony-arnold] | [#446]
|
||||
|
||||
### [8.15.0] - 2018-12-18
|
||||
- 'Text Encoding Brute Force' operation added [@Cynser] | [#439]
|
||||
|
||||
### [8.14.0] - 2018-12-18
|
||||
- 'To Base62' and 'From Base62' operations added [@tcode2k16] | [#443]
|
||||
|
||||
### [8.13.0] - 2018-12-15
|
||||
- 'A1Z26 Cipher Encode' and 'A1Z26 Cipher Decode' operations added [@jarmovanlenthe] | [#441]
|
||||
|
||||
### [8.12.0] - 2018-11-21
|
||||
- 'Citrix CTX1 Encode' and 'Citrix CTX1 Decode' operations added [@bwhitn] | [#428]
|
||||
|
||||
### [8.11.0] - 2018-11-13
|
||||
- 'CSV to JSON' and 'JSON to CSV' operations added [@n1474335] | [#277]
|
||||
|
||||
### [8.10.0] - 2018-11-07
|
||||
- 'Remove Diacritics' operation added [@klaxon1] | [#387]
|
||||
|
||||
### [8.9.0] - 2018-11-07
|
||||
- 'Defang URL' operation added [@arnydo] | [#394]
|
||||
|
||||
### [8.8.0] - 2018-10-10
|
||||
- 'Parse TLV' operation added [@GCHQ77703] | [#351]
|
||||
|
||||
### [8.7.0] - 2018-08-31
|
||||
- 'JWT Sign', 'JWT Verify' and 'JWT Decode' operations added [@GCHQ77703] | [#348]
|
||||
|
||||
### [8.6.0] - 2018-08-29
|
||||
- 'To Geohash' and 'From Geohash' operations added [@GCHQ77703] | [#344]
|
||||
|
||||
### [8.5.0] - 2018-08-23
|
||||
- 'To Braille' and 'From Braille' operations added [@n1474335] | [#255]
|
||||
|
||||
### [8.4.0] - 2018-08-23
|
||||
- 'To Base85' and 'From Base85' operations added [@PenguinGeorge] | [#340]
|
||||
|
||||
### [8.3.0] - 2018-08-21
|
||||
- 'To MessagePack' and 'From MessagePack' operations added [@artemisbot] | [#338]
|
||||
|
||||
### [8.2.0] - 2018-08-21
|
||||
- Added information links to most operations, accessible in the description popover @PenguinGeorge #298
|
||||
- Information links added to most operations, accessible in the description popover [@PenguinGeorge] | [#298]
|
||||
|
||||
### [8.1.0] - 2018-08-19
|
||||
- 'Dechunk HTTP response' operation added @sevzero #311
|
||||
- 'Dechunk HTTP response' operation added [@sevzero] | [#311]
|
||||
|
||||
## [8.0.0] - 2018-08-05
|
||||
- Codebase rewritten using [ES modules](https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/) and [classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) #284
|
||||
- Operation architecture restructured to make adding new operations a lot simpler #284
|
||||
- A script has been added to aid in the creation of new operations by running `npm run newop` @n1474335 #284
|
||||
- 'Magic' operation added - [automated detection of encoded data](https://github.com/gchq/CyberChef/wiki/Automatic-detection-of-encoded-data-using-CyberChef-Magic) @n1474335 #239
|
||||
- UI updated to use [Bootstrap Material Design](https://fezvrasta.github.io/bootstrap-material-design/) @n1474335 #248
|
||||
- `JSON`, `File` and `List<File>` Dish types added @n1474335 #284
|
||||
- `OperationError` type added for better handling of errors thrown by operations @d98762625 #296
|
||||
- A `present()` method has been added, allowing operations to pass machine-friendly data to subsequent operations whilst presenting human-friendly data to the user @n1474335 #284
|
||||
- Set operations added @d98762625 #281
|
||||
- 'To Table' operation added @JustAnotherMark #294
|
||||
- 'Haversine distance' operation added @Dachande663 #325
|
||||
- Started keeping a changelog @n1474335
|
||||
- Codebase rewritten using [ES modules](https://hacks.mozilla.org/2018/03/es-modules-a-cartoon-deep-dive/) and [classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) [@n1474335] [@d98762625] [@artemisbot] [@picapi] | [#284]
|
||||
- Operation architecture restructured to make adding new operations a lot simpler [@n1474335] | [#284]
|
||||
- A script has been added to aid in the creation of new operations by running `npm run newop` [@n1474335] | [#284]
|
||||
- 'Magic' operation added - [automated detection of encoded data](https://github.com/gchq/CyberChef/wiki/Automatic-detection-of-encoded-data-using-CyberChef-Magic) [@n1474335] | [#239]
|
||||
- UI updated to use [Bootstrap Material Design](https://fezvrasta.github.io/bootstrap-material-design/) [@n1474335] | [#248]
|
||||
- `JSON`, `File` and `List<File>` Dish types added [@n1474335] | [#284]
|
||||
- `OperationError` type added for better handling of errors thrown by operations [@d98762625] | [#296]
|
||||
- A `present()` method has been added, allowing operations to pass machine-friendly data to subsequent operations whilst presenting human-friendly data to the user [@n1474335] | [#284]
|
||||
- Set operations added [@d98762625] | [#281]
|
||||
- 'To Table' operation added [@JustAnotherMark] | [#294]
|
||||
- 'Haversine distance' operation added [@Dachande663] | [#325]
|
||||
- Started keeping a changelog [@n1474335]
|
||||
|
||||
## [7.0.0] - 2017-12-28
|
||||
- Added support for loading, processing and downloading files up to 500MB @n1474335 #224
|
||||
- Added support for loading, processing and downloading files up to 500MB [@n1474335] | [#224]
|
||||
|
||||
## [6.0.0] - 2017-09-19
|
||||
- Added threading support, moving all recipe processing into a [Web Worker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers) to increase performance and allow long-running operations to be cancelled @n1474335 #173
|
||||
- Created modules so that operations relying on large libraries can be downloaded separately as required, reducing the initial loading time for the app @n1474335 #173
|
||||
- Threading support added. All recipe processing moved into a [Web Worker](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers) to increase performance and to allow long-running operations to be cancelled [@n1474335] | [#173]
|
||||
- Module system created so that operations relying on large libraries can be downloaded separately as required, reducing the initial loading time for the app [@n1474335] | [#173]
|
||||
|
||||
## [5.0.0] - 2017-03-30
|
||||
- Configured Webpack build process, Babel transpilation and ES6 imports and exports @n1474335 #95
|
||||
- Webpack build process configured with Babel transpilation and ES6 imports and exports [@n1474335] | [#95]
|
||||
|
||||
## [4.0.0] - 2016-11-28
|
||||
- Initial open source commit @n1474335
|
||||
- Initial open source commit [@n1474335] | [b1d73a72](https://github.com/gchq/CyberChef/commit/b1d73a725dc7ab9fb7eb789296efd2b7e4b08306)
|
||||
|
||||
|
||||
|
||||
[8.17.0]: https://github.com/gchq/CyberChef/releases/tag/v8.17.0
|
||||
[8.16.0]: https://github.com/gchq/CyberChef/releases/tag/v8.16.0
|
||||
[8.15.0]: https://github.com/gchq/CyberChef/releases/tag/v8.15.0
|
||||
[8.14.0]: https://github.com/gchq/CyberChef/releases/tag/v8.14.0
|
||||
[8.13.0]: https://github.com/gchq/CyberChef/releases/tag/v8.13.0
|
||||
[8.12.0]: https://github.com/gchq/CyberChef/releases/tag/v8.12.0
|
||||
[8.11.0]: https://github.com/gchq/CyberChef/releases/tag/v8.11.0
|
||||
[8.10.0]: https://github.com/gchq/CyberChef/releases/tag/v8.10.0
|
||||
[8.9.0]: https://github.com/gchq/CyberChef/releases/tag/v8.9.0
|
||||
[8.8.0]: https://github.com/gchq/CyberChef/releases/tag/v8.8.0
|
||||
[8.7.0]: https://github.com/gchq/CyberChef/releases/tag/v8.7.0
|
||||
[8.6.0]: https://github.com/gchq/CyberChef/releases/tag/v8.6.0
|
||||
[8.5.0]: https://github.com/gchq/CyberChef/releases/tag/v8.5.0
|
||||
[8.4.0]: https://github.com/gchq/CyberChef/releases/tag/v8.4.0
|
||||
[8.3.0]: https://github.com/gchq/CyberChef/releases/tag/v8.3.0
|
||||
[8.2.0]: https://github.com/gchq/CyberChef/releases/tag/v8.2.0
|
||||
[8.1.0]: https://github.com/gchq/CyberChef/releases/tag/v8.1.0
|
||||
[8.0.0]: https://github.com/gchq/CyberChef/releases/tag/v8.0.0
|
||||
@@ -42,3 +104,49 @@ All notable changes to this project will be documented in this file.
|
||||
[6.0.0]: https://github.com/gchq/CyberChef/releases/tag/v6.0.0
|
||||
[5.0.0]: https://github.com/gchq/CyberChef/releases/tag/v5.0.0
|
||||
[4.0.0]: https://github.com/gchq/CyberChef/commit/b1d73a725dc7ab9fb7eb789296efd2b7e4b08306
|
||||
|
||||
[@n1474335]: https://github.com/n1474335
|
||||
[@d98762625]: https://github.com/d98762625
|
||||
[@j433866]: https://github.com/j433866
|
||||
[@GCHQ77703]: https://github.com/GCHQ77703
|
||||
[@artemisbot]: https://github.com/artemisbot
|
||||
[@picapi]: https://github.com/picapi
|
||||
[@Dachande663]: https://github.com/Dachande663
|
||||
[@JustAnotherMark]: https://github.com/JustAnotherMark
|
||||
[@sevzero]: https://github.com/sevzero
|
||||
[@PenguinGeorge]: https://github.com/PenguinGeorge
|
||||
[@arnydo]: https://github.com/arnydo
|
||||
[@klaxon1]: https://github.com/klaxon1
|
||||
[@bwhitn]: https://github.com/bwhitn
|
||||
[@jarmovanlenthe]: https://github.com/jarmovanlenthe
|
||||
[@tcode2k16]: https://github.com/tcode2k16
|
||||
[@Cynser]: https://github.com/Cynser
|
||||
[@anthony-arnold]: https://github.com/anthony-arnold
|
||||
|
||||
[#95]: https://github.com/gchq/CyberChef/pull/299
|
||||
[#173]: https://github.com/gchq/CyberChef/pull/173
|
||||
[#224]: https://github.com/gchq/CyberChef/pull/224
|
||||
[#239]: https://github.com/gchq/CyberChef/pull/239
|
||||
[#248]: https://github.com/gchq/CyberChef/pull/248
|
||||
[#255]: https://github.com/gchq/CyberChef/issues/255
|
||||
[#277]: https://github.com/gchq/CyberChef/issues/277
|
||||
[#281]: https://github.com/gchq/CyberChef/pull/281
|
||||
[#284]: https://github.com/gchq/CyberChef/pull/284
|
||||
[#294]: https://github.com/gchq/CyberChef/pull/294
|
||||
[#296]: https://github.com/gchq/CyberChef/pull/296
|
||||
[#298]: https://github.com/gchq/CyberChef/pull/298
|
||||
[#311]: https://github.com/gchq/CyberChef/pull/311
|
||||
[#325]: https://github.com/gchq/CyberChef/pull/325
|
||||
[#338]: https://github.com/gchq/CyberChef/pull/338
|
||||
[#340]: https://github.com/gchq/CyberChef/pull/340
|
||||
[#344]: https://github.com/gchq/CyberChef/pull/344
|
||||
[#348]: https://github.com/gchq/CyberChef/pull/348
|
||||
[#351]: https://github.com/gchq/CyberChef/pull/351
|
||||
[#387]: https://github.com/gchq/CyberChef/pull/387
|
||||
[#394]: https://github.com/gchq/CyberChef/pull/394
|
||||
[#428]: https://github.com/gchq/CyberChef/pull/428
|
||||
[#439]: https://github.com/gchq/CyberChef/pull/439
|
||||
[#441]: https://github.com/gchq/CyberChef/pull/441
|
||||
[#443]: https://github.com/gchq/CyberChef/pull/443
|
||||
[#446]: https://github.com/gchq/CyberChef/pull/446
|
||||
[#448]: https://github.com/gchq/CyberChef/pull/448
|
||||
|
||||
18
Gruntfile.js
18
Gruntfile.js
@@ -22,7 +22,7 @@ module.exports = function (grunt) {
|
||||
// Tasks
|
||||
grunt.registerTask("dev",
|
||||
"A persistent task which creates a development build whenever source files are modified.",
|
||||
["clean:dev", "exec:generateConfig", "concurrent:dev"]);
|
||||
["clean:dev", "clean:config", "exec:generateConfig", "concurrent:dev"]);
|
||||
|
||||
grunt.registerTask("node",
|
||||
"Compiles CyberChef into a single NodeJS module.",
|
||||
@@ -38,7 +38,7 @@ module.exports = function (grunt) {
|
||||
|
||||
grunt.registerTask("prod",
|
||||
"Creates a production-ready build. Use the --msg flag to add a compile message.",
|
||||
["eslint", "clean:prod", "exec:generateConfig", "webpack:web", "inline", "chmod"]);
|
||||
["eslint", "clean:prod", "clean:config", "exec:generateConfig", "webpack:web", "inline", "chmod"]);
|
||||
|
||||
grunt.registerTask("default",
|
||||
"Lints the code base",
|
||||
@@ -143,7 +143,7 @@ module.exports = function (grunt) {
|
||||
options: {
|
||||
configFile: "./.eslintrc.json"
|
||||
},
|
||||
configs: ["Gruntfile.js"],
|
||||
configs: ["*.js"],
|
||||
core: ["src/core/**/*.{js,mjs}", "!src/core/vendor/**/*", "!src/core/operations/legacy/**/*"],
|
||||
web: ["src/web/**/*.{js,mjs}"],
|
||||
node: ["src/node/**/*.{js,mjs}"],
|
||||
@@ -280,7 +280,11 @@ module.exports = function (grunt) {
|
||||
chunks: false,
|
||||
modules: false,
|
||||
entrypoints: false,
|
||||
warningsFilter: [/source-map/, /dependency is an expression/],
|
||||
warningsFilter: [
|
||||
/source-map/,
|
||||
/dependency is an expression/,
|
||||
/export 'default'/
|
||||
],
|
||||
}
|
||||
},
|
||||
start: {
|
||||
@@ -382,13 +386,13 @@ module.exports = function (grunt) {
|
||||
"mkdir -p src/core/config/modules",
|
||||
"echo 'export default {};\n' > src/core/config/modules/OpModules.mjs",
|
||||
"echo '[]\n' > src/core/config/OperationConfig.json",
|
||||
"node --experimental-modules src/core/config/scripts/generateOpsIndex.mjs",
|
||||
"node --experimental-modules src/core/config/scripts/generateConfig.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",
|
||||
"echo '--- Config scripts finished. ---\n'"
|
||||
].join(";")
|
||||
},
|
||||
tests: {
|
||||
command: "node --experimental-modules test/index.mjs"
|
||||
command: "node --experimental-modules --no-warnings --no-deprecation test/index.mjs"
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
23
babel.config.js
Normal file
23
babel.config.js
Normal file
@@ -0,0 +1,23 @@
|
||||
module.exports = function(api) {
|
||||
api.cache.forever();
|
||||
|
||||
return {
|
||||
"presets": [
|
||||
["@babel/preset-env", {
|
||||
"targets": {
|
||||
"chrome": 40,
|
||||
"firefox": 35,
|
||||
"edge": 14,
|
||||
"node": "6.5"
|
||||
},
|
||||
"modules": false,
|
||||
"useBuiltIns": "entry"
|
||||
}]
|
||||
],
|
||||
"plugins": [
|
||||
["babel-plugin-transform-builtin-extend", {
|
||||
"globals": ["Error"]
|
||||
}]
|
||||
]
|
||||
};
|
||||
};
|
||||
6129
package-lock.json
generated
6129
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
78
package.json
78
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cyberchef",
|
||||
"version": "8.2.0",
|
||||
"version": "8.17.0",
|
||||
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
|
||||
"author": "n1474335 <n1474335@gmail.com>",
|
||||
"homepage": "https://gchq.github.io/CyberChef",
|
||||
@@ -30,45 +30,44 @@
|
||||
"main": "build/node/CyberChef.js",
|
||||
"bugs": "https://github.com/gchq/CyberChef/issues",
|
||||
"devDependencies": {
|
||||
"autoprefixer": "^9.1.0",
|
||||
"babel-core": "^6.26.3",
|
||||
"babel-loader": "^7.1.5",
|
||||
"babel-preset-env": "^1.7.0",
|
||||
"@babel/core": "^7.1.5",
|
||||
"@babel/preset-env": "^7.1.5",
|
||||
"autoprefixer": "^9.3.1",
|
||||
"babel-loader": "^8.0.4",
|
||||
"bootstrap": "^4.1.3",
|
||||
"colors": "^1.3.1",
|
||||
"css-loader": "^1.0.0",
|
||||
"eslint": "^5.3.0",
|
||||
"colors": "^1.3.2",
|
||||
"css-loader": "^1.0.1",
|
||||
"eslint": "^5.8.0",
|
||||
"exports-loader": "^0.7.0",
|
||||
"extract-text-webpack-plugin": "^4.0.0-alpha0",
|
||||
"file-loader": "^1.1.11",
|
||||
"file-loader": "^2.0.0",
|
||||
"grunt": "^1.0.3",
|
||||
"grunt-accessibility": "~6.0.0",
|
||||
"grunt-chmod": "~1.1.1",
|
||||
"grunt-concurrent": "^2.3.1",
|
||||
"grunt-contrib-clean": "~1.1.0",
|
||||
"grunt-contrib-clean": "~2.0.0",
|
||||
"grunt-contrib-copy": "~1.0.0",
|
||||
"grunt-contrib-watch": "^1.1.0",
|
||||
"grunt-eslint": "^21.0.0",
|
||||
"grunt-exec": "~3.0.0",
|
||||
"grunt-jsdoc": "^2.2.1",
|
||||
"grunt-webpack": "^3.1.2",
|
||||
"grunt-jsdoc": "^2.3.0",
|
||||
"grunt-webpack": "^3.1.3",
|
||||
"html-webpack-plugin": "^3.2.0",
|
||||
"imports-loader": "^0.8.0",
|
||||
"ink-docstrap": "^1.3.2",
|
||||
"js-to-mjs": "^0.2.0",
|
||||
"jsdoc-babel": "^0.4.0",
|
||||
"node-sass": "^4.9.2",
|
||||
"postcss-css-variables": "^0.9.0",
|
||||
"postcss-import": "^12.0.0",
|
||||
"postcss-loader": "^2.1.6",
|
||||
"jsdoc-babel": "^0.5.0",
|
||||
"node-sass": "^4.10.0",
|
||||
"postcss-css-variables": "^0.11.0",
|
||||
"postcss-import": "^12.0.1",
|
||||
"postcss-loader": "^3.0.0",
|
||||
"prompt": "^1.0.0",
|
||||
"sass-loader": "^7.1.0",
|
||||
"sitemap": "^1.13.0",
|
||||
"style-loader": "^0.21.0",
|
||||
"url-loader": "^1.0.1",
|
||||
"sitemap": "^2.1.0",
|
||||
"style-loader": "^0.23.1",
|
||||
"url-loader": "^1.1.2",
|
||||
"web-resource-inliner": "^4.2.1",
|
||||
"webpack": "^4.16.4",
|
||||
"webpack-dev-server": "^3.1.5",
|
||||
"webpack": "^4.25.1",
|
||||
"webpack-dev-server": "^3.1.10",
|
||||
"webpack-node-externals": "^1.7.2",
|
||||
"worker-loader": "^2.0.0"
|
||||
},
|
||||
@@ -77,46 +76,52 @@
|
||||
"babel-plugin-transform-builtin-extend": "1.1.2",
|
||||
"babel-polyfill": "^6.26.0",
|
||||
"bcryptjs": "^2.4.3",
|
||||
"bignumber.js": "^7.2.1",
|
||||
"bignumber.js": "^8.0.1",
|
||||
"bootstrap-colorpicker": "^2.5.3",
|
||||
"bootstrap-material-design": "^4.1.1",
|
||||
"bson": "^3.0.2",
|
||||
"chi-squared": "^1.1.0",
|
||||
"crypto-api": "^0.8.0",
|
||||
"crypto-api": "^0.8.3",
|
||||
"crypto-js": "^3.1.9-1",
|
||||
"ctph.js": "0.0.5",
|
||||
"diff": "^3.5.0",
|
||||
"es6-promisify": "^6.0.0",
|
||||
"es6-promisify": "^6.0.1",
|
||||
"escodegen": "^1.11.0",
|
||||
"esmangle": "^1.0.1",
|
||||
"esprima": "^4.0.1",
|
||||
"exif-parser": "^0.1.12",
|
||||
"file-saver": "^1.3.8",
|
||||
"highlight.js": "^9.12.0",
|
||||
"file-saver": "^2.0.0-rc.4",
|
||||
"highlight.js": "^9.13.1",
|
||||
"jimp": "^0.6.0",
|
||||
"jquery": "^3.3.1",
|
||||
"js-crc": "^0.2.0",
|
||||
"js-sha3": "^0.7.0",
|
||||
"js-sha3": "^0.8.0",
|
||||
"jsbn": "^1.1.0",
|
||||
"jsesc": "^2.5.1",
|
||||
"jsonpath": "^1.0.0",
|
||||
"jsonwebtoken": "^8.3.0",
|
||||
"jsqr": "^1.1.1",
|
||||
"jsrsasign": "8.0.12",
|
||||
"kbpgp": "^2.0.77",
|
||||
"lodash": "^4.17.10",
|
||||
"kbpgp": "^2.0.82",
|
||||
"lodash": "^4.17.11",
|
||||
"loglevel": "^1.6.1",
|
||||
"loglevel-message-prefix": "^3.0.0",
|
||||
"moment": "^2.22.2",
|
||||
"moment-timezone": "^0.5.21",
|
||||
"node-forge": "^0.7.5",
|
||||
"moment-timezone": "^0.5.23",
|
||||
"ngeohash": "^0.6.0",
|
||||
"node-forge": "^0.7.6",
|
||||
"node-md6": "^0.1.0",
|
||||
"notepack.io": "^2.1.3",
|
||||
"nwmatcher": "^1.4.4",
|
||||
"otp": "^0.1.3",
|
||||
"popper.js": "^1.14.4",
|
||||
"qr-image": "^3.2.0",
|
||||
"scryptsy": "^2.0.0",
|
||||
"snackbarjs": "^1.1.0",
|
||||
"sortablejs": "^1.7.0",
|
||||
"split.js": "^1.3.5",
|
||||
"split.js": "^1.5.9",
|
||||
"ssdeep.js": "0.0.2",
|
||||
"ua-parser-js": "^0.7.18",
|
||||
"ua-parser-js": "^0.7.19",
|
||||
"utf8": "^3.0.0",
|
||||
"vkbeautify": "^0.99.3",
|
||||
"xmldom": "^0.1.27",
|
||||
@@ -130,7 +135,6 @@
|
||||
"test": "grunt test",
|
||||
"docs": "grunt docs",
|
||||
"lint": "grunt lint",
|
||||
"newop": "node --experimental-modules src/core/config/scripts/newOperation.mjs",
|
||||
"postinstall": "[ -f node_modules/crypto-api/src/crypto-api.mjs ] || npx j2m node_modules/crypto-api/src/crypto-api.js"
|
||||
"newop": "node --experimental-modules src/core/config/scripts/newOperation.mjs"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,7 +169,7 @@ class Dish {
|
||||
this.value = this.value instanceof BigNumber ? Utils.strToByteArray(this.value.toFixed()) : [];
|
||||
break;
|
||||
case Dish.JSON:
|
||||
this.value = this.value ? Utils.strToByteArray(JSON.stringify(this.value)) : [];
|
||||
this.value = this.value ? Utils.strToByteArray(JSON.stringify(this.value, null, 4)) : [];
|
||||
break;
|
||||
case Dish.FILE:
|
||||
this.value = await Utils.readFile(this.value);
|
||||
|
||||
@@ -25,6 +25,7 @@ class Ingredient {
|
||||
this.hint = "";
|
||||
this.toggleValues = [];
|
||||
this.target = null;
|
||||
this.defaultIndex = 0;
|
||||
|
||||
if (ingredientConfig) {
|
||||
this._parseConfig(ingredientConfig);
|
||||
@@ -46,6 +47,7 @@ class Ingredient {
|
||||
this.hint = ingredientConfig.hint || false;
|
||||
this.toggleValues = ingredientConfig.toggleValues;
|
||||
this.target = typeof ingredientConfig.target !== "undefined" ? ingredientConfig.target : null;
|
||||
this.defaultIndex = typeof ingredientConfig.defaultIndex !== "undefined" ? ingredientConfig.defaultIndex : 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -181,6 +181,7 @@ class Operation {
|
||||
if (ing.hint) conf.hint = ing.hint;
|
||||
if (ing.disabled) conf.disabled = ing.disabled;
|
||||
if (ing.target) conf.target = ing.target;
|
||||
if (ing.defaultIndex) conf.defaultIndex = ing.defaultIndex;
|
||||
return conf;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import moment from "moment-timezone";
|
||||
import {fromBase64} from "./lib/Base64";
|
||||
import {fromHex} from "./lib/Hex";
|
||||
import {fromDecimal} from "./lib/Decimal";
|
||||
import {fromBinary} from "./lib/Binary";
|
||||
|
||||
|
||||
/**
|
||||
@@ -298,7 +299,7 @@ class Utils {
|
||||
* Accepts hex, Base64, UTF8 and Latin1 strings.
|
||||
*
|
||||
* @param {string} str
|
||||
* @param {string} type - One of "Hex", "Decimal", "Base64", "UTF8" or "Latin1"
|
||||
* @param {string} type - One of "Binary", "Hex", "Decimal", "Base64", "UTF8" or "Latin1"
|
||||
* @returns {byteArray}
|
||||
*
|
||||
* @example
|
||||
@@ -313,6 +314,8 @@ class Utils {
|
||||
*/
|
||||
static convertToByteArray(str, type) {
|
||||
switch (type.toLowerCase()) {
|
||||
case "binary":
|
||||
return fromBinary(str);
|
||||
case "hex":
|
||||
return fromHex(str);
|
||||
case "decimal":
|
||||
@@ -333,7 +336,7 @@ class Utils {
|
||||
* Accepts hex, Base64, UTF8 and Latin1 strings.
|
||||
*
|
||||
* @param {string} str
|
||||
* @param {string} type - One of "Hex", "Decimal", "Base64", "UTF8" or "Latin1"
|
||||
* @param {string} type - One of "Binary", "Hex", "Decimal", "Base64", "UTF8" or "Latin1"
|
||||
* @returns {string}
|
||||
*
|
||||
* @example
|
||||
@@ -348,6 +351,8 @@ class Utils {
|
||||
*/
|
||||
static convertToByteString(str, type) {
|
||||
switch (type.toLowerCase()) {
|
||||
case "binary":
|
||||
return Utils.byteArrayToChars(fromBinary(str));
|
||||
case "hex":
|
||||
return Utils.byteArrayToChars(fromHex(str));
|
||||
case "decimal":
|
||||
@@ -555,8 +560,6 @@ class Utils {
|
||||
if (renderNext) {
|
||||
cell += b;
|
||||
renderNext = false;
|
||||
} else if (b === "\\") {
|
||||
renderNext = true;
|
||||
} else if (b === "\"" && !inString) {
|
||||
inString = true;
|
||||
} else if (b === "\"" && inString) {
|
||||
@@ -570,6 +573,10 @@ class Utils {
|
||||
cell = "";
|
||||
lines.push(line);
|
||||
line = [];
|
||||
// Skip next byte if it is also a line delim (e.g. \r\n)
|
||||
if (lineDelims.indexOf(next) >= 0 && next !== b) {
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
cell += b;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,10 @@
|
||||
"From Base32",
|
||||
"To Base58",
|
||||
"From Base58",
|
||||
"To Base62",
|
||||
"From Base62",
|
||||
"To Base85",
|
||||
"From Base85",
|
||||
"To Base",
|
||||
"From Base",
|
||||
"To BCD",
|
||||
@@ -47,7 +51,15 @@
|
||||
"Change IP format",
|
||||
"Encode text",
|
||||
"Decode text",
|
||||
"Swap endianness"
|
||||
"Text Encoding Brute Force",
|
||||
"Swap endianness",
|
||||
"To MessagePack",
|
||||
"From MessagePack",
|
||||
"To Braille",
|
||||
"From Braille",
|
||||
"Parse TLV",
|
||||
"CSV to JSON",
|
||||
"JSON to CSV"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -77,12 +89,19 @@
|
||||
"Bifid Cipher Decode",
|
||||
"Affine Cipher Encode",
|
||||
"Affine Cipher Decode",
|
||||
"A1Z26 Cipher Encode",
|
||||
"A1Z26 Cipher Decode",
|
||||
"Atbash Cipher",
|
||||
"Substitute",
|
||||
"Derive PBKDF2 key",
|
||||
"Derive EVP key",
|
||||
"Bcrypt",
|
||||
"Scrypt",
|
||||
"JWT Sign",
|
||||
"JWT Verify",
|
||||
"JWT Decode",
|
||||
"Citrix CTX1 Encode",
|
||||
"Citrix CTX1 Decode",
|
||||
"Pseudo-Random Number Generator"
|
||||
]
|
||||
},
|
||||
@@ -149,7 +168,8 @@
|
||||
"Change IP format",
|
||||
"Group IP addresses",
|
||||
"Encode NetBIOS Name",
|
||||
"Decode NetBIOS Name"
|
||||
"Decode NetBIOS Name",
|
||||
"Defang URL"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -157,6 +177,7 @@
|
||||
"ops": [
|
||||
"Encode text",
|
||||
"Decode text",
|
||||
"Remove Diacritics",
|
||||
"Unescape Unicode Characters"
|
||||
]
|
||||
},
|
||||
@@ -283,7 +304,9 @@
|
||||
"Adler-32 Checksum",
|
||||
"CRC-16 Checksum",
|
||||
"CRC-32 Checksum",
|
||||
"TCP/IP Checksum"
|
||||
"TCP/IP Checksum",
|
||||
"To Geohash",
|
||||
"From Geohash"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -313,7 +336,20 @@
|
||||
"To Camel case",
|
||||
"To Kebab case",
|
||||
"BSON serialise",
|
||||
"BSON deserialise"
|
||||
"BSON deserialise",
|
||||
"To MessagePack",
|
||||
"From MessagePack"
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "Forensics",
|
||||
"ops": [
|
||||
"Detect File Type",
|
||||
"Scan for Embedded Files",
|
||||
"Remove EXIF",
|
||||
"Extract EXIF",
|
||||
"Render Image",
|
||||
"Play Media"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -322,17 +358,14 @@
|
||||
"Entropy",
|
||||
"Frequency distribution",
|
||||
"Chi Square",
|
||||
"Detect File Type",
|
||||
"Scan for Embedded Files",
|
||||
"Disassemble x86",
|
||||
"Pseudo-Random Number Generator",
|
||||
"Generate UUID",
|
||||
"Generate TOTP",
|
||||
"Generate HOTP",
|
||||
"Generate QR Code",
|
||||
"Parse QR Code",
|
||||
"Haversine distance",
|
||||
"Render Image",
|
||||
"Remove EXIF",
|
||||
"Extract EXIF",
|
||||
"Numberwang",
|
||||
"XKCD Random Number"
|
||||
]
|
||||
|
||||
@@ -81,6 +81,7 @@ export function fromBase64(data, alphabet="A-Za-z0-9+/=", returnType="string", r
|
||||
return returnType === "string" ? "" : [];
|
||||
}
|
||||
|
||||
alphabet = alphabet || "A-Za-z0-9+/=";
|
||||
alphabet = Utils.expandAlphRange(alphabet).join("");
|
||||
|
||||
const output = [];
|
||||
@@ -125,14 +126,14 @@ export function fromBase64(data, alphabet="A-Za-z0-9+/=", returnType="string", r
|
||||
* Base64 alphabets.
|
||||
*/
|
||||
export const ALPHABET_OPTIONS = [
|
||||
{name: "Standard: A-Za-z0-9+/=", value: "A-Za-z0-9+/="},
|
||||
{name: "URL safe: A-Za-z0-9-_", value: "A-Za-z0-9-_"},
|
||||
{name: "Standard (RFC 4648): A-Za-z0-9+/=", value: "A-Za-z0-9+/="},
|
||||
{name: "URL safe (RFC 4648 \u00A75): A-Za-z0-9-_", value: "A-Za-z0-9-_"},
|
||||
{name: "Filename safe: A-Za-z0-9+-=", value: "A-Za-z0-9+\\-="},
|
||||
{name: "itoa64: ./0-9A-Za-z=", value: "./0-9A-Za-z="},
|
||||
{name: "XML: A-Za-z0-9_.", value: "A-Za-z0-9_."},
|
||||
{name: "y64: A-Za-z0-9._-", value: "A-Za-z0-9._-"},
|
||||
{name: "z64: 0-9a-zA-Z+/=", value: "0-9a-zA-Z+/="},
|
||||
{name: "Radix-64: 0-9A-Za-z+/=", value: "0-9A-Za-z+/="},
|
||||
{name: "Radix-64 (RFC 4880): 0-9A-Za-z+/=", value: "0-9A-Za-z+/="},
|
||||
{name: "Uuencoding: [space]-_", value: " -_"},
|
||||
{name: "Xxencoding: +-0-9A-Za-z", value: "+\\-0-9A-Za-z"},
|
||||
{name: "BinHex: !-,-0-689@A-NP-VX-Z[`a-fh-mp-r", value: "!-,-0-689@A-NP-VX-Z[`a-fh-mp-r"},
|
||||
|
||||
45
src/core/lib/Base85.mjs
Normal file
45
src/core/lib/Base85.mjs
Normal file
@@ -0,0 +1,45 @@
|
||||
/**
|
||||
* Base85 resources.
|
||||
*
|
||||
* @author PenguinGeorge [george@penguingeorge.com]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Base85 alphabet options.
|
||||
*/
|
||||
export const ALPHABET_OPTIONS = [
|
||||
{
|
||||
name: "Standard",
|
||||
value: "!-u",
|
||||
},
|
||||
{
|
||||
name: "Z85 (ZeroMQ)",
|
||||
value: "0-9a-zA-Z.\\-:+=^!/*?&<>()[]{}@%$#",
|
||||
},
|
||||
{
|
||||
name: "IPv6",
|
||||
value: "0-9A-Za-z!#$%&()*+\\-;<=>?@^_`{|~}",
|
||||
}
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Returns the name of the alphabet, when given the alphabet.
|
||||
*
|
||||
* @param {string} alphabet
|
||||
* @returns {string}
|
||||
*/
|
||||
export function alphabetName(alphabet) {
|
||||
alphabet = alphabet.replace("'", "'");
|
||||
alphabet = alphabet.replace("\"", """);
|
||||
alphabet = alphabet.replace("\\", "\");
|
||||
let name;
|
||||
|
||||
ALPHABET_OPTIONS.forEach(function(a) {
|
||||
if (escape(alphabet) === escape(a.value)) name = a.name;
|
||||
});
|
||||
|
||||
return name;
|
||||
}
|
||||
70
src/core/lib/Binary.mjs
Normal file
70
src/core/lib/Binary.mjs
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Binary functions.
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Utils from "../Utils";
|
||||
|
||||
|
||||
/**
|
||||
* Convert a byte array into a binary string.
|
||||
*
|
||||
* @param {Uint8Array|byteArray} data
|
||||
* @param {string} [delim="Space"]
|
||||
* @param {number} [padding=8]
|
||||
* @returns {string}
|
||||
*
|
||||
* @example
|
||||
* // returns "00010000 00100000 00110000"
|
||||
* toBinary([10,20,30]);
|
||||
*
|
||||
* // returns "00010000 00100000 00110000"
|
||||
* toBinary([10,20,30], ":");
|
||||
*/
|
||||
export function toBinary(data, delim="Space", padding=8) {
|
||||
if (!data) return "";
|
||||
|
||||
delim = Utils.charRep(delim);
|
||||
let output = "";
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
output += data[i].toString(2).padStart(padding, "0") + delim;
|
||||
}
|
||||
|
||||
if (delim.length) {
|
||||
return output.slice(0, -delim.length);
|
||||
} else {
|
||||
return output;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Convert a binary string into a byte array.
|
||||
*
|
||||
* @param {string} data
|
||||
* @param {string} [delim]
|
||||
* @param {number} [byteLen=8]
|
||||
* @returns {byteArray}
|
||||
*
|
||||
* @example
|
||||
* // returns [10,20,30]
|
||||
* fromBinary("00010000 00100000 00110000");
|
||||
*
|
||||
* // returns [10,20,30]
|
||||
* fromBinary("00010000:00100000:00110000", "Colon");
|
||||
*/
|
||||
export function fromBinary(data, delim="Space", byteLen=8) {
|
||||
const delimRegex = Utils.regexRep(delim);
|
||||
data = data.replace(delimRegex, "");
|
||||
|
||||
const output = [];
|
||||
for (let i = 0; i < data.length; i += byteLen) {
|
||||
output.push(parseInt(data.substr(i, byteLen), 2));
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ export function bitOp (input, key, func, nullPreserving, scheme) {
|
||||
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
k = key[i % key.length];
|
||||
if (scheme === "Cascade") k = input[i + 1] || 0;
|
||||
o = input[i];
|
||||
x = nullPreserving && (o === 0 || o === k) ? o : func(o, k);
|
||||
result.push(x);
|
||||
@@ -115,3 +116,9 @@ export function sub(operand, key) {
|
||||
const result = operand - key;
|
||||
return (result < 0) ? 256 + result : result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delimiter options for bitwise operations
|
||||
*/
|
||||
export const BITWISE_OP_DELIMS = ["Hex", "Decimal", "Binary", "Base64", "UTF8", "Latin1"];
|
||||
|
||||
15
src/core/lib/Braille.mjs
Normal file
15
src/core/lib/Braille.mjs
Normal file
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* Braille resources.
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Braille lookup table.
|
||||
*/
|
||||
export const BRAILLE_LOOKUP = {
|
||||
ascii: " A1B'K2L@CIF/MSP\"E3H9O6R^DJG>NTQ,*5<-U8V.%[$+X!&;:4\\0Z7(_?W]#Y)=",
|
||||
dot6: "⠀⠁⠂⠃⠄⠅⠆⠇⠈⠉⠊⠋⠌⠍⠎⠏⠐⠑⠒⠓⠔⠕⠖⠗⠘⠙⠚⠛⠜⠝⠞⠟⠠⠡⠢⠣⠤⠥⠦⠧⠨⠩⠪⠫⠬⠭⠮⠯⠰⠱⠲⠳⠴⠵⠶⠷⠸⠹⠺⠻⠼⠽⠾⠿"
|
||||
};
|
||||
@@ -39,3 +39,21 @@ export function search (input, searchRegex, removeRegex, includeTotal) {
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* URL regular expression
|
||||
*/
|
||||
const protocol = "[A-Z]+://",
|
||||
hostname = "[-\\w]+(?:\\.\\w[-\\w]*)+",
|
||||
port = ":\\d+",
|
||||
path = "/[^.!,?\"<>\\[\\]{}\\s\\x7F-\\xFF]*" +
|
||||
"(?:[.!,?]+[^.!,?\"<>\\[\\]{}\\s\\x7F-\\xFF]+)*";
|
||||
|
||||
export const URL_REGEX = new RegExp(protocol + hostname + "(?:" + port + ")?(?:" + path + ")?", "ig");
|
||||
|
||||
|
||||
/**
|
||||
* Domain name regular expression
|
||||
*/
|
||||
export const DOMAIN_REGEX = /\b((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,63}\b/ig;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
*
|
||||
* @author picapi
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @author Klaxon [klaxon@veyr.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
@@ -109,8 +110,8 @@ export function ipv6CidrRange(cidr, includeNetworkInfo) {
|
||||
* @returns {string}
|
||||
*/
|
||||
export function ipv4HyphenatedRange(range, includeNetworkInfo, enumerateAddresses, allowLargeList) {
|
||||
const ip1 = strToIpv4(range[1]),
|
||||
ip2 = strToIpv4(range[2]);
|
||||
const ip1 = strToIpv4(range[0].split("-")[0].trim()),
|
||||
ip2 = strToIpv4(range[0].split("-")[1].trim());
|
||||
|
||||
let output = "";
|
||||
|
||||
@@ -162,8 +163,8 @@ Total addresses in range: ${(((ip2 - ip1) >>> 0) + 1)}
|
||||
* @returns {string}
|
||||
*/
|
||||
export function ipv6HyphenatedRange(range, includeNetworkInfo) {
|
||||
const ip1 = strToIpv6(range[1]),
|
||||
ip2 = strToIpv6(range[14]),
|
||||
const ip1 = strToIpv6(range[0].split("-")[0].trim()),
|
||||
ip2 = strToIpv6(range[0].split("-")[1].trim()),
|
||||
total = new Array(128).fill();
|
||||
|
||||
let output = "",
|
||||
@@ -188,6 +189,93 @@ export function ipv6HyphenatedRange(range, includeNetworkInfo) {
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a list of IPv4 addresses separated by a new line (\n) and displays information
|
||||
* about it.
|
||||
*
|
||||
* @param {RegExp} list
|
||||
* @param {boolean} includeNetworkInfo
|
||||
* @param {boolean} enumerateAddresses
|
||||
* @param {boolean} allowLargeList
|
||||
* @returns {string}
|
||||
*/
|
||||
export function ipv4ListedRange(match, includeNetworkInfo, enumerateAddresses, allowLargeList) {
|
||||
|
||||
let ipv4List = match[0].split("\n");
|
||||
ipv4List = ipv4List.filter(Boolean);
|
||||
|
||||
const ipv4CidrList = ipv4List.filter(function(a) {
|
||||
return a.includes("/");
|
||||
});
|
||||
for (let i = 0; i < ipv4CidrList.length; i++) {
|
||||
const network = strToIpv4(ipv4CidrList[i].split("/")[0]);
|
||||
const cidrRange = parseInt(ipv4CidrList[i].split("/")[1], 10);
|
||||
if (cidrRange < 0 || cidrRange > 31) {
|
||||
return "IPv4 CIDR must be less than 32";
|
||||
}
|
||||
const mask = ~(0xFFFFFFFF >>> cidrRange),
|
||||
cidrIp1 = network & mask,
|
||||
cidrIp2 = cidrIp1 | ~mask;
|
||||
ipv4List.splice(ipv4List.indexOf(ipv4CidrList[i]), 1);
|
||||
ipv4List.push(ipv4ToStr(cidrIp1), ipv4ToStr(cidrIp2));
|
||||
}
|
||||
|
||||
ipv4List = ipv4List.sort(ipv4Compare);
|
||||
const ip1 = ipv4List[0];
|
||||
const ip2 = ipv4List[ipv4List.length - 1];
|
||||
const range = [ip1 + " - " + ip2];
|
||||
return ipv4HyphenatedRange(range, includeNetworkInfo, enumerateAddresses, allowLargeList);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a list of IPv6 addresses separated by a new line (\n) and displays information
|
||||
* about it.
|
||||
*
|
||||
* @param {RegExp} list
|
||||
* @param {boolean} includeNetworkInfo
|
||||
* @returns {string}
|
||||
*/
|
||||
export function ipv6ListedRange(match, includeNetworkInfo) {
|
||||
|
||||
let ipv6List = match[0].split("\n");
|
||||
ipv6List = ipv6List.filter(function(str) {
|
||||
return str.trim();
|
||||
});
|
||||
for (let i =0; i < ipv6List.length; i++){
|
||||
ipv6List[i] = ipv6List[i].trim();
|
||||
}
|
||||
const ipv6CidrList = ipv6List.filter(function(a) {
|
||||
return a.includes("/");
|
||||
});
|
||||
|
||||
for (let i = 0; i < ipv6CidrList.length; i++) {
|
||||
|
||||
const network = strToIpv6(ipv6CidrList[i].split("/")[0]);
|
||||
const cidrRange = parseInt(ipv6CidrList[i].split("/")[1], 10);
|
||||
|
||||
if (cidrRange < 0 || cidrRange > 127) {
|
||||
return "IPv6 CIDR must be less than 128";
|
||||
}
|
||||
|
||||
const cidrIp1 = new Array(8),
|
||||
cidrIp2 = new Array(8);
|
||||
|
||||
const mask = genIpv6Mask(cidrRange);
|
||||
|
||||
for (let j = 0; j < 8; j++) {
|
||||
cidrIp1[j] = network[j] & mask[j];
|
||||
cidrIp2[j] = cidrIp1[j] | (~mask[j] & 0x0000FFFF);
|
||||
}
|
||||
ipv6List.splice(ipv6List.indexOf(ipv6CidrList[i]), 1);
|
||||
ipv6List.push(ipv6ToStr(cidrIp1), ipv6ToStr(cidrIp2));
|
||||
}
|
||||
ipv6List = ipv6List.sort(ipv6Compare);
|
||||
const ip1 = ipv6List[0];
|
||||
const ip2 = ipv6List[ipv6List.length - 1];
|
||||
const range = [ip1 + " - " + ip2];
|
||||
return ipv6HyphenatedRange(range, includeNetworkInfo);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an IPv4 address from string format to numerical format.
|
||||
*
|
||||
@@ -391,6 +479,37 @@ export function genIpv6Mask(cidr) {
|
||||
return mask;
|
||||
}
|
||||
|
||||
/**
|
||||
* Comparison operation for sorting of IPv4 addresses.
|
||||
*
|
||||
* @param {string} a
|
||||
* @param {string} b
|
||||
* @returns {number}
|
||||
*/
|
||||
export function ipv4Compare(a, b) {
|
||||
return strToIpv4(a) - strToIpv4(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Comparison operation for sorting of IPv6 addresses.
|
||||
*
|
||||
* @param {string} a
|
||||
* @param {string} b
|
||||
* @returns {number}
|
||||
*/
|
||||
export function ipv6Compare(a, b) {
|
||||
|
||||
const a_ = strToIpv6(a),
|
||||
b_ = strToIpv6(b);
|
||||
|
||||
for (let i = 0; i < a_.length; i++){
|
||||
if (a_[i] !== b_[i]){
|
||||
return a_[i] - b_[i];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
const _LARGE_RANGE_ERROR = "The specified range contains more than 65,536 addresses. Running this query could crash your browser. If you want to run it, select the \"Allow large queries\" option. You are advised to turn off \"Auto Bake\" whilst editing large ranges.";
|
||||
|
||||
/**
|
||||
|
||||
@@ -265,9 +265,10 @@ class Magic {
|
||||
* performance)
|
||||
* @param {Object[]} [recipeConfig=[]] - The recipe configuration up to this point
|
||||
* @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
|
||||
* @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) {
|
||||
async speculativeExecution(depth=0, extLang=false, intensive=false, recipeConfig=[], useful=false, crib=null) {
|
||||
if (depth < 0) return [];
|
||||
|
||||
// Find any operations that can be run on this data
|
||||
@@ -284,9 +285,9 @@ class Magic {
|
||||
isUTF8: this.isUTF8(),
|
||||
entropy: this.calcEntropy(),
|
||||
matchingOps: matchingOps,
|
||||
useful: useful
|
||||
useful: useful,
|
||||
matchesCrib: crib && crib.test(this.inputStr)
|
||||
});
|
||||
|
||||
const prevOp = recipeConfig[recipeConfig.length - 1];
|
||||
|
||||
// Execute each of the matching operations, then recursively call the speculativeExecution()
|
||||
@@ -305,7 +306,7 @@ class Magic {
|
||||
|
||||
const magic = new Magic(output, this.opPatterns),
|
||||
speculativeResults = await magic.speculativeExecution(
|
||||
depth-1, extLang, intensive, [...recipeConfig, opConfig], op.useful);
|
||||
depth-1, extLang, intensive, [...recipeConfig, opConfig], op.useful, crib);
|
||||
|
||||
results = results.concat(speculativeResults);
|
||||
}));
|
||||
@@ -317,7 +318,7 @@ class Magic {
|
||||
await Promise.all(bfEncodings.map(async enc => {
|
||||
const magic = new Magic(enc.data, this.opPatterns),
|
||||
bfResults = await magic.speculativeExecution(
|
||||
depth-1, extLang, false, [...recipeConfig, enc.conf]);
|
||||
depth-1, extLang, false, [...recipeConfig, enc.conf], false, crib);
|
||||
|
||||
results = results.concat(bfResults);
|
||||
}));
|
||||
|
||||
78
src/core/lib/TLVParser.mjs
Normal file
78
src/core/lib/TLVParser.mjs
Normal file
@@ -0,0 +1,78 @@
|
||||
/**
|
||||
* Parser for Type-length-value data.
|
||||
*
|
||||
* @author gchq77703 []
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
const defaults = {
|
||||
location: 0,
|
||||
bytesInLength: 1,
|
||||
basicEncodingRules: false
|
||||
};
|
||||
|
||||
/**
|
||||
* TLVParser library
|
||||
*/
|
||||
export default class TLVParser {
|
||||
|
||||
/**
|
||||
* TLVParser constructor
|
||||
*
|
||||
* @param {byteArray} input
|
||||
* @param {Object} options
|
||||
*/
|
||||
constructor(input, options) {
|
||||
this.input = input;
|
||||
Object.assign(this, defaults, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {number}
|
||||
*/
|
||||
getLength() {
|
||||
if (this.basicEncodingRules) {
|
||||
const bit = this.input[this.location];
|
||||
if (bit & 0x80) {
|
||||
this.bytesInLength = bit & ~0x80;
|
||||
} else {
|
||||
this.location++;
|
||||
return bit & ~0x80;
|
||||
}
|
||||
}
|
||||
|
||||
let length = 0;
|
||||
|
||||
for (let i = 0; i < this.bytesInLength; i++) {
|
||||
length += this.input[this.location] * Math.pow(Math.pow(2, 8), i);
|
||||
this.location++;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {number} length
|
||||
* @returns {number[]}
|
||||
*/
|
||||
getValue(length) {
|
||||
const value = [];
|
||||
|
||||
for (let i = 0; i < length; i++) {
|
||||
if (this.location > this.input.length) return value;
|
||||
value.push(this.input[this.location]);
|
||||
this.location++;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns {boolean}
|
||||
*/
|
||||
atEnd() {
|
||||
return this.input.length <= this.location;
|
||||
}
|
||||
}
|
||||
63
src/core/operations/A1Z26CipherDecode.mjs
Normal file
63
src/core/operations/A1Z26CipherDecode.mjs
Normal file
@@ -0,0 +1,63 @@
|
||||
/**
|
||||
* @author Jarmo van Lenthe [github.com/jarmovanlenthe]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import {DELIM_OPTIONS} from "../lib/Delim";
|
||||
import OperationError from "../errors/OperationError";
|
||||
|
||||
/**
|
||||
* A1Z26 Cipher Decode operation
|
||||
*/
|
||||
class A1Z26CipherDecode extends Operation {
|
||||
|
||||
/**
|
||||
* A1Z26CipherDecode constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "A1Z26 Cipher Decode";
|
||||
this.module = "Ciphers";
|
||||
this.description = "Converts alphabet order numbers into their corresponding alphabet character.<br><br>e.g. <code>1</code> becomes <code>a</code> and <code>2</code> becomes <code>b</code>.";
|
||||
this.infoURL = "";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "Delimiter",
|
||||
type: "option",
|
||||
value: DELIM_OPTIONS
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const delim = Utils.charRep(args[0] || "Space");
|
||||
|
||||
if (input.length === 0) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const bites = input.split(delim);
|
||||
let latin1 = "";
|
||||
for (let i = 0; i < bites.length; i++) {
|
||||
if (bites[i] < 1 || bites[i] > 26) {
|
||||
throw new OperationError("Error: all numbers must be between 1 and 26.");
|
||||
}
|
||||
latin1 += Utils.chr(parseInt(bites[i], 10) + 96);
|
||||
}
|
||||
return latin1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default A1Z26CipherDecode;
|
||||
61
src/core/operations/A1Z26CipherEncode.mjs
Normal file
61
src/core/operations/A1Z26CipherEncode.mjs
Normal file
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* @author Jarmo van Lenthe [github.com/jarmovanlenthe]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import {DELIM_OPTIONS} from "../lib/Delim";
|
||||
|
||||
/**
|
||||
* A1Z26 Cipher Encode operation
|
||||
*/
|
||||
class A1Z26CipherEncode extends Operation {
|
||||
|
||||
/**
|
||||
* A1Z26CipherEncode constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "A1Z26 Cipher Encode";
|
||||
this.module = "Ciphers";
|
||||
this.description = "Converts alphabet characters into their corresponding alphabet order number.<br><br>e.g. <code>a</code> becomes <code>1</code> and <code>b</code> becomes <code>2</code>.<br><br>Non-alphabet characters are dropped.";
|
||||
this.infoURL = "";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "Delimiter",
|
||||
type: "option",
|
||||
value: DELIM_OPTIONS
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const delim = Utils.charRep(args[0] || "Space");
|
||||
let output = "";
|
||||
|
||||
const sanitizedinput = input.toLowerCase(),
|
||||
charcode = Utils.strToCharcode(sanitizedinput);
|
||||
|
||||
for (let i = 0; i < charcode.length; i++) {
|
||||
const ordinal = charcode[i] - 96;
|
||||
|
||||
if (ordinal > 0 && ordinal <= 26) {
|
||||
output += ordinal.toString(10) + delim;
|
||||
}
|
||||
}
|
||||
return output.slice(0, -delim.length);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default A1Z26CipherEncode;
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import { bitOp, add } from "../lib/BitwiseOp";
|
||||
import { bitOp, add, BITWISE_OP_DELIMS } from "../lib/BitwiseOp";
|
||||
|
||||
/**
|
||||
* ADD operation
|
||||
@@ -30,7 +30,7 @@ class ADD extends Operation {
|
||||
"name": "Key",
|
||||
"type": "toggleString",
|
||||
"value": "",
|
||||
"toggleValues": ["Hex", "Decimal", "Base64", "UTF8", "Latin1"]
|
||||
"toggleValues": BITWISE_OP_DELIMS
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import { bitOp, and } from "../lib/BitwiseOp";
|
||||
import { bitOp, and, BITWISE_OP_DELIMS } from "../lib/BitwiseOp";
|
||||
|
||||
/**
|
||||
* AND operation
|
||||
@@ -30,7 +30,7 @@ class AND extends Operation {
|
||||
"name": "Key",
|
||||
"type": "toggleString",
|
||||
"value": "",
|
||||
"toggleValues": ["Hex", "Decimal", "Base64", "UTF8", "Latin1"]
|
||||
"toggleValues": BITWISE_OP_DELIMS
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import bzip2 from "../vendor/bzip2.js";
|
||||
import bzip2 from "../vendor/bzip2";
|
||||
import OperationError from "../errors/OperationError";
|
||||
|
||||
/**
|
||||
|
||||
80
src/core/operations/CSVToJSON.mjs
Normal file
80
src/core/operations/CSVToJSON.mjs
Normal file
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import Utils from "../Utils";
|
||||
|
||||
/**
|
||||
* CSV to JSON operation
|
||||
*/
|
||||
class CSVToJSON extends Operation {
|
||||
|
||||
/**
|
||||
* CSVToJSON constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "CSV to JSON";
|
||||
this.module = "Default";
|
||||
this.description = "Converts a CSV file to JSON format.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Comma-separated_values";
|
||||
this.inputType = "string";
|
||||
this.outputType = "JSON";
|
||||
this.args = [
|
||||
{
|
||||
name: "Cell delimiters",
|
||||
type: "binaryShortString",
|
||||
value: ","
|
||||
},
|
||||
{
|
||||
name: "Row delimiters",
|
||||
type: "binaryShortString",
|
||||
value: "\\r\\n"
|
||||
},
|
||||
{
|
||||
name: "Format",
|
||||
type: "option",
|
||||
value: ["Array of dictionaries", "Array of arrays"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {JSON}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [cellDelims, rowDelims, format] = args;
|
||||
let json, header;
|
||||
|
||||
try {
|
||||
json = Utils.parseCSV(input, cellDelims.split(""), rowDelims.split(""));
|
||||
} catch (err) {
|
||||
throw new OperationError("Unable to parse CSV: " + err);
|
||||
}
|
||||
|
||||
switch (format) {
|
||||
case "Array of dictionaries":
|
||||
header = json[0];
|
||||
return json.slice(1).map(row => {
|
||||
const obj = {};
|
||||
header.forEach((h, i) => {
|
||||
obj[h] = row[i];
|
||||
});
|
||||
return obj;
|
||||
});
|
||||
case "Array of arrays":
|
||||
default:
|
||||
return json;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default CSVToJSON;
|
||||
58
src/core/operations/CitrixCTX1Decode.mjs
Normal file
58
src/core/operations/CitrixCTX1Decode.mjs
Normal file
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* @author bwhitn [brian.m.whitney@gmail.com]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import cptable from "../vendor/js-codepage/cptable.js";
|
||||
|
||||
/**
|
||||
* Citrix CTX1 Decode operation
|
||||
*/
|
||||
class CitrixCTX1Decode extends Operation {
|
||||
|
||||
/**
|
||||
* CitrixCTX1Decode constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Citrix CTX1 Decode";
|
||||
this.module = "Encodings";
|
||||
this.description = "Decodes strings in a Citrix CTX1 password format to plaintext.";
|
||||
this.infoURL = "https://www.reddit.com/r/AskNetsec/comments/1s3r6y/citrix_ctx1_hash_decoding/";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
if (input.length % 4 !== 0) {
|
||||
throw new OperationError("Incorrect hash length");
|
||||
}
|
||||
const revinput = input.reverse();
|
||||
const result = [];
|
||||
let temp = 0;
|
||||
for (let i = 0; i < revinput.length; i += 2) {
|
||||
if (i + 2 >= revinput.length) {
|
||||
temp = 0;
|
||||
} else {
|
||||
temp = ((revinput[i + 2] - 0x41) & 0xf) ^ (((revinput[i + 3]- 0x41) << 4) & 0xf0);
|
||||
}
|
||||
temp = (((revinput[i] - 0x41) & 0xf) ^ (((revinput[i + 1] - 0x41) << 4) & 0xf0)) ^ 0xa5 ^ temp;
|
||||
result.push(temp);
|
||||
}
|
||||
// Decodes a utf-16le string
|
||||
return cptable.utils.decode(1200, result.reverse());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default CitrixCTX1Decode;
|
||||
50
src/core/operations/CitrixCTX1Encode.mjs
Normal file
50
src/core/operations/CitrixCTX1Encode.mjs
Normal file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* @author bwhitn [brian.m.whitney@gmail.com]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import cptable from "../vendor/js-codepage/cptable.js";
|
||||
|
||||
/**
|
||||
* Citrix CTX1 Encode operation
|
||||
*/
|
||||
class CitrixCTX1Encode extends Operation {
|
||||
|
||||
/**
|
||||
* CitrixCTX1Encode constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Citrix CTX1 Encode";
|
||||
this.module = "Encodings";
|
||||
this.description = "Encodes strings to Citrix CTX1 password format.";
|
||||
this.infoURL = "https://www.reddit.com/r/AskNetsec/comments/1s3r6y/citrix_ctx1_hash_decoding/";
|
||||
this.inputType = "string";
|
||||
this.outputType = "byteArray";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
run(input, args) {
|
||||
const utf16pass = Array.from(cptable.utils.encode(1200, input));
|
||||
const result = [];
|
||||
let temp = 0;
|
||||
for (let i = 0; i < utf16pass.length; i++) {
|
||||
temp = utf16pass[i] ^ 0xa5 ^ temp;
|
||||
result.push(((temp >>> 4) & 0xf) + 0x41);
|
||||
result.push((temp & 0xf) + 0x41);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default CitrixCTX1Encode;
|
||||
102
src/core/operations/DefangURL.mjs
Normal file
102
src/core/operations/DefangURL.mjs
Normal file
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* @author arnydo [arnydo@protonmail.com]
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import {URL_REGEX, DOMAIN_REGEX} from "../lib/Extract";
|
||||
|
||||
/**
|
||||
* DefangURL operation
|
||||
*/
|
||||
class DefangURL extends Operation {
|
||||
|
||||
/**
|
||||
* DefangURL constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Defang URL";
|
||||
this.module = "Default";
|
||||
this.description = "Takes a Universal Resource Locator (URL) and 'Defangs' it; meaning the URL becomes invalid, neutralising the risk of accidentally clicking on a malicious link.<br><br>This is often used when dealing with malicious links or IOCs.<br><br>Works well when combined with the 'Extract URLs' operation.";
|
||||
this.infoURL = "https://isc.sans.edu/forums/diary/Defang+all+the+things/22744/";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "Escape dots",
|
||||
type: "boolean",
|
||||
value: true
|
||||
},
|
||||
{
|
||||
name: "Escape http",
|
||||
type: "boolean",
|
||||
value: true
|
||||
},
|
||||
{
|
||||
name: "Escape ://",
|
||||
type: "boolean",
|
||||
value: true
|
||||
},
|
||||
{
|
||||
name: "Process",
|
||||
type: "option",
|
||||
value: ["Valid domains and full URLs", "Only full URLs", "Everything"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [dots, http, slashes, process] = args;
|
||||
|
||||
switch (process) {
|
||||
case "Valid domains and full URLs":
|
||||
input = input.replace(URL_REGEX, x => {
|
||||
return defangURL(x, dots, http, slashes);
|
||||
});
|
||||
input = input.replace(DOMAIN_REGEX, x => {
|
||||
return defangURL(x, dots, http, slashes);
|
||||
});
|
||||
break;
|
||||
case "Only full URLs":
|
||||
input = input.replace(URL_REGEX, x => {
|
||||
return defangURL(x, dots, http, slashes);
|
||||
});
|
||||
break;
|
||||
case "Everything":
|
||||
input = defangURL(input, dots, http, slashes);
|
||||
break;
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Defangs a given URL
|
||||
*
|
||||
* @param {string} url
|
||||
* @param {boolean} dots
|
||||
* @param {boolean} http
|
||||
* @param {boolean} slashes
|
||||
* @returns {string}
|
||||
*/
|
||||
function defangURL(url, dots, http, slashes) {
|
||||
if (dots) url = url.replace(/\./g, "[.]");
|
||||
if (http) url = url.replace(/http/gi, "hxxp");
|
||||
if (slashes) url = url.replace(/:\/\//g, "[://]");
|
||||
|
||||
return url;
|
||||
}
|
||||
|
||||
export default DefangURL;
|
||||
@@ -5,7 +5,6 @@
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
|
||||
/**
|
||||
* Drop bytes operation
|
||||
@@ -20,7 +19,7 @@ class DropBytes extends Operation {
|
||||
|
||||
this.name = "Drop bytes";
|
||||
this.module = "Default";
|
||||
this.description = "Cuts a slice of the specified number of bytes out of the data.";
|
||||
this.description = "Cuts a slice of the specified number of bytes out of the data. Negative values are allowed.";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "ArrayBuffer";
|
||||
this.args = [
|
||||
@@ -50,14 +49,25 @@ class DropBytes extends Operation {
|
||||
* @throws {OperationError} if invalid input
|
||||
*/
|
||||
run(input, args) {
|
||||
const start = args[0],
|
||||
length = args[1],
|
||||
applyToEachLine = args[2];
|
||||
|
||||
if (start < 0 || length < 0)
|
||||
throw new OperationError("Error: Invalid value");
|
||||
let start = args[0],
|
||||
length = args[1];
|
||||
const applyToEachLine = args[2];
|
||||
|
||||
if (!applyToEachLine) {
|
||||
if (start < 0) { // Take from the end
|
||||
start = input.byteLength + start;
|
||||
}
|
||||
|
||||
if (length < 0) { // Flip start point
|
||||
start = start + length;
|
||||
if (start < 0) {
|
||||
start = input.byteLength + start;
|
||||
length = start - length;
|
||||
} else {
|
||||
length = -length;
|
||||
}
|
||||
}
|
||||
|
||||
const left = input.slice(0, start),
|
||||
right = input.slice(start + length, input.byteLength);
|
||||
const result = new Uint8Array(left.byteLength + right.byteLength);
|
||||
@@ -82,10 +92,28 @@ class DropBytes extends Operation {
|
||||
}
|
||||
lines.push(line);
|
||||
|
||||
let output = [];
|
||||
let output = [],
|
||||
s = start,
|
||||
l = length;
|
||||
for (i = 0; i < lines.length; i++) {
|
||||
output = output.concat(lines[i].slice(0, start).concat(lines[i].slice(start+length, lines[i].length)));
|
||||
if (s < 0) { // Take from the end
|
||||
s = lines[i].length + s;
|
||||
}
|
||||
|
||||
if (l < 0) { // Flip start point
|
||||
s = s + l;
|
||||
if (s < 0) {
|
||||
s = lines[i].length + s;
|
||||
l = s - l;
|
||||
} else {
|
||||
l = -l;
|
||||
}
|
||||
}
|
||||
|
||||
output = output.concat(lines[i].slice(0, s).concat(lines[i].slice(s+l, lines[i].length)));
|
||||
output.push(0x0a);
|
||||
s = start;
|
||||
l = length;
|
||||
}
|
||||
return new Uint8Array(output.slice(0, output.length-1)).buffer;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import { search } from "../lib/Extract";
|
||||
import { search, DOMAIN_REGEX } from "../lib/Extract";
|
||||
|
||||
/**
|
||||
* Extract domains operation
|
||||
@@ -38,10 +38,8 @@ class ExtractDomains extends Operation {
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const displayTotal = args[0],
|
||||
regex = /\b((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,63}\b/ig;
|
||||
|
||||
return search(input, regex, null, displayTotal);
|
||||
const displayTotal = args[0];
|
||||
return search(input, DOMAIN_REGEX, null, displayTotal);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -39,8 +39,8 @@ class ExtractEmailAddresses extends Operation {
|
||||
*/
|
||||
run(input, args) {
|
||||
const displayTotal = args[0],
|
||||
regex = /\b\w[-.\w]*@[-\w]+(?:\.[-\w]+)*\.[A-Z]{2,4}\b/ig;
|
||||
|
||||
// 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;
|
||||
return search(input, regex, null, displayTotal);
|
||||
}
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import { search } from "../lib/Extract";
|
||||
import { search, URL_REGEX } from "../lib/Extract";
|
||||
|
||||
/**
|
||||
* Extract URLs operation
|
||||
@@ -38,16 +38,8 @@ class ExtractURLs extends Operation {
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const displayTotal = args[0],
|
||||
protocol = "[A-Z]+://",
|
||||
hostname = "[-\\w]+(?:\\.\\w[-\\w]*)+",
|
||||
port = ":\\d+";
|
||||
let path = "/[^.!,?\"<>\\[\\]{}\\s\\x7F-\\xFF]*";
|
||||
|
||||
path += "(?:[.!,?]+[^.!,?\"<>\\[\\]{}\\s\\x7F-\\xFF]+)*";
|
||||
const regex = new RegExp(protocol + hostname + "(?:" + port +
|
||||
")?(?:" + path + ")?", "ig");
|
||||
return search(input, regex, null, displayTotal);
|
||||
const displayTotal = args[0];
|
||||
return search(input, URL_REGEX, null, displayTotal);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import {INPUT_DELIM_OPTIONS} from "../lib/Delim";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import XRegExp from "xregexp";
|
||||
|
||||
/**
|
||||
* Filter operation
|
||||
@@ -21,7 +22,7 @@ class Filter extends Operation {
|
||||
super();
|
||||
|
||||
this.name = "Filter";
|
||||
this.module = "Default";
|
||||
this.module = "Regex";
|
||||
this.description = "Splits up the input using the specified delimiter and then filters each branch based on a regular expression.";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
@@ -55,7 +56,7 @@ class Filter extends Operation {
|
||||
let regex;
|
||||
|
||||
try {
|
||||
regex = new RegExp(args[1]);
|
||||
regex = new XRegExp(args[1]);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Invalid regex. Details: ${err.message}`);
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import XRegExp from "xregexp";
|
||||
|
||||
/**
|
||||
* Find / Replace operation
|
||||
@@ -50,6 +51,11 @@ class FindReplace extends Operation {
|
||||
"name": "Multiline matching",
|
||||
"type": "boolean",
|
||||
"value": true
|
||||
},
|
||||
{
|
||||
"name": "Dot matches all",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
}
|
||||
];
|
||||
}
|
||||
@@ -60,16 +66,17 @@ class FindReplace extends Operation {
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [{option: type}, replace, g, i, m] = args;
|
||||
const [{option: type}, replace, g, i, m, s] = args;
|
||||
let find = args[0].string,
|
||||
modifiers = "";
|
||||
|
||||
if (g) modifiers += "g";
|
||||
if (i) modifiers += "i";
|
||||
if (m) modifiers += "m";
|
||||
if (s) modifiers += "s";
|
||||
|
||||
if (type === "Regex") {
|
||||
find = new RegExp(find, modifiers);
|
||||
find = new XRegExp(find, modifiers);
|
||||
return input.replace(find, replace);
|
||||
}
|
||||
|
||||
@@ -77,7 +84,7 @@ class FindReplace extends Operation {
|
||||
find = Utils.parseEscapedChars(find);
|
||||
}
|
||||
|
||||
find = new RegExp(Utils.escapeRegex(find), modifiers);
|
||||
find = new XRegExp(Utils.escapeRegex(find), modifiers);
|
||||
|
||||
return input.replace(find, replace);
|
||||
}
|
||||
|
||||
@@ -71,6 +71,11 @@ class FromBase58 extends Operation {
|
||||
|
||||
if (input.length === 0) return [];
|
||||
|
||||
let zeroPrefix = 0;
|
||||
for (let i = 0; i < input.length && input[i] === alphabet[0]; i++) {
|
||||
zeroPrefix++;
|
||||
}
|
||||
|
||||
[].forEach.call(input, function(c, charIndex) {
|
||||
const index = alphabet.indexOf(c);
|
||||
|
||||
@@ -98,6 +103,10 @@ class FromBase58 extends Operation {
|
||||
}
|
||||
});
|
||||
|
||||
while (zeroPrefix--) {
|
||||
result.push(0);
|
||||
}
|
||||
|
||||
return result.reverse();
|
||||
}
|
||||
|
||||
|
||||
58
src/core/operations/FromBase62.mjs
Normal file
58
src/core/operations/FromBase62.mjs
Normal file
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* @author tcode2k16 [tcode2k16@gmail.com]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import BigNumber from "bignumber.js";
|
||||
import Utils from "../Utils";
|
||||
|
||||
|
||||
/**
|
||||
* From Base62 operation
|
||||
*/
|
||||
class FromBase62 extends Operation {
|
||||
|
||||
/**
|
||||
* FromBase62 constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "From Base62";
|
||||
this.module = "Default";
|
||||
this.description = "Base62 is a notation for encoding arbitrary byte data using a restricted set of symbols that can be conveniently used by humans and processed by computers. The high number base results in shorter strings than with the decimal or hexadecimal system.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/List_of_numeral_systems";
|
||||
this.inputType = "string";
|
||||
this.outputType = "byteArray";
|
||||
this.args = [
|
||||
{
|
||||
name: "Alphabet",
|
||||
type: "string",
|
||||
value: "0-9A-Za-z"
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
run(input, args) {
|
||||
if (input.length < 1) return [];
|
||||
const ALPHABET = Utils.expandAlphRange(args[0]).join("");
|
||||
const BN = BigNumber.clone({ ALPHABET });
|
||||
|
||||
const re = new RegExp("[^" + ALPHABET.replace(/[[\]\\\-^$]/g, "\\$&") + "]", "g");
|
||||
input = input.replace(re, "");
|
||||
|
||||
const number = new BN(input, 62);
|
||||
|
||||
return Utils.convertToByteArray(number.toString(16), "Hex");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default FromBase62;
|
||||
@@ -38,44 +38,44 @@ class FromBase64 extends Operation {
|
||||
];
|
||||
this.patterns = [
|
||||
{
|
||||
match: "^(?:[A-Z\\d+/]{4})+(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?$",
|
||||
match: "^\\s*(?:[A-Z\\d+/]{4})+(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
|
||||
flags: "i",
|
||||
args: ["A-Za-z0-9+/=", false]
|
||||
args: ["A-Za-z0-9+/=", true]
|
||||
},
|
||||
{
|
||||
match: "^[A-Z\\d\\-_]{20,}$",
|
||||
match: "^\\s*[A-Z\\d\\-_]{20,}\\s*$",
|
||||
flags: "i",
|
||||
args: ["A-Za-z0-9-_", false]
|
||||
args: ["A-Za-z0-9-_", true]
|
||||
},
|
||||
{
|
||||
match: "^(?:[A-Z\\d+\\-]{4}){5,}(?:[A-Z\\d+\\-]{2}==|[A-Z\\d+\\-]{3}=)?$",
|
||||
match: "^\\s*(?:[A-Z\\d+\\-]{4}){5,}(?:[A-Z\\d+\\-]{2}==|[A-Z\\d+\\-]{3}=)?\\s*$",
|
||||
flags: "i",
|
||||
args: ["A-Za-z0-9+\\-=", false]
|
||||
args: ["A-Za-z0-9+\\-=", true]
|
||||
},
|
||||
{
|
||||
match: "^(?:[A-Z\\d./]{4}){5,}(?:[A-Z\\d./]{2}==|[A-Z\\d./]{3}=)?$",
|
||||
match: "^\\s*(?:[A-Z\\d./]{4}){5,}(?:[A-Z\\d./]{2}==|[A-Z\\d./]{3}=)?\\s*$",
|
||||
flags: "i",
|
||||
args: ["./0-9A-Za-z=", false]
|
||||
args: ["./0-9A-Za-z=", true]
|
||||
},
|
||||
{
|
||||
match: "^[A-Z\\d_.]{20,}$",
|
||||
match: "^\\s*[A-Z\\d_.]{20,}\\s*$",
|
||||
flags: "i",
|
||||
args: ["A-Za-z0-9_.", false]
|
||||
args: ["A-Za-z0-9_.", true]
|
||||
},
|
||||
{
|
||||
match: "^(?:[A-Z\\d._]{4}){5,}(?:[A-Z\\d._]{2}--|[A-Z\\d._]{3}-)?$",
|
||||
match: "^\\s*(?:[A-Z\\d._]{4}){5,}(?:[A-Z\\d._]{2}--|[A-Z\\d._]{3}-)?\\s*$",
|
||||
flags: "i",
|
||||
args: ["A-Za-z0-9._-", false]
|
||||
args: ["A-Za-z0-9._-", true]
|
||||
},
|
||||
{
|
||||
match: "^(?:[A-Z\\d+/]{4}){5,}(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?$",
|
||||
match: "^\\s*(?:[A-Z\\d+/]{4}){5,}(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
|
||||
flags: "i",
|
||||
args: ["0-9a-zA-Z+/=", false]
|
||||
args: ["0-9a-zA-Z+/=", true]
|
||||
},
|
||||
{
|
||||
match: "^(?:[A-Z\\d+/]{4}){5,}(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?$",
|
||||
match: "^\\s*(?:[A-Z\\d+/]{4}){5,}(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
|
||||
flags: "i",
|
||||
args: ["0-9A-Za-z+/=", false]
|
||||
args: ["0-9A-Za-z+/=", true]
|
||||
},
|
||||
{
|
||||
match: "^[ !\"#$%&'()*+,\\-./\\d:;<=>?@A-Z[\\\\\\]^_]{20,}$",
|
||||
@@ -83,24 +83,24 @@ class FromBase64 extends Operation {
|
||||
args: [" -_", false]
|
||||
},
|
||||
{
|
||||
match: "^[A-Z\\d+\\-]{20,}$",
|
||||
match: "^\\s*[A-Z\\d+\\-]{20,}\\s*$",
|
||||
flags: "i",
|
||||
args: ["+\\-0-9A-Za-z", false]
|
||||
args: ["+\\-0-9A-Za-z", true]
|
||||
},
|
||||
{
|
||||
match: "^[!\"#$%&'()*+,\\-0-689@A-NP-VX-Z[`a-fh-mp-r]{20,}$",
|
||||
match: "^\\s*[!\"#$%&'()*+,\\-0-689@A-NP-VX-Z[`a-fh-mp-r]{20,}\\s*$",
|
||||
flags: "",
|
||||
args: ["!-,-0-689@A-NP-VX-Z[`a-fh-mp-r", false]
|
||||
args: ["!-,-0-689@A-NP-VX-Z[`a-fh-mp-r", true]
|
||||
},
|
||||
{
|
||||
match: "^(?:[N-ZA-M\\d+/]{4}){5,}(?:[N-ZA-M\\d+/]{2}==|[N-ZA-M\\d+/]{3}=)?$",
|
||||
match: "^\\s*(?:[N-ZA-M\\d+/]{4}){5,}(?:[N-ZA-M\\d+/]{2}==|[N-ZA-M\\d+/]{3}=)?\\s*$",
|
||||
flags: "i",
|
||||
args: ["N-ZA-Mn-za-m0-9+/=", false]
|
||||
args: ["N-ZA-Mn-za-m0-9+/=", true]
|
||||
},
|
||||
{
|
||||
match: "^[A-Z\\d./]{20,}$",
|
||||
match: "^\\s*[A-Z\\d./]{20,}\\s*$",
|
||||
flags: "i",
|
||||
args: ["./0-9A-Za-z", false]
|
||||
args: ["./0-9A-Za-z", true]
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
105
src/core/operations/FromBase85.mjs
Normal file
105
src/core/operations/FromBase85.mjs
Normal file
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* @author PenguinGeorge [george@penguingeorge.com]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import Utils from "../Utils";
|
||||
import {alphabetName, ALPHABET_OPTIONS} from "../lib/Base85";
|
||||
|
||||
/**
|
||||
* From Base85 operation
|
||||
*/
|
||||
class FromBase85 extends Operation {
|
||||
|
||||
/**
|
||||
* From Base85 constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "From Base85";
|
||||
this.module = "Default";
|
||||
this.description = "Base85 (also called Ascii85) is a notation for encoding arbitrary byte data. It is usually more efficient that Base64.<br><br>This operation decodes data from an ASCII string (with an alphabet of your choosing, presets included).<br><br>e.g. <code>BOu!rD]j7BEbo7</code> becomes <code>hello world</code><br><br>Base85 is commonly used in Adobe's PostScript and PDF file formats.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Ascii85";
|
||||
this.inputType = "string";
|
||||
this.outputType = "byteArray";
|
||||
this.args = [
|
||||
{
|
||||
name: "Alphabet",
|
||||
type: "editableOption",
|
||||
value: ALPHABET_OPTIONS
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
run(input, args) {
|
||||
const alphabet = Utils.expandAlphRange(args[0]).join(""),
|
||||
encoding = alphabetName(alphabet),
|
||||
result = [];
|
||||
|
||||
if (alphabet.length !== 85 ||
|
||||
[].unique.call(alphabet).length !== 85) {
|
||||
throw new OperationError("Alphabet must be of length 85");
|
||||
}
|
||||
|
||||
if (input.length === 0) return [];
|
||||
|
||||
const matches = input.match(/<~(.+?)~>/);
|
||||
if (matches !== null) input = matches[1];
|
||||
|
||||
let i = 0;
|
||||
let block, blockBytes;
|
||||
while (i < input.length) {
|
||||
if (encoding === "Standard" && input[i] === "z") {
|
||||
result.push(0, 0, 0, 0);
|
||||
i++;
|
||||
} else {
|
||||
let digits = [];
|
||||
digits = input
|
||||
.substr(i, 5)
|
||||
.split("")
|
||||
.map((chr, idx) => {
|
||||
const digit = alphabet.indexOf(chr);
|
||||
if (digit < 0 || digit > 84) {
|
||||
throw `Invalid character '${chr}' at index ${idx}`;
|
||||
}
|
||||
return digit;
|
||||
});
|
||||
|
||||
block =
|
||||
digits[0] * 52200625 +
|
||||
digits[1] * 614125 +
|
||||
(i + 2 < input.length ? digits[2] : 84) * 7225 +
|
||||
(i + 3 < input.length ? digits[3] : 84) * 85 +
|
||||
(i + 4 < input.length ? digits[4] : 84);
|
||||
|
||||
blockBytes = [
|
||||
(block >> 24) & 0xff,
|
||||
(block >> 16) & 0xff,
|
||||
(block >> 8) & 0xff,
|
||||
block & 0xff
|
||||
];
|
||||
|
||||
if (input.length < i + 5) {
|
||||
blockBytes.splice(input.length - (i + 5), 5);
|
||||
}
|
||||
|
||||
result.push.apply(result, blockBytes);
|
||||
i += 5;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default FromBase85;
|
||||
@@ -7,6 +7,7 @@
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import {BIN_DELIM_OPTIONS} from "../lib/Delim";
|
||||
import {fromBinary} from "../lib/Binary";
|
||||
|
||||
/**
|
||||
* From Binary operation
|
||||
@@ -77,15 +78,7 @@ class FromBinary extends Operation {
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
run(input, args) {
|
||||
const delimRegex = Utils.regexRep(args[0] || "Space");
|
||||
input = input.replace(delimRegex, "");
|
||||
|
||||
const output = [];
|
||||
const byteLen = 8;
|
||||
for (let i = 0; i < input.length; i += byteLen) {
|
||||
output.push(parseInt(input.substr(i, byteLen), 2));
|
||||
}
|
||||
return output;
|
||||
return fromBinary(input, args[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
70
src/core/operations/FromBraille.mjs
Normal file
70
src/core/operations/FromBraille.mjs
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import {BRAILLE_LOOKUP} from "../lib/Braille";
|
||||
|
||||
/**
|
||||
* From Braille operation
|
||||
*/
|
||||
class FromBraille extends Operation {
|
||||
|
||||
/**
|
||||
* FromBraille constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "From Braille";
|
||||
this.module = "Default";
|
||||
this.description = "Converts six-dot braille symbols to text.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Braille";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
return input.split("").map(b => {
|
||||
const idx = BRAILLE_LOOKUP.dot6.indexOf(b);
|
||||
return idx < 0 ? b : BRAILLE_LOOKUP.ascii[idx];
|
||||
}).join("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight From Braille
|
||||
*
|
||||
* @param {Object[]} pos
|
||||
* @param {number} pos[].start
|
||||
* @param {number} pos[].end
|
||||
* @param {Object[]} args
|
||||
* @returns {Object[]} pos
|
||||
*/
|
||||
highlight(pos, args) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight From Braille in reverse
|
||||
*
|
||||
* @param {Object[]} pos
|
||||
* @param {number} pos[].start
|
||||
* @param {number} pos[].end
|
||||
* @param {Object[]} args
|
||||
* @returns {Object[]} pos
|
||||
*/
|
||||
highlightReverse(pos, args) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default FromBraille;
|
||||
@@ -29,38 +29,43 @@ class FromDecimal extends Operation {
|
||||
"name": "Delimiter",
|
||||
"type": "option",
|
||||
"value": DELIM_OPTIONS
|
||||
},
|
||||
{
|
||||
"name": "Support signed values",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
}
|
||||
];
|
||||
this.patterns = [
|
||||
{
|
||||
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]))*$",
|
||||
flags: "",
|
||||
args: ["Space"]
|
||||
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]))*$",
|
||||
flags: "",
|
||||
args: ["Comma"]
|
||||
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]))*$",
|
||||
flags: "",
|
||||
args: ["Semi-colon"]
|
||||
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]))*$",
|
||||
flags: "",
|
||||
args: ["Colon"]
|
||||
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]))*$",
|
||||
flags: "",
|
||||
args: ["Line feed"]
|
||||
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]))*$",
|
||||
flags: "",
|
||||
args: ["CRLF"]
|
||||
args: ["CRLF", false]
|
||||
},
|
||||
];
|
||||
}
|
||||
@@ -71,7 +76,11 @@ class FromDecimal extends Operation {
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
run(input, args) {
|
||||
return fromDecimal(input, args[0]);
|
||||
let data = fromDecimal(input, args[0]);
|
||||
if (args[1]) { // Convert negatives
|
||||
data = data.map(v => v < 0 ? 0xFF + v + 1 : v);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
44
src/core/operations/FromGeohash.mjs
Normal file
44
src/core/operations/FromGeohash.mjs
Normal file
@@ -0,0 +1,44 @@
|
||||
/**
|
||||
* @author gchq77703 []
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import geohash from "ngeohash";
|
||||
|
||||
/**
|
||||
* From Geohash operation
|
||||
*/
|
||||
class FromGeohash extends Operation {
|
||||
|
||||
/**
|
||||
* FromGeohash constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "From Geohash";
|
||||
this.module = "Hashing";
|
||||
this.description = "Converts Geohash strings into Lat/Long coordinates. For example, <code>ww8p1r4t8</code> becomes <code>37.8324,112.5584</code>.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Geohash";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
return input.split("\n").map(line => {
|
||||
const coords = geohash.decode(line);
|
||||
return [coords.latitude, coords.longitude].join(",");
|
||||
}).join("\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default FromGeohash;
|
||||
47
src/core/operations/FromMessagePack.mjs
Normal file
47
src/core/operations/FromMessagePack.mjs
Normal file
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* @author Matt C [matt@artemisbot.uk]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import notepack from "notepack.io";
|
||||
|
||||
/**
|
||||
* From MessagePack operation
|
||||
*/
|
||||
class FromMessagePack extends Operation {
|
||||
|
||||
/**
|
||||
* FromMessagePack constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "From MessagePack";
|
||||
this.module = "Code";
|
||||
this.description = "Converts MessagePack encoded data to JSON. MessagePack is a computer data interchange format. It is a binary form for representing simple data structures like arrays and associative arrays.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/MessagePack";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "JSON";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {JSON}
|
||||
*/
|
||||
run(input, args) {
|
||||
try {
|
||||
const buf = Buffer.from(new Uint8Array(input));
|
||||
return notepack.decode(buf);
|
||||
} catch (err) {
|
||||
throw new OperationError(`Could not decode MessagePack to JSON: ${err}`);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default FromMessagePack;
|
||||
@@ -30,7 +30,7 @@ class FromQuotedPrintable extends Operation {
|
||||
this.args = [];
|
||||
this.patterns = [
|
||||
{
|
||||
match: "^[\\x21-\\x3d\\x3f-\\x7e \\t]*(?:=[\\da-f]{2}|=\\r?\\n)(?:[\\x21-\\x3d\\x3f-\\x7e \\t]|=[\\da-f]{2}|=\\r?\\n)*$",
|
||||
match: "^[\\x21-\\x3d\\x3f-\\x7e \\t]{0,76}(?:=[\\da-f]{2}|=\\r?\\n)(?:[\\x21-\\x3d\\x3f-\\x7e \\t]|=[\\da-f]{2}|=\\r?\\n)*$",
|
||||
flags: "i",
|
||||
args: []
|
||||
},
|
||||
|
||||
119
src/core/operations/GenerateQRCode.mjs
Normal file
119
src/core/operations/GenerateQRCode.mjs
Normal file
@@ -0,0 +1,119 @@
|
||||
/**
|
||||
* @author j433866 [j433866@gmail.com]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import qr from "qr-image";
|
||||
import { toBase64 } from "../lib/Base64";
|
||||
import Magic from "../lib/Magic";
|
||||
import Utils from "../Utils";
|
||||
|
||||
/**
|
||||
* Generate QR Code operation
|
||||
*/
|
||||
class GenerateQRCode extends Operation {
|
||||
|
||||
/**
|
||||
* GenerateQRCode constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Generate QR Code";
|
||||
this.module = "Image";
|
||||
this.description = "Generates a Quick Response (QR) code from the input text.<br><br>A QR code is a type of matrix barcode (or two-dimensional barcode) first designed in 1994 for the automotive industry in Japan. A barcode is a machine-readable optical label that contains information about the item to which it is attached.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/QR_code";
|
||||
this.inputType = "string";
|
||||
this.outputType = "byteArray";
|
||||
this.presentType = "html";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Image Format",
|
||||
"type": "option",
|
||||
"value": ["PNG", "SVG", "EPS", "PDF"]
|
||||
},
|
||||
{
|
||||
"name": "Module size (px)",
|
||||
"type": "number",
|
||||
"value": 5
|
||||
},
|
||||
{
|
||||
"name": "Margin (num modules)",
|
||||
"type": "number",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"name": "Error correction",
|
||||
"type": "option",
|
||||
"value": ["Low", "Medium", "Quartile", "High"],
|
||||
"defaultIndex": 1
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [format, size, margin, errorCorrection] = args;
|
||||
|
||||
// Create new QR image from the input data, and convert it to a buffer
|
||||
const qrImage = qr.imageSync(input, {
|
||||
type: format,
|
||||
size: size,
|
||||
margin: margin,
|
||||
"ec_level": errorCorrection.charAt(0).toUpperCase()
|
||||
});
|
||||
|
||||
if (qrImage == null) {
|
||||
throw new OperationError("Error generating QR code.");
|
||||
}
|
||||
|
||||
switch (format) {
|
||||
case "SVG":
|
||||
case "EPS":
|
||||
case "PDF":
|
||||
return [...Buffer.from(qrImage)];
|
||||
case "PNG":
|
||||
// Return the QR image buffer as a byte array
|
||||
return [...qrImage];
|
||||
default:
|
||||
throw new OperationError("Unsupported QR code format.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the QR image using HTML for web apps
|
||||
*
|
||||
* @param {byteArray} data
|
||||
* @returns {html}
|
||||
*/
|
||||
present(data, args) {
|
||||
if (!data.length) return "";
|
||||
|
||||
const [format] = args;
|
||||
|
||||
if (format === "PNG") {
|
||||
let dataURI = "data:";
|
||||
const type = Magic.magicFileType(data);
|
||||
if (type && type.mime.indexOf("image") === 0){
|
||||
dataURI += type.mime + ";";
|
||||
} else {
|
||||
throw new OperationError("Invalid PNG file generated by QR image");
|
||||
}
|
||||
dataURI += "base64," + toBase64(data);
|
||||
|
||||
return `<img src="${dataURI}">`;
|
||||
}
|
||||
|
||||
return Utils.byteArrayToChars(data);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default GenerateQRCode;
|
||||
@@ -28,8 +28,9 @@ class HMAC extends Operation {
|
||||
this.args = [
|
||||
{
|
||||
"name": "Key",
|
||||
"type": "binaryString",
|
||||
"value": ""
|
||||
"type": "toggleString",
|
||||
"value": "",
|
||||
"toggleValues": ["Hex", "Decimal", "Base64", "UTF8", "Latin1"]
|
||||
},
|
||||
{
|
||||
"name": "Hashing function",
|
||||
@@ -66,19 +67,12 @@ class HMAC extends Operation {
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const key = args[0],
|
||||
const key = Utils.convertToByteString(args[0].string || "", args[0].option),
|
||||
hashFunc = args[1].toLowerCase(),
|
||||
msg = Utils.arrayBufferToStr(input, false),
|
||||
hasher = CryptoApi.getHasher(hashFunc);
|
||||
|
||||
// Horrible shim to fix constructor bug. Reported in nf404/crypto-api#8
|
||||
hasher.reset = () => {
|
||||
hasher.state = {};
|
||||
const tmp = new hasher.constructor();
|
||||
hasher.state = tmp.state;
|
||||
};
|
||||
|
||||
const mac = CryptoApi.getHmac(CryptoApi.encoder.fromUtf(key), hasher);
|
||||
const mac = CryptoApi.getHmac(key, hasher);
|
||||
mac.update(msg);
|
||||
return CryptoApi.encoder.toHex(mac.finalize());
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @author Phillip Nordwall [phillip.nordwall@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
@@ -27,7 +28,12 @@ class JSONBeautify extends Operation {
|
||||
{
|
||||
"name": "Indent string",
|
||||
"type": "binaryShortString",
|
||||
"value": "\\t"
|
||||
"value": " "
|
||||
},
|
||||
{
|
||||
"name": "Sort Object Keys",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
}
|
||||
];
|
||||
}
|
||||
@@ -38,11 +44,35 @@ class JSONBeautify extends Operation {
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const indentStr = args[0];
|
||||
const [indentStr, sortBool] = args;
|
||||
|
||||
if (!input) return "";
|
||||
if (sortBool) {
|
||||
input = JSON.stringify(JSONBeautify._sort(JSON.parse(input)));
|
||||
}
|
||||
return vkbeautify.json(input, indentStr);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sort JSON representation of an object
|
||||
*
|
||||
* @author Phillip Nordwall [phillip.nordwall@gmail.com]
|
||||
* @private
|
||||
* @param {object} o
|
||||
* @returns {object}
|
||||
*/
|
||||
static _sort(o) {
|
||||
if (Array.isArray(o)) {
|
||||
return o.map(JSONBeautify._sort);
|
||||
} else if ("[object Object]" === Object.prototype.toString.call(o)) {
|
||||
return Object.keys(o).sort().reduce(function(a, k) {
|
||||
a[k] = JSONBeautify._sort(o[k]);
|
||||
return a;
|
||||
}, {});
|
||||
}
|
||||
return o;
|
||||
}
|
||||
}
|
||||
|
||||
export default JSONBeautify;
|
||||
|
||||
111
src/core/operations/JSONToCSV.mjs
Normal file
111
src/core/operations/JSONToCSV.mjs
Normal file
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
|
||||
/**
|
||||
* JSON to CSV operation
|
||||
*/
|
||||
class JSONToCSV extends Operation {
|
||||
|
||||
/**
|
||||
* JSONToCSV constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "JSON to CSV";
|
||||
this.module = "Default";
|
||||
this.description = "Converts JSON data to a CSV based on the definition in RFC 4180.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Comma-separated_values";
|
||||
this.inputType = "JSON";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "Cell delimiter",
|
||||
type: "binaryShortString",
|
||||
value: ","
|
||||
},
|
||||
{
|
||||
name: "Row delimiter",
|
||||
type: "binaryShortString",
|
||||
value: "\\r\\n"
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {JSON} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [cellDelim, rowDelim] = args;
|
||||
|
||||
// Record values so they don't have to be passed to other functions explicitly
|
||||
this.cellDelim = cellDelim;
|
||||
this.rowDelim = rowDelim;
|
||||
const self = this;
|
||||
|
||||
try {
|
||||
// If the JSON is an array of arrays, this is easy
|
||||
if (input[0] instanceof Array) {
|
||||
return input
|
||||
.map(row => row
|
||||
.map(self.escapeCellContents.bind(self))
|
||||
.join(cellDelim)
|
||||
)
|
||||
.join(rowDelim) +
|
||||
rowDelim;
|
||||
}
|
||||
|
||||
// If it's an array of dictionaries...
|
||||
const header = Object.keys(input[0]);
|
||||
return header
|
||||
.map(self.escapeCellContents.bind(self))
|
||||
.join(cellDelim) +
|
||||
rowDelim +
|
||||
input
|
||||
.map(row => header
|
||||
.map(h => row[h])
|
||||
.map(self.escapeCellContents.bind(self))
|
||||
.join(cellDelim)
|
||||
)
|
||||
.join(rowDelim) +
|
||||
rowDelim;
|
||||
} catch (err) {
|
||||
throw new OperationError("Unable to parse JSON to CSV: " + err.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Correctly escapes a cell's contents based on the cell and row delimiters.
|
||||
*
|
||||
* @param {string} data
|
||||
* @returns {string}
|
||||
*/
|
||||
escapeCellContents(data) {
|
||||
// Double quotes should be doubled up
|
||||
data = data.replace(/"/g, '""');
|
||||
|
||||
// If the cell contains a cell or row delimiter or a double quote, it mut be enclosed in double quotes
|
||||
if (
|
||||
data.indexOf(this.cellDelim) >= 0 ||
|
||||
data.indexOf(this.rowDelim) >= 0 ||
|
||||
data.indexOf("\n") >= 0 ||
|
||||
data.indexOf("\r") >= 0 ||
|
||||
data.indexOf('"') >= 0
|
||||
) {
|
||||
data = `"${data}"`;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default JSONToCSV;
|
||||
51
src/core/operations/JWTDecode.mjs
Normal file
51
src/core/operations/JWTDecode.mjs
Normal file
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* @author gchq77703 []
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import jwt from "jsonwebtoken";
|
||||
import OperationError from "../errors/OperationError";
|
||||
|
||||
/**
|
||||
* JWT Decode operation
|
||||
*/
|
||||
class JWTDecode extends Operation {
|
||||
|
||||
/**
|
||||
* JWTDecode constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "JWT Decode";
|
||||
this.module = "Crypto";
|
||||
this.description = "Decodes a JSON Web Token <b>without</b> checking whether the provided secret / private key is valid. Use 'JWT Verify' to check if the signature is valid as well.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/JSON_Web_Token";
|
||||
this.inputType = "string";
|
||||
this.outputType = "JSON";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {JSON}
|
||||
*/
|
||||
run(input, args) {
|
||||
try {
|
||||
const decoded = jwt.decode(input, {
|
||||
json: true,
|
||||
complete: true
|
||||
});
|
||||
|
||||
return decoded.payload;
|
||||
} catch (err) {
|
||||
throw new OperationError(err);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default JWTDecode;
|
||||
74
src/core/operations/JWTSign.mjs
Normal file
74
src/core/operations/JWTSign.mjs
Normal file
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* @author gchq77703 []
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import jwt from "jsonwebtoken";
|
||||
import OperationError from "../errors/OperationError";
|
||||
|
||||
/**
|
||||
* JWT Sign operation
|
||||
*/
|
||||
class JWTSign extends Operation {
|
||||
|
||||
/**
|
||||
* JWTSign constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "JWT Sign";
|
||||
this.module = "Crypto";
|
||||
this.description = "Signs a JSON object as a JSON Web Token using a provided secret / private key.<br><br>The key should be either the secret for HMAC algorithms or the PEM-encoded private key for RSA and ECDSA.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/JSON_Web_Token";
|
||||
this.inputType = "JSON";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "Private/Secret Key",
|
||||
type: "text",
|
||||
value: "secret"
|
||||
},
|
||||
{
|
||||
name: "Signing algorithm",
|
||||
type: "option",
|
||||
value: [
|
||||
"HS256",
|
||||
"HS384",
|
||||
"HS512",
|
||||
"RS256",
|
||||
"RS384",
|
||||
"RS512",
|
||||
"ES256",
|
||||
"ES384",
|
||||
"ES512",
|
||||
"None"
|
||||
]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {JSON} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [key, algorithm] = args;
|
||||
|
||||
try {
|
||||
return jwt.sign(input, key, {
|
||||
algorithm: algorithm === "None" ? "none" : algorithm
|
||||
});
|
||||
} catch (err) {
|
||||
throw new OperationError(`Error: Have you entered the key correctly? The key should be either the secret for HMAC algorithms or the PEM-encoded private key for RSA and ECDSA.
|
||||
|
||||
${err}`);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default JWTSign;
|
||||
65
src/core/operations/JWTVerify.mjs
Normal file
65
src/core/operations/JWTVerify.mjs
Normal file
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* @author gchq77703 []
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import jwt from "jsonwebtoken";
|
||||
import OperationError from "../errors/OperationError";
|
||||
|
||||
/**
|
||||
* JWT Verify operation
|
||||
*/
|
||||
class JWTVerify extends Operation {
|
||||
|
||||
/**
|
||||
* JWTVerify constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "JWT Verify";
|
||||
this.module = "Crypto";
|
||||
this.description = "Verifies that a JSON Web Token is valid and has been signed with the provided secret / private key.<br><br>The key should be either the secret for HMAC algorithms or the PEM-encoded private key for RSA and ECDSA.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/JSON_Web_Token";
|
||||
this.inputType = "string";
|
||||
this.outputType = "JSON";
|
||||
this.args = [
|
||||
{
|
||||
name: "Private/Secret Key",
|
||||
type: "text",
|
||||
value: "secret"
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [key] = args;
|
||||
|
||||
try {
|
||||
const verified = jwt.verify(input, key, { algorithms: [
|
||||
"HS256",
|
||||
"HS384",
|
||||
"HS512",
|
||||
"none"
|
||||
]});
|
||||
|
||||
if (verified.hasOwnProperty("name") && verified.name === "JsonWebTokenError") {
|
||||
throw new OperationError(verified.message);
|
||||
}
|
||||
|
||||
return verified;
|
||||
} catch (err) {
|
||||
throw new OperationError(err);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default JWTVerify;
|
||||
@@ -23,7 +23,7 @@ class Magic extends Operation {
|
||||
this.name = "Magic";
|
||||
this.flowControl = true;
|
||||
this.module = "Default";
|
||||
this.description = "The Magic operation attempts to detect various properties of the input data and suggests which operations could help to make more sense of it.<br><br><b>Options</b><br><u>Depth:</u> If an operation appears to match the data, it will be run and the result will be analysed further. This argument controls the maximum number of levels of recursion.<br><br><u>Intensive mode:</u> When this is turned on, various operations like XOR, bit rotates, and character encodings are brute-forced to attempt to detect valid data underneath. To improve performance, only the first 100 bytes of the data is brute-forced.<br><br><u>Extensive language support:</u> At each stage, the relative byte frequencies of the data will be compared to average frequencies for a number of languages. The default set consists of ~40 of the most commonly used languages on the Internet. The extensive list consists of 284 languages and can result in many languages matching the data if their byte frequencies are similar.";
|
||||
this.description = "The Magic operation attempts to detect various properties of the input data and suggests which operations could help to make more sense of it.<br><br><b>Options</b><br><u>Depth:</u> If an operation appears to match the data, it will be run and the result will be analysed further. This argument controls the maximum number of levels of recursion.<br><br><u>Intensive mode:</u> When this is turned on, various operations like XOR, bit rotates, and character encodings are brute-forced to attempt to detect valid data underneath. To improve performance, only the first 100 bytes of the data is brute-forced.<br><br><u>Extensive language support:</u> At each stage, the relative byte frequencies of the data will be compared to average frequencies for a number of languages. The default set consists of ~40 of the most commonly used languages on the Internet. The extensive list consists of 284 languages and can result in many languages matching the data if their byte frequencies are similar.<br><br>Optionally enter a regular expression to match a string you expect to find to filter results (crib).";
|
||||
this.infoURL = "https://github.com/gchq/CyberChef/wiki/Automatic-detection-of-encoded-data-using-CyberChef-Magic";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "JSON";
|
||||
@@ -43,6 +43,11 @@ class Magic extends Operation {
|
||||
"name": "Extensive language support",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
},
|
||||
{
|
||||
"name": "Crib (known plaintext string or regex)",
|
||||
"type": "string",
|
||||
"value": ""
|
||||
}
|
||||
];
|
||||
}
|
||||
@@ -56,10 +61,16 @@ class Magic extends Operation {
|
||||
*/
|
||||
async run(state) {
|
||||
const ings = state.opList[state.progress].ingValues,
|
||||
[depth, intensive, extLang] = ings,
|
||||
[depth, intensive, extLang, crib] = ings,
|
||||
dish = state.dish,
|
||||
magic = new MagicLib(await dish.get(Dish.ARRAY_BUFFER)),
|
||||
options = await magic.speculativeExecution(depth, extLang, intensive);
|
||||
cribRegex = (crib && crib.length) ? new RegExp(crib, "i") : null;
|
||||
let options = await magic.speculativeExecution(depth, extLang, intensive, [], false, cribRegex);
|
||||
|
||||
// Filter down to results which matched the crib
|
||||
if (cribRegex) {
|
||||
options = options.filter(option => option.matchesCrib);
|
||||
}
|
||||
|
||||
// Record the current state for use when presenting
|
||||
this.state = state;
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import { bitOp, or } from "../lib/BitwiseOp";
|
||||
import { bitOp, or, BITWISE_OP_DELIMS } from "../lib/BitwiseOp";
|
||||
|
||||
/**
|
||||
* OR operation
|
||||
@@ -30,7 +30,7 @@ class OR extends Operation {
|
||||
"name": "Key",
|
||||
"type": "toggleString",
|
||||
"value": "",
|
||||
"toggleValues": ["Hex", "Decimal", "Base64", "UTF8", "Latin1"]
|
||||
"toggleValues": BITWISE_OP_DELIMS
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1,12 +1,13 @@
|
||||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @author Klaxon [klaxon@veyr.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import {ipv4CidrRange, ipv4HyphenatedRange, ipv6CidrRange, ipv6HyphenatedRange} from "../lib/IP";
|
||||
import {ipv4CidrRange, ipv4HyphenatedRange, ipv4ListedRange, ipv6CidrRange, ipv6HyphenatedRange, ipv6ListedRange} from "../lib/IP";
|
||||
|
||||
/**
|
||||
* Parse IP range operation
|
||||
@@ -21,7 +22,7 @@ class ParseIPRange extends Operation {
|
||||
|
||||
this.name = "Parse IP range";
|
||||
this.module = "JSBN";
|
||||
this.description = "Given a CIDR range (e.g. <code>10.0.0.0/24</code>) or a hyphenated range (e.g. <code>10.0.0.0 - 10.0.1.0</code>), this operation provides network information and enumerates all IP addresses in the range.<br><br>IPv6 is supported but will not be enumerated.";
|
||||
this.description = "Given a CIDR range (e.g. <code>10.0.0.0/24</code>), hyphenated range (e.g. <code>10.0.0.0 - 10.0.1.0</code>), or a list of IPs and/or CIDR ranges (separated by a new line), this operation provides network information and enumerates all IP addresses in the range.<br><br>IPv6 is supported but will not be enumerated.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Subnetwork";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
@@ -59,18 +60,24 @@ class ParseIPRange extends Operation {
|
||||
// Check what type of input we are looking at
|
||||
const ipv4CidrRegex = /^\s*((?:\d{1,3}\.){3}\d{1,3})\/(\d\d?)\s*$/,
|
||||
ipv4RangeRegex = /^\s*((?:\d{1,3}\.){3}\d{1,3})\s*-\s*((?:\d{1,3}\.){3}\d{1,3})\s*$/,
|
||||
ipv4ListRegex = /^\s*(((?:\d{1,3}\.){3}\d{1,3})(\/(\d\d?))?(\n|$)(\n*))+\s*$/,
|
||||
ipv6CidrRegex = /^\s*(((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\4)::|:\b|(?![\dA-F])))|(?!\3\4)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4}))\/(\d\d?\d?)\s*$/i,
|
||||
ipv6RangeRegex = /^\s*(((?=.*::)(?!.*::[^-]+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\4)::|:\b|(?![\dA-F])))|(?!\3\4)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4}))\s*-\s*(((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\17)::|:\b|(?![\dA-F])))|(?!\16\17)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4}))\s*$/i;
|
||||
ipv6RangeRegex = /^\s*(((?=.*::)(?!.*::[^-]+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\4)::|:\b|(?![\dA-F])))|(?!\3\4)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4}))\s*-\s*(((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\17)::|:\b|(?![\dA-F])))|(?!\16\17)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4}))\s*$/i,
|
||||
ipv6ListRegex = /^\s*((((?=.*::)(?!.*::.+::)(::)?([\dA-F]{1,4}:(:|\b)|){5}|([\dA-F]{1,4}:){6})((([\dA-F]{1,4}((?!\4)::|:\b|(?![\dA-F])))|(?!\3\4)){2}|(((2[0-4]|1\d|[1-9])?\d|25[0-5])\.?\b){4}))(\/(\d\d?\d?))?(\n|$)(\n*))+\s*$/i;
|
||||
let match;
|
||||
|
||||
if ((match = ipv4CidrRegex.exec(input))) {
|
||||
return ipv4CidrRange(match, includeNetworkInfo, enumerateAddresses, allowLargeList);
|
||||
} else if ((match = ipv4RangeRegex.exec(input))) {
|
||||
return ipv4HyphenatedRange(match, includeNetworkInfo, enumerateAddresses, allowLargeList);
|
||||
} else if ((match = ipv4ListRegex.exec(input))) {
|
||||
return ipv4ListedRange(match, includeNetworkInfo, enumerateAddresses, allowLargeList);
|
||||
} else if ((match = ipv6CidrRegex.exec(input))) {
|
||||
return ipv6CidrRange(match, includeNetworkInfo);
|
||||
} else if ((match = ipv6RangeRegex.exec(input))) {
|
||||
return ipv6HyphenatedRange(match, includeNetworkInfo);
|
||||
} else if ((match = ipv6ListRegex.exec(input))) {
|
||||
return ipv6ListedRange(match, includeNetworkInfo);
|
||||
} else {
|
||||
throw new OperationError("Invalid input.\n\nEnter either a CIDR range (e.g. 10.0.0.0/24) or a hyphenated range (e.g. 10.0.0.0 - 10.0.1.0). IPv6 also supported.");
|
||||
}
|
||||
|
||||
107
src/core/operations/ParseQRCode.mjs
Normal file
107
src/core/operations/ParseQRCode.mjs
Normal file
@@ -0,0 +1,107 @@
|
||||
/**
|
||||
* @author j433866 [j433866@gmail.com]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import Magic from "../lib/Magic";
|
||||
import jsqr from "jsqr";
|
||||
import jimp from "jimp";
|
||||
|
||||
/**
|
||||
* Parse QR Code operation
|
||||
*/
|
||||
class ParseQRCode extends Operation {
|
||||
|
||||
/**
|
||||
* ParseQRCode constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Parse QR Code";
|
||||
this.module = "Image";
|
||||
this.description = "Reads an image file and attempts to detect and read a Quick Response (QR) code from the image.<br><br><u>Normalise Image</u><br>Attempts to normalise the image before parsing it to improve detection of a QR code.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/QR_code";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Normalise image",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
async run(input, args) {
|
||||
const type = Magic.magicFileType(input);
|
||||
const [normalise] = args;
|
||||
|
||||
// Make sure that the input is an image
|
||||
if (type && type.mime.indexOf("image") === 0) {
|
||||
let image = input;
|
||||
|
||||
if (normalise) {
|
||||
// Process the image to be easier to read by jsqr
|
||||
// Disables the alpha channel
|
||||
// Sets the image default background to white
|
||||
// Normalises the image colours
|
||||
// Makes the image greyscale
|
||||
// Converts image to a JPEG
|
||||
image = await new Promise((resolve, reject) => {
|
||||
jimp.read(Buffer.from(input))
|
||||
.then(image => {
|
||||
image
|
||||
.rgba(false)
|
||||
.background(0xFFFFFFFF)
|
||||
.normalize()
|
||||
.greyscale()
|
||||
.getBuffer(jimp.MIME_JPEG, (error, result) => {
|
||||
resolve(result);
|
||||
});
|
||||
})
|
||||
.catch(err => {
|
||||
reject(new OperationError("Error reading the image file."));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
if (image instanceof OperationError) {
|
||||
throw image;
|
||||
}
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
jimp.read(Buffer.from(image))
|
||||
.then(image => {
|
||||
if (image.bitmap != null) {
|
||||
const qrData = jsqr(image.bitmap.data, image.getWidth(), image.getHeight());
|
||||
if (qrData != null) {
|
||||
resolve(qrData.data);
|
||||
} else {
|
||||
reject(new OperationError("Couldn't read a QR code from the image."));
|
||||
}
|
||||
} else {
|
||||
reject(new OperationError("Error reading the image file."));
|
||||
}
|
||||
})
|
||||
.catch(err => {
|
||||
reject(new OperationError("Error reading the image file."));
|
||||
});
|
||||
});
|
||||
} else {
|
||||
throw new OperationError("Invalid file type.");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ParseQRCode;
|
||||
76
src/core/operations/ParseTLV.mjs
Normal file
76
src/core/operations/ParseTLV.mjs
Normal file
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* @author gchq77703 []
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import TLVParser from "../lib/TLVParser";
|
||||
import OperationError from "../errors/OperationError";
|
||||
|
||||
/**
|
||||
* Parse TLV operation
|
||||
*/
|
||||
class ParseTLV extends Operation {
|
||||
|
||||
/**
|
||||
* ParseTLV constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Parse TLV";
|
||||
this.module = "Default";
|
||||
this.description = "Converts a Type-Length-Value (TLV) encoded string into a JSON object. Can optionally include a <code>Key</code> / <code>Type</code> entry. <br><br>Tags: Key-Length-Value, KLV, Length-Value, LV";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Type-length-value";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "JSON";
|
||||
this.args = [
|
||||
{
|
||||
name: "Type/Key size",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Length size",
|
||||
type: "number",
|
||||
value: 1
|
||||
},
|
||||
{
|
||||
name: "Use BER",
|
||||
type: "boolean",
|
||||
value: false
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [bytesInKey, bytesInLength, basicEncodingRules] = args;
|
||||
|
||||
if (bytesInKey <= 0 && bytesInLength <= 0)
|
||||
throw new OperationError("Type or Length size must be greater than 0");
|
||||
|
||||
const tlv = new TLVParser(input, { bytesInLength, basicEncodingRules });
|
||||
|
||||
const data = [];
|
||||
|
||||
while (!tlv.atEnd()) {
|
||||
const key = bytesInKey ? tlv.getValue(bytesInKey) : undefined;
|
||||
const length = tlv.getLength();
|
||||
const value = tlv.getValue(length);
|
||||
|
||||
data.push({ key, length, value });
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ParseTLV;
|
||||
102
src/core/operations/PlayMedia.mjs
Normal file
102
src/core/operations/PlayMedia.mjs
Normal file
@@ -0,0 +1,102 @@
|
||||
/**
|
||||
* @author anthony-arnold [anthony.arnold@uqconnect.edu.au]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import { fromBase64, toBase64 } from "../lib/Base64";
|
||||
import { fromHex } from "../lib/Hex";
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import Utils from "../Utils";
|
||||
import Magic from "../lib/Magic";
|
||||
|
||||
/**
|
||||
* PlayMedia operation
|
||||
*/
|
||||
class PlayMedia extends Operation {
|
||||
|
||||
/**
|
||||
* PlayMedia constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Play Media";
|
||||
this.module = "Default";
|
||||
this.description = "Plays the input as audio or video depending on the type.<br><br>Tags: sound, movie, mp3, mp4, mov, webm, wav, ogg";
|
||||
this.infoURL = "";
|
||||
this.inputType = "string";
|
||||
this.outputType = "byteArray";
|
||||
this.presentType = "html";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Input format",
|
||||
"type": "option",
|
||||
"value": ["Raw", "Base64", "Hex"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {byteArray} The multimedia data as bytes.
|
||||
*/
|
||||
run(input, args) {
|
||||
const [inputFormat] = args;
|
||||
|
||||
if (!input.length) return [];
|
||||
|
||||
// Convert input to raw bytes
|
||||
switch (inputFormat) {
|
||||
case "Hex":
|
||||
input = fromHex(input);
|
||||
break;
|
||||
case "Base64":
|
||||
// Don't trust the Base64 entered by the user.
|
||||
// Unwrap it first, then re-encode later.
|
||||
input = fromBase64(input, undefined, "byteArray");
|
||||
break;
|
||||
case "Raw":
|
||||
default:
|
||||
input = Utils.strToByteArray(input);
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// Determine file type
|
||||
const type = Magic.magicFileType(input);
|
||||
if (!(type && /^audio|video/.test(type.mime))) {
|
||||
throw new OperationError("Invalid or unrecognised file type");
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays an audio or video element that may be able to play the media
|
||||
* file.
|
||||
*
|
||||
* @param data {byteArray} Data containing an audio or video file.
|
||||
* @returns {string} Markup to display a media player.
|
||||
*/
|
||||
async present(data) {
|
||||
if (!data.length) return "";
|
||||
|
||||
const type = Magic.magicFileType(data);
|
||||
const matches = /^audio|video/.exec(type.mime);
|
||||
if (!matches) {
|
||||
throw new OperationError("Invalid file type");
|
||||
}
|
||||
const dataURI = `data:${type.mime};base64,${toBase64(data)}`;
|
||||
const element = matches[0];
|
||||
|
||||
let html = `<${element} src='${dataURI}' type='${type.mime}' controls>`;
|
||||
html += "<p>Unsupported media type.</p>";
|
||||
html += `</${element}>`;
|
||||
return html;
|
||||
}
|
||||
}
|
||||
|
||||
export default PlayMedia;
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Dish from "../Dish";
|
||||
import XRegExp from "xregexp";
|
||||
|
||||
/**
|
||||
* Register operation
|
||||
@@ -20,7 +21,7 @@ class Register extends Operation {
|
||||
|
||||
this.name = "Register";
|
||||
this.flowControl = true;
|
||||
this.module = "Default";
|
||||
this.module = "Regex";
|
||||
this.description = "Extract data from the input and store it in registers which can then be passed into subsequent operations as arguments. Regular expression capture groups are used to select the data to extract.<br><br>To use registers in arguments, refer to them using the notation <code>$Rn</code> where n is the register number, starting at 0.<br><br>For example:<br>Input: <code>Test</code><br>Extractor: <code>(.*)</code><br>Argument: <code>$R0</code> becomes <code>Test</code><br><br>Registers can be escaped in arguments using a backslash. e.g. <code>\\$R0</code> would become <code>$R0</code> rather than <code>Test</code>.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Regular_expression#Syntax";
|
||||
this.inputType = "string";
|
||||
@@ -40,6 +41,11 @@ class Register extends Operation {
|
||||
"name": "Multiline matching",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
},
|
||||
{
|
||||
"name": "Dot matches all",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
}
|
||||
];
|
||||
}
|
||||
@@ -53,13 +59,14 @@ class Register extends Operation {
|
||||
*/
|
||||
async run(state) {
|
||||
const ings = state.opList[state.progress].ingValues;
|
||||
const [extractorStr, i, m] = ings;
|
||||
const [extractorStr, i, m, s] = ings;
|
||||
|
||||
let modifiers = "";
|
||||
if (i) modifiers += "i";
|
||||
if (m) modifiers += "m";
|
||||
if (s) modifiers += "s";
|
||||
|
||||
const extractor = new RegExp(extractorStr, modifiers),
|
||||
const extractor = new XRegExp(extractorStr, modifiers),
|
||||
input = await state.dish.get(Dish.STRING),
|
||||
registers = input.match(extractor);
|
||||
|
||||
|
||||
@@ -227,6 +227,7 @@ function regexList (input, regex, displayTotal, matches, captureGroups) {
|
||||
*/
|
||||
function regexHighlight (input, regex, displayTotal) {
|
||||
let output = "",
|
||||
title = "",
|
||||
m,
|
||||
hl = 1,
|
||||
i = 0,
|
||||
@@ -241,8 +242,16 @@ function regexHighlight (input, regex, displayTotal) {
|
||||
// Add up to match
|
||||
output += Utils.escapeHtml(input.slice(i, m.index));
|
||||
|
||||
title = `Offset: ${m.index}\n`;
|
||||
if (m.length > 1) {
|
||||
title += "Groups:\n";
|
||||
for (let n = 1; n < m.length; ++n) {
|
||||
title += `\t${n}: ${m[n]}\n`;
|
||||
}
|
||||
}
|
||||
|
||||
// Add match with highlighting
|
||||
output += "<span class='hl"+hl+"'>" + Utils.escapeHtml(m[0]) + "</span>";
|
||||
output += "<span class='hl"+hl+"' title='"+title+"'>" + Utils.escapeHtml(m[0]) + "</span>";
|
||||
|
||||
// Switch highlight
|
||||
hl = hl === 1 ? 2 : 1;
|
||||
|
||||
41
src/core/operations/RemoveDiacritics.mjs
Normal file
41
src/core/operations/RemoveDiacritics.mjs
Normal file
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* @author Klaxon [klaxon@veyr.com]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
|
||||
/**
|
||||
* Remove Diacritics operation
|
||||
*/
|
||||
class RemoveDiacritics extends Operation {
|
||||
|
||||
/**
|
||||
* RemoveDiacritics constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Remove Diacritics";
|
||||
this.module = "Default";
|
||||
this.description = "Replaces accented characters with their latin character equivalent.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Diacritic";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
// reference: https://stackoverflow.com/questions/990904/remove-accents-diacritics-in-a-string-in-javascript/37511463
|
||||
return input.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default RemoveDiacritics;
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import { bitOp, sub } from "../lib/BitwiseOp";
|
||||
import { bitOp, sub, BITWISE_OP_DELIMS } from "../lib/BitwiseOp";
|
||||
|
||||
/**
|
||||
* SUB operation
|
||||
@@ -30,7 +30,7 @@ class SUB extends Operation {
|
||||
"name": "Key",
|
||||
"type": "toggleString",
|
||||
"value": "",
|
||||
"toggleValues": ["Hex", "Decimal", "Base64", "UTF8", "Latin1"]
|
||||
"toggleValues": BITWISE_OP_DELIMS
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@ class Scrypt extends Operation {
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const salt = Utils.convertToByteString(args[0].string || "", args[0].option),
|
||||
const salt = Buffer.from(Utils.convertToByteArray(args[0].string || "", args[0].option)),
|
||||
iterations = args[1],
|
||||
memFactor = args[2],
|
||||
parallelFactor = args[3],
|
||||
|
||||
@@ -36,6 +36,11 @@ class ShowBase64Offsets extends Operation {
|
||||
name: "Show variable chars and padding",
|
||||
type: "boolean",
|
||||
value: true
|
||||
},
|
||||
{
|
||||
name: "Input format",
|
||||
type: "option",
|
||||
value: ["Raw", "Base64"]
|
||||
}
|
||||
];
|
||||
}
|
||||
@@ -46,7 +51,11 @@ class ShowBase64Offsets extends Operation {
|
||||
* @returns {html}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [alphabet, showVariable] = args;
|
||||
const [alphabet, showVariable, format] = args;
|
||||
|
||||
if (format === "Base64") {
|
||||
input = fromBase64(Utils.byteArrayToUtf8(input), null, "byteArray");
|
||||
}
|
||||
|
||||
let offset0 = toBase64(input, alphabet),
|
||||
offset1 = toBase64([0].concat(input), alphabet),
|
||||
|
||||
@@ -38,7 +38,7 @@ class Sort extends Operation {
|
||||
{
|
||||
"name": "Order",
|
||||
"type": "option",
|
||||
"value": ["Alphabetical (case sensitive)", "Alphabetical (case insensitive)", "IP address", "Numeric"]
|
||||
"value": ["Alphabetical (case sensitive)", "Alphabetical (case insensitive)", "IP address", "Numeric", "Numeric (hexadecimal)"]
|
||||
}
|
||||
];
|
||||
}
|
||||
@@ -62,6 +62,8 @@ class Sort extends Operation {
|
||||
sorted = sorted.sort(Sort._ipSort);
|
||||
} else if (order === "Numeric") {
|
||||
sorted = sorted.sort(Sort._numericSort);
|
||||
} else if (order === "Numeric (hexadecimal)") {
|
||||
sorted = sorted.sort(Sort._hexadecimalSort);
|
||||
}
|
||||
|
||||
if (sortReverse) sorted.reverse();
|
||||
@@ -131,6 +133,44 @@ class Sort extends Operation {
|
||||
return a.localeCompare(b);
|
||||
}
|
||||
|
||||
/**
|
||||
* Comparison operation for sorting of hexadecimal values.
|
||||
*
|
||||
* @author Chris van Marle
|
||||
* @private
|
||||
* @param {string} a
|
||||
* @param {string} b
|
||||
* @returns {number}
|
||||
*/
|
||||
static _hexadecimalSort(a, b) {
|
||||
let a_ = a.split(/([^\da-f]+)/i),
|
||||
b_ = b.split(/([^\da-f]+)/i);
|
||||
|
||||
a_ = a_.map(v => {
|
||||
const t = parseInt(v, 16);
|
||||
return isNaN(t) ? v : t;
|
||||
});
|
||||
|
||||
b_ = b_.map(v => {
|
||||
const t = parseInt(v, 16);
|
||||
return isNaN(t) ? v : t;
|
||||
});
|
||||
|
||||
for (let i = 0; i < a_.length && i < b.length; ++i) {
|
||||
if (isNaN(a_[i]) && !isNaN(b_[i])) return 1; // Numbers after non-numbers
|
||||
if (!isNaN(a_[i]) && isNaN(b_[i])) return -1;
|
||||
if (isNaN(a_[i]) && isNaN(b_[i])) {
|
||||
const ret = a_[i].localeCompare(b_[i]); // Compare strings
|
||||
if (ret !== 0) return ret;
|
||||
}
|
||||
if (!isNaN(a_[i]) && !isNaN(a_[i])) { // Compare numbers
|
||||
if (a_[i] - b_[i] !== 0) return a_[i] - b_[i];
|
||||
}
|
||||
}
|
||||
|
||||
return a.localeCompare(b);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Sort;
|
||||
|
||||
@@ -20,7 +20,7 @@ class Substitute extends Operation {
|
||||
|
||||
this.name = "Substitute";
|
||||
this.module = "Default";
|
||||
this.description = "A substitution cipher allowing you to specify bytes to replace with other byte values. This can be used to create Caesar ciphers but is more powerful as any byte value can be substituted, not just letters, and the substitution values need not be in order.<br><br>Enter the bytes you want to replace in the Plaintext field and the bytes to replace them with in the Ciphertext field.<br><br>Non-printable bytes can be specified using string escape notation. For example, a line feed character can be written as either <code>\n</code> or <code>\x0a</code>.<br><br>Byte ranges can be specified using a hyphen. For example, the sequence <code>0123456789</code> can be written as <code>0-9</code>.";
|
||||
this.description = "A substitution cipher allowing you to specify bytes to replace with other byte values. This can be used to create Caesar ciphers but is more powerful as any byte value can be substituted, not just letters, and the substitution values need not be in order.<br><br>Enter the bytes you want to replace in the Plaintext field and the bytes to replace them with in the Ciphertext field.<br><br>Non-printable bytes can be specified using string escape notation. For example, a line feed character can be written as either <code>\\n</code> or <code>\\x0a</code>.<br><br>Byte ranges can be specified using a hyphen. For example, the sequence <code>0123456789</code> can be written as <code>0-9</code>.<br><br>Note that blackslash characters are used to escape special characters, so will need to be escaped themselves if you want to use them on their own (e.g.<code>\\\\</code>).";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Substitution_cipher";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
|
||||
/**
|
||||
* Take bytes operation
|
||||
@@ -20,7 +19,7 @@ class TakeBytes extends Operation {
|
||||
|
||||
this.name = "Take bytes";
|
||||
this.module = "Default";
|
||||
this.description = "Takes a slice of the specified number of bytes from the data.";
|
||||
this.description = "Takes a slice of the specified number of bytes from the data. Negative values are allowed.";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "ArrayBuffer";
|
||||
this.args = [
|
||||
@@ -50,15 +49,27 @@ class TakeBytes extends Operation {
|
||||
* @throws {OperationError} if invalid value
|
||||
*/
|
||||
run(input, args) {
|
||||
const start = args[0],
|
||||
length = args[1],
|
||||
applyToEachLine = args[2];
|
||||
let start = args[0],
|
||||
length = args[1];
|
||||
const applyToEachLine = args[2];
|
||||
|
||||
if (start < 0 || length < 0)
|
||||
throw new OperationError("Error: Invalid value");
|
||||
if (!applyToEachLine) {
|
||||
if (start < 0) { // Take from the end
|
||||
start = input.byteLength + start;
|
||||
}
|
||||
|
||||
if (length < 0) { // Flip start point
|
||||
start = start + length;
|
||||
if (start < 0) {
|
||||
start = input.byteLength + start;
|
||||
length = start - length;
|
||||
} else {
|
||||
length = -length;
|
||||
}
|
||||
}
|
||||
|
||||
if (!applyToEachLine)
|
||||
return input.slice(start, start+length);
|
||||
}
|
||||
|
||||
// Split input into lines
|
||||
const data = new Uint8Array(input);
|
||||
@@ -77,9 +88,26 @@ class TakeBytes extends Operation {
|
||||
lines.push(line);
|
||||
|
||||
let output = [];
|
||||
let s = start,
|
||||
l = length;
|
||||
for (i = 0; i < lines.length; i++) {
|
||||
output = output.concat(lines[i].slice(start, start+length));
|
||||
if (s < 0) { // Take from the end
|
||||
s = lines[i].length + s;
|
||||
}
|
||||
|
||||
if (l < 0) { // Flip start point
|
||||
s = s + l;
|
||||
if (s < 0) {
|
||||
s = lines[i].length + s;
|
||||
l = s - l;
|
||||
} else {
|
||||
l = -l;
|
||||
}
|
||||
}
|
||||
output = output.concat(lines[i].slice(s, s+l));
|
||||
output.push(0x0a);
|
||||
s = start;
|
||||
l = length;
|
||||
}
|
||||
return new Uint8Array(output.slice(0, output.length-1)).buffer;
|
||||
}
|
||||
|
||||
92
src/core/operations/TextEncodingBruteForce.mjs
Normal file
92
src/core/operations/TextEncodingBruteForce.mjs
Normal file
@@ -0,0 +1,92 @@
|
||||
/**
|
||||
* @author Cynser
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import cptable from "../vendor/js-codepage/cptable.js";
|
||||
import {IO_FORMAT} from "../lib/ChrEnc";
|
||||
|
||||
/**
|
||||
* Text Encoding Brute Force operation
|
||||
*/
|
||||
class TextEncodingBruteForce extends Operation {
|
||||
|
||||
/**
|
||||
* TextEncodingBruteForce constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Text Encoding Brute Force";
|
||||
this.module = "CharEnc";
|
||||
this.description = [
|
||||
"Enumerates all supported text encodings for the input, allowing you to quickly spot the correct one.",
|
||||
"<br><br>",
|
||||
"Supported charsets are:",
|
||||
"<ul>",
|
||||
Object.keys(IO_FORMAT).map(e => `<li>${e}</li>`).join("\n"),
|
||||
"</ul>"
|
||||
].join("\n");
|
||||
this.infoURL = "https://wikipedia.org/wiki/Character_encoding";
|
||||
this.inputType = "string";
|
||||
this.outputType = "json";
|
||||
this.presentType = "html";
|
||||
this.args = [
|
||||
{
|
||||
name: "Mode",
|
||||
type: "option",
|
||||
value: ["Encode", "Decode"]
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {json}
|
||||
*/
|
||||
run(input, args) {
|
||||
const output = {},
|
||||
charsets = Object.keys(IO_FORMAT),
|
||||
mode = args[0];
|
||||
|
||||
charsets.forEach(charset => {
|
||||
try {
|
||||
if (mode === "Decode") {
|
||||
output[charset] = cptable.utils.decode(IO_FORMAT[charset], input);
|
||||
} else {
|
||||
output[charset] = Utils.arrayBufferToStr(cptable.utils.encode(IO_FORMAT[charset], input));
|
||||
}
|
||||
} catch (err) {
|
||||
output[charset] = "Could not decode.";
|
||||
}
|
||||
});
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the encodings in an HTML table for web apps.
|
||||
*
|
||||
* @param {Object[]} encodings
|
||||
* @returns {html}
|
||||
*/
|
||||
present(encodings) {
|
||||
let table = "<table class='table table-hover table-sm table-bordered table-nonfluid'><tr><th>Encoding</th><th>Value</th></tr>";
|
||||
|
||||
for (const enc in encodings) {
|
||||
const value = Utils.printable(encodings[enc], true);
|
||||
table += `<tr><td>${enc}</td><td>${value}</td></tr>`;
|
||||
}
|
||||
|
||||
table += "<table>";
|
||||
return table;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default TextEncodingBruteForce;
|
||||
@@ -53,6 +53,11 @@ class ToBase58 extends Operation {
|
||||
|
||||
if (input.length === 0) return "";
|
||||
|
||||
let zeroPrefix = 0;
|
||||
for (let i = 0; i < input.length && input[i] === 0; i++) {
|
||||
zeroPrefix++;
|
||||
}
|
||||
|
||||
input.forEach(function(b) {
|
||||
let carry = (result[0] << 8) + b;
|
||||
result[0] = carry % 58;
|
||||
@@ -74,7 +79,7 @@ class ToBase58 extends Operation {
|
||||
return alphabet[b];
|
||||
}).reverse().join("");
|
||||
|
||||
while (result.length < input.length) {
|
||||
while (zeroPrefix--) {
|
||||
result = alphabet[0] + result;
|
||||
}
|
||||
|
||||
|
||||
58
src/core/operations/ToBase62.mjs
Normal file
58
src/core/operations/ToBase62.mjs
Normal file
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* @author tcode2k16 [tcode2k16@gmail.com]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import BigNumber from "bignumber.js";
|
||||
import Utils from "../Utils";
|
||||
import {toHexFast} from "../lib/Hex";
|
||||
|
||||
/**
|
||||
* To Base62 operation
|
||||
*/
|
||||
class ToBase62 extends Operation {
|
||||
|
||||
/**
|
||||
* ToBase62 constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "To Base62";
|
||||
this.module = "Default";
|
||||
this.description = "Base62 is a notation for encoding arbitrary byte data using a restricted set of symbols that can be conveniently used by humans and processed by computers. The high number base results in shorter strings than with the decimal or hexadecimal system.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/List_of_numeral_systems";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "Alphabet",
|
||||
type: "string",
|
||||
value: "0-9A-Za-z"
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
if (input.length < 1) return "";
|
||||
|
||||
const ALPHABET = Utils.expandAlphRange(args[0]).join("");
|
||||
const BN = BigNumber.clone({ ALPHABET });
|
||||
|
||||
input = toHexFast(input).toUpperCase();
|
||||
|
||||
const number = new BN(input, 16);
|
||||
|
||||
return number.toString(62);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ToBase62;
|
||||
93
src/core/operations/ToBase85.mjs
Normal file
93
src/core/operations/ToBase85.mjs
Normal file
@@ -0,0 +1,93 @@
|
||||
/**
|
||||
* @author PenguinGeorge [george@penguingeorge.com]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError";
|
||||
import Utils from "../Utils";
|
||||
import {alphabetName, ALPHABET_OPTIONS} from "../lib/Base85";
|
||||
|
||||
/**
|
||||
* To Base85 operation
|
||||
*/
|
||||
class ToBase85 extends Operation {
|
||||
|
||||
/**
|
||||
* To Base85 constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "To Base85";
|
||||
this.module = "Default";
|
||||
this.description = "Base85 (also called Ascii85) is a notation for encoding arbitrary byte data. It is usually more efficient that Base64.<br><br>This operation encodes data in an ASCII string (with an alphabet of your choosing, presets included).<br><br>e.g. <code>hello world</code> becomes <code>BOu!rD]j7BEbo7</code><br><br>Base85 is commonly used in Adobe's PostScript and PDF file formats.<br><br><strong>Options</strong><br><u>Alphabet</u><ul><li>Standard - The standard alphabet, referred to as Ascii85</li><li>Z85 (ZeroMQ) - A string-safe variant of Base85, which avoids quote marks and backslash characters</li><li>IPv6 - A variant of Base85 suitable for encoding IPv6 addresses (RFC 1924)</li></ul><u>Include delimiter</u><br>Adds a '<~' and '~>' delimiter to the start and end of the data. This is standard for Adobe's implementation of Base85.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Ascii85";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "Alphabet",
|
||||
type: "editableOption",
|
||||
value: ALPHABET_OPTIONS
|
||||
},
|
||||
{
|
||||
name: "Include delimeter",
|
||||
type: "boolean",
|
||||
value: false
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const alphabet = Utils.expandAlphRange(args[0]).join(""),
|
||||
encoding = alphabetName(alphabet),
|
||||
includeDelim = args[1];
|
||||
let result = "";
|
||||
|
||||
if (alphabet.length !== 85 ||
|
||||
[].unique.call(alphabet).length !== 85) {
|
||||
throw new OperationError("Error: Alphabet must be of length 85");
|
||||
}
|
||||
|
||||
if (input.length === 0) return "";
|
||||
|
||||
let block;
|
||||
for (let i = 0; i < input.length; i += 4) {
|
||||
block = (
|
||||
((input[i]) << 24) +
|
||||
((input[i + 1] || 0) << 16) +
|
||||
((input[i + 2] || 0) << 8) +
|
||||
((input[i + 3] || 0))
|
||||
) >>> 0;
|
||||
|
||||
if (encoding !== "Standard" || block > 0) {
|
||||
let digits = [];
|
||||
for (let j = 0; j < 5; j++) {
|
||||
digits.push(block % 85);
|
||||
block = Math.floor(block / 85);
|
||||
}
|
||||
|
||||
digits = digits.reverse();
|
||||
|
||||
if (input.length < i + 4) {
|
||||
digits.splice(input.length - (i + 4), 4);
|
||||
}
|
||||
|
||||
result += digits.map(digit => alphabet[digit]).join("");
|
||||
} else {
|
||||
result += (encoding === "Standard") ? "z" : null;
|
||||
}
|
||||
}
|
||||
|
||||
return includeDelim ? `<~${result}~>` : result;
|
||||
}
|
||||
}
|
||||
|
||||
export default ToBase85;
|
||||
@@ -7,6 +7,7 @@
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import {BIN_DELIM_OPTIONS} from "../lib/Delim";
|
||||
import {toBinary} from "../lib/Binary";
|
||||
|
||||
/**
|
||||
* To Binary operation
|
||||
@@ -40,19 +41,7 @@ class ToBinary extends Operation {
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const delim = Utils.charRep(args[0] || "Space"),
|
||||
padding = 8;
|
||||
let output = "";
|
||||
|
||||
for (let i = 0; i < input.length; i++) {
|
||||
output += input[i].toString(2).padStart(padding, "0") + delim;
|
||||
}
|
||||
|
||||
if (delim.length) {
|
||||
return output.slice(0, -delim.length);
|
||||
} else {
|
||||
return output;
|
||||
}
|
||||
return toBinary(input, args[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
70
src/core/operations/ToBraille.mjs
Normal file
70
src/core/operations/ToBraille.mjs
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import {BRAILLE_LOOKUP} from "../lib/Braille";
|
||||
|
||||
/**
|
||||
* To Braille operation
|
||||
*/
|
||||
class ToBraille extends Operation {
|
||||
|
||||
/**
|
||||
* ToBraille constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "To Braille";
|
||||
this.module = "Default";
|
||||
this.description = "Converts text to six-dot braille symbols.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Braille";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
return input.split("").map(c => {
|
||||
const idx = BRAILLE_LOOKUP.ascii.indexOf(c.toUpperCase());
|
||||
return idx < 0 ? c : BRAILLE_LOOKUP.dot6[idx];
|
||||
}).join("");
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight To Braille
|
||||
*
|
||||
* @param {Object[]} pos
|
||||
* @param {number} pos[].start
|
||||
* @param {number} pos[].end
|
||||
* @param {Object[]} args
|
||||
* @returns {Object[]} pos
|
||||
*/
|
||||
highlight(pos, args) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Highlight To Braille in reverse
|
||||
*
|
||||
* @param {Object[]} pos
|
||||
* @param {number} pos[].start
|
||||
* @param {number} pos[].end
|
||||
* @param {Object[]} args
|
||||
* @returns {Object[]} pos
|
||||
*/
|
||||
highlightReverse(pos, args) {
|
||||
return pos;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ToBraille;
|
||||
@@ -30,6 +30,11 @@ class ToDecimal extends Operation {
|
||||
"name": "Delimiter",
|
||||
"type": "option",
|
||||
"value": DELIM_OPTIONS
|
||||
},
|
||||
{
|
||||
"name": "Support signed values",
|
||||
"type": "boolean",
|
||||
"value": false
|
||||
}
|
||||
];
|
||||
}
|
||||
@@ -40,7 +45,11 @@ class ToDecimal extends Operation {
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const delim = Utils.charRep(args[0]);
|
||||
const delim = Utils.charRep(args[0]),
|
||||
signed = args[1];
|
||||
if (signed) {
|
||||
input = input.map(v => v > 0x7F ? v - 0xFF - 1 : v);
|
||||
}
|
||||
return input.join(delim);
|
||||
}
|
||||
|
||||
|
||||
53
src/core/operations/ToGeohash.mjs
Normal file
53
src/core/operations/ToGeohash.mjs
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* @author gchq77703 []
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import geohash from "ngeohash";
|
||||
|
||||
/**
|
||||
* To Geohash operation
|
||||
*/
|
||||
class ToGeohash extends Operation {
|
||||
|
||||
/**
|
||||
* ToGeohash constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "To Geohash";
|
||||
this.module = "Hashing";
|
||||
this.description = "Converts Lat/Long coordinates into a Geohash string. For example, <code>37.8324,112.5584</code> becomes <code>ww8p1r4t8</code>.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Geohash";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [
|
||||
{
|
||||
name: "Precision",
|
||||
type: "number",
|
||||
value: 9
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const [precision] = args;
|
||||
|
||||
return input.split("\n").map(line => {
|
||||
line = line.replace(/ /g, "");
|
||||
if (line === "") return "";
|
||||
return geohash.encode(...line.split(",").map(num => parseFloat(num)), precision);
|
||||
}).join("\n");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ToGeohash;
|
||||
50
src/core/operations/ToMessagePack.mjs
Normal file
50
src/core/operations/ToMessagePack.mjs
Normal file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* @author Matt C [matt@artemisbot.uk]
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import OperationError from "../errors/OperationError.mjs";
|
||||
import notepack from "notepack.io";
|
||||
|
||||
/**
|
||||
* To MessagePack operation
|
||||
*/
|
||||
class ToMessagePack extends Operation {
|
||||
|
||||
/**
|
||||
* ToMessagePack constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "To MessagePack";
|
||||
this.module = "Code";
|
||||
this.description = "Converts JSON to MessagePack encoded byte buffer. MessagePack is a computer data interchange format. It is a binary form for representing simple data structures like arrays and associative arrays.";
|
||||
this.infoURL = "https://wikipedia.org/wiki/MessagePack";
|
||||
this.inputType = "JSON";
|
||||
this.outputType = "ArrayBuffer";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {JSON} input
|
||||
* @param {Object[]} args
|
||||
* @returns {ArrayBuffer}
|
||||
*/
|
||||
run(input, args) {
|
||||
try {
|
||||
if (ENVIRONMENT_IS_WORKER()) {
|
||||
return notepack.encode(input);
|
||||
} else {
|
||||
return notepack.encode(input).buffer;
|
||||
}
|
||||
} catch (err) {
|
||||
throw new OperationError(`Could not encode JSON to MessagePack: ${err}`);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ToMessagePack;
|
||||
@@ -33,7 +33,7 @@ class ToTable extends Operation {
|
||||
{
|
||||
"name": "Row delimiters",
|
||||
"type": "binaryShortString",
|
||||
"value": "\\n\\r"
|
||||
"value": "\\r\\n"
|
||||
},
|
||||
{
|
||||
"name": "Make first row header",
|
||||
|
||||
@@ -20,7 +20,7 @@ class Whirlpool extends Operation {
|
||||
|
||||
this.name = "Whirlpool";
|
||||
this.module = "Hashing";
|
||||
this.description = "Whirlpool is a cryptographic hash function designed by Vincent Rijmen (co-creator of AES) and Paulo S. L. M. Barreto, who first described it in 2000.<br><br>Several variants exist:<ul><li>Whirlpool-0 is the original version released in 2000.</li><li>Whirlpool-T is the first revision, released in 2001, improving the generation of the s-box.</li><li>Wirlpool is the latest revision, released in 2003, fixing a flaw in the difusion matrix.</li></ul>";
|
||||
this.description = "Whirlpool is a cryptographic hash function designed by Vincent Rijmen (co-creator of AES) and Paulo S. L. M. Barreto, who first described it in 2000.<br><br>Several variants exist:<ul><li>Whirlpool-0 is the original version released in 2000.</li><li>Whirlpool-T is the first revision, released in 2001, improving the generation of the s-box.</li><li>Whirlpool is the latest revision, released in 2003, fixing a flaw in the difusion matrix.</li></ul>";
|
||||
this.infoURL = "https://wikipedia.org/wiki/Whirlpool_(cryptography)";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "string";
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import { bitOp, xor } from "../lib/BitwiseOp";
|
||||
import { bitOp, xor, BITWISE_OP_DELIMS } from "../lib/BitwiseOp";
|
||||
|
||||
/**
|
||||
* XOR operation
|
||||
@@ -21,7 +21,7 @@ class XOR extends Operation {
|
||||
|
||||
this.name = "XOR";
|
||||
this.module = "Default";
|
||||
this.description = "XOR the input with the given key.<br>e.g. <code>fe023da5</code><br><br><strong>Options</strong><br><u>Null preserving:</u> If the current byte is 0x00 or the same as the key, skip it.<br><br><u>Scheme:</u><ul><li>Standard - key is unchanged after each round</li><li>Input differential - key is set to the value of the previous unprocessed byte</li><li>Output differential - key is set to the value of the previous processed byte</li></ul>";
|
||||
this.description = "XOR the input with the given key.<br>e.g. <code>fe023da5</code><br><br><strong>Options</strong><br><u>Null preserving:</u> If the current byte is 0x00 or the same as the key, skip it.<br><br><u>Scheme:</u><ul><li>Standard - key is unchanged after each round</li><li>Input differential - key is set to the value of the previous unprocessed byte</li><li>Output differential - key is set to the value of the previous processed byte</li><li>Cascade - key is set to the input byte shifted by one</li></ul>";
|
||||
this.infoURL = "https://wikipedia.org/wiki/XOR";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "byteArray";
|
||||
@@ -30,12 +30,12 @@ class XOR extends Operation {
|
||||
"name": "Key",
|
||||
"type": "toggleString",
|
||||
"value": "",
|
||||
"toggleValues": ["Hex", "Decimal", "Base64", "UTF8", "Latin1"]
|
||||
"toggleValues": BITWISE_OP_DELIMS
|
||||
},
|
||||
{
|
||||
"name": "Scheme",
|
||||
"type": "option",
|
||||
"value": ["Standard", "Input differential", "Output differential"]
|
||||
"value": ["Standard", "Input differential", "Output differential", "Cascade"]
|
||||
},
|
||||
{
|
||||
"name": "Null preserving",
|
||||
|
||||
@@ -262,4 +262,4 @@ bzip2.decompress = function(bits, size, len){
|
||||
return output;
|
||||
}
|
||||
|
||||
module.exports = bzip2;
|
||||
export default bzip2;
|
||||
@@ -67,6 +67,7 @@ class BackgroundWorkerWaiter {
|
||||
log.debug("Background ChefWorker loaded");
|
||||
break;
|
||||
case "optionUpdate":
|
||||
case "statusMessage":
|
||||
// Ignore these messages
|
||||
break;
|
||||
default:
|
||||
|
||||
@@ -26,6 +26,7 @@ class HTMLIngredient {
|
||||
this.disabled = config.disabled || false;
|
||||
this.hint = config.hint || false;
|
||||
this.target = config.target;
|
||||
this.defaultIndex = config.defaultIndex || 0;
|
||||
this.toggleValues = config.toggleValues;
|
||||
this.id = "ing-" + this.app.nextIngId();
|
||||
}
|
||||
@@ -133,7 +134,7 @@ class HTMLIngredient {
|
||||
} else if ((m = this.value[i].match(/\[\/([a-z0-9 -()^]+)\]/i))) {
|
||||
html += "</optgroup>";
|
||||
} else {
|
||||
html += `<option>${this.value[i]}</option>`;
|
||||
html += `<option ${this.defaultIndex === i ? "selected" : ""}>${this.value[i]}</option>`;
|
||||
}
|
||||
}
|
||||
html += `</select>
|
||||
@@ -170,7 +171,7 @@ class HTMLIngredient {
|
||||
class="form-control arg inline"
|
||||
id="${this.id}"
|
||||
arg-name="${this.name}"
|
||||
value="${this.value[0].value}"
|
||||
value="${this.value[this.defaultIndex].value}"
|
||||
${this.disabled ? "disabled" : ""}>
|
||||
${this.hint ? "<span class='bmd-help'>" + this.hint + "</span>" : ""}
|
||||
<div class="input-group-append inline">
|
||||
|
||||
@@ -131,14 +131,16 @@ class HTMLOperation {
|
||||
*/
|
||||
function titleFromWikiLink(url) {
|
||||
const splitURL = url.split("/");
|
||||
if (splitURL.indexOf("wiki") < 0) {
|
||||
if (splitURL.indexOf("wikipedia.org") < 0 && splitURL.indexOf("forensicswiki.org") < 0) {
|
||||
// Not a wiki link, return full URL
|
||||
return `<a href='${url}' target='_blank'>More Information<i class='material-icons inline-icon'>open_in_new</i></a>`;
|
||||
}
|
||||
|
||||
const wikiName = splitURL.indexOf("forensicswiki.org") < 0 ? "Wikipedia" : "Forensics Wiki";
|
||||
|
||||
const pageTitle = decodeURIComponent(splitURL[splitURL.length - 1])
|
||||
.replace(/_/g, " ");
|
||||
return `<a href='${url}' target='_blank'>${pageTitle}<i class='material-icons inline-icon'>open_in_new</i></a> on Wikipedia`;
|
||||
return `<a href='${url}' target='_blank'>${pageTitle}<i class='material-icons inline-icon'>open_in_new</i></a> on ${wikiName}`;
|
||||
}
|
||||
|
||||
export default HTMLOperation;
|
||||
|
||||
@@ -116,6 +116,13 @@ div.toggle-string {
|
||||
left: 12px;
|
||||
}
|
||||
|
||||
.operation label.bmd-label-floating {
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
width: calc(100% - 13px);
|
||||
}
|
||||
|
||||
.operation .bmd-form-group .bmd-help {
|
||||
margin-top: -17px;
|
||||
}
|
||||
@@ -172,6 +179,7 @@ div.toggle-string {
|
||||
background-color: var(--fc-operation-border-colour);
|
||||
font-family: var(--fixed-width-font-family);
|
||||
padding: 10px;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.op-icon {
|
||||
|
||||
@@ -24,46 +24,64 @@ global.ENVIRONMENT_IS_WEB = function() {
|
||||
};
|
||||
|
||||
import TestRegister from "./TestRegister";
|
||||
import "./tests/operations/BCD";
|
||||
import "./tests/operations/BSON";
|
||||
import "./tests/operations/Base58";
|
||||
import "./tests/operations/Base64";
|
||||
import "./tests/operations/BCD";
|
||||
import "./tests/operations/Base62";
|
||||
import "./tests/operations/BitwiseOp";
|
||||
import "./tests/operations/BSON";
|
||||
import "./tests/operations/ByteRepr";
|
||||
import "./tests/operations/CartesianProduct";
|
||||
import "./tests/operations/CharEnc";
|
||||
import "./tests/operations/Ciphers";
|
||||
import "./tests/operations/Checksum";
|
||||
import "./tests/operations/Ciphers";
|
||||
import "./tests/operations/Code";
|
||||
import "./tests/operations/Compress";
|
||||
import "./tests/operations/Crypt";
|
||||
import "./tests/operations/DateTime";
|
||||
import "./tests/operations/Fork";
|
||||
import "./tests/operations/Jump";
|
||||
import "./tests/operations/ConditionalJump";
|
||||
import "./tests/operations/Register";
|
||||
import "./tests/operations/Comment";
|
||||
import "./tests/operations/Compress";
|
||||
import "./tests/operations/ConditionalJump";
|
||||
import "./tests/operations/Crypt";
|
||||
import "./tests/operations/CSV";
|
||||
import "./tests/operations/DateTime";
|
||||
import "./tests/operations/ExtractEmailAddresses";
|
||||
import "./tests/operations/Fork";
|
||||
import "./tests/operations/FromDecimal";
|
||||
import "./tests/operations/FromGeohash";
|
||||
import "./tests/operations/Hash";
|
||||
import "./tests/operations/HaversineDistance";
|
||||
import "./tests/operations/Hexdump";
|
||||
import "./tests/operations/Image";
|
||||
import "./tests/operations/MorseCode";
|
||||
import "./tests/operations/Jump";
|
||||
import "./tests/operations/JSONBeautify";
|
||||
import "./tests/operations/JSONMinify";
|
||||
import "./tests/operations/JWTDecode";
|
||||
import "./tests/operations/JWTSign";
|
||||
import "./tests/operations/JWTVerify";
|
||||
import "./tests/operations/MS";
|
||||
import "./tests/operations/PGP";
|
||||
import "./tests/operations/PHP";
|
||||
import "./tests/operations/Magic";
|
||||
import "./tests/operations/MorseCode";
|
||||
import "./tests/operations/NetBIOS";
|
||||
import "./tests/operations/OTP";
|
||||
import "./tests/operations/PGP";
|
||||
import "./tests/operations/PHP";
|
||||
import "./tests/operations/ParseIPRange";
|
||||
import "./tests/operations/ParseQRCode";
|
||||
import "./tests/operations/PowerSet";
|
||||
import "./tests/operations/Regex";
|
||||
import "./tests/operations/Register";
|
||||
import "./tests/operations/RemoveDiacritics";
|
||||
import "./tests/operations/Rotate";
|
||||
import "./tests/operations/StrUtils";
|
||||
import "./tests/operations/SeqUtils";
|
||||
import "./tests/operations/SetDifference";
|
||||
import "./tests/operations/SetIntersection";
|
||||
import "./tests/operations/SetUnion";
|
||||
import "./tests/operations/StrUtils";
|
||||
import "./tests/operations/SymmetricDifference";
|
||||
import "./tests/operations/TextEncodingBruteForce";
|
||||
import "./tests/operations/ToGeohash.mjs";
|
||||
import "./tests/operations/TranslateDateTimeFormat";
|
||||
import "./tests/operations/Magic";
|
||||
import "./tests/operations/ParseTLV";
|
||||
import "./tests/operations/Media";
|
||||
|
||||
let allTestsPassing = true;
|
||||
const testStatusCounts = {
|
||||
@@ -115,12 +133,12 @@ function handleTestResult(testResult) {
|
||||
|
||||
|
||||
/**
|
||||
* Fail if the process takes longer than 10 seconds.
|
||||
* Fail if the process takes longer than 60 seconds.
|
||||
*/
|
||||
setTimeout(function() {
|
||||
console.log("Tests took longer than 10 seconds to run, returning.");
|
||||
console.log("Tests took longer than 60 seconds to run, returning.");
|
||||
process.exit(1);
|
||||
}, 10 * 1000);
|
||||
}, 60 * 1000);
|
||||
|
||||
|
||||
TestRegister.runTests()
|
||||
@@ -142,4 +160,3 @@ TestRegister.runTests()
|
||||
|
||||
process.exit(allTestsPassing ? 0 : 1);
|
||||
});
|
||||
|
||||
|
||||
@@ -53,6 +53,28 @@ TestRegister.addTests([
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "To Base58 with null prefix and suffix",
|
||||
input: "\0\0\0Hello\0\0\0",
|
||||
expectedOutput: "111D7LMXYjHjTu",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "To Base58",
|
||||
args: ["123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "From Base58 with null prefix and suffix",
|
||||
input: "111D7LMXYjHjTu",
|
||||
expectedOutput: "\0\0\0Hello\0\0\0",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "From Base58",
|
||||
args: ["123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "From Base58 (Bitcoin): 'StV1DL6CwTryKyV'",
|
||||
input: "StV1DL6CwTryKyV",
|
||||
|
||||
79
test/tests/operations/Base62.mjs
Normal file
79
test/tests/operations/Base62.mjs
Normal file
@@ -0,0 +1,79 @@
|
||||
/**
|
||||
* Base62 tests.
|
||||
*
|
||||
* @author tcode2k16 [tcode2k16@gmail.com]
|
||||
*
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import TestRegister from "../../TestRegister";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "To Base62: nothing",
|
||||
input: "",
|
||||
expectedOutput: "",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "To Base62",
|
||||
args: ["0-9A-Za-z"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "To Base62: Hello, World!",
|
||||
input: "Hello, World!",
|
||||
expectedOutput: "1wJfrzvdbtXUOlUjUf",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "To Base62",
|
||||
args: ["0-9A-Za-z"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "To Base62: UTF-8",
|
||||
input: "ნუ პანიკას",
|
||||
expectedOutput: "BPDNbjoGvDCDzHbKT77eWg0vGQrJuWRXltuRVZ",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "To Base62",
|
||||
args: ["0-9A-Za-z"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "From Base62: nothing",
|
||||
input: "",
|
||||
expectedOutput: "",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "From Base62",
|
||||
args: ["0-9A-Za-z"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "From Base62: Hello, World!",
|
||||
input: "1wJfrzvdbtXUOlUjUf",
|
||||
expectedOutput: "Hello, World!",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "From Base62",
|
||||
args: ["0-9A-Za-z"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "From Base62: UTF-8",
|
||||
input: "BPDNbjoGvDCDzHbKT77eWg0vGQrJuWRXltuRVZ",
|
||||
expectedOutput: "ნუ პანიკას",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "From Base62",
|
||||
args: ["0-9A-Za-z"],
|
||||
},
|
||||
],
|
||||
}
|
||||
]);
|
||||
179
test/tests/operations/CSV.mjs
Normal file
179
test/tests/operations/CSV.mjs
Normal file
@@ -0,0 +1,179 @@
|
||||
/**
|
||||
* CSV tests.
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
*
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
import TestRegister from "../../TestRegister";
|
||||
|
||||
const EXAMPLE_CSV = `A,B,C,D,E,F\r
|
||||
1,2,3,4,5,6\r
|
||||
",",;,',"""",,\r
|
||||
"""hello""","a""1","multi\r
|
||||
line",,,end\r
|
||||
`;
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "CSV to JSON: Array of dictionaries",
|
||||
input: EXAMPLE_CSV,
|
||||
expectedOutput: JSON.stringify([
|
||||
{
|
||||
"A": "1",
|
||||
"B": "2",
|
||||
"C": "3",
|
||||
"D": "4",
|
||||
"E": "5",
|
||||
"F": "6"
|
||||
},
|
||||
{
|
||||
"A": ",",
|
||||
"B": ";",
|
||||
"C": "'",
|
||||
"D": "\"",
|
||||
"E": "",
|
||||
"F": ""
|
||||
},
|
||||
{
|
||||
"A": "\"hello\"",
|
||||
"B": "a\"1",
|
||||
"C": "multi\r\nline",
|
||||
"D": "",
|
||||
"E": "",
|
||||
"F": "end"
|
||||
}
|
||||
], null, 4),
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "CSV to JSON",
|
||||
args: [",", "\r\n", "Array of dictionaries"],
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "CSV to JSON: Array of arrays",
|
||||
input: EXAMPLE_CSV,
|
||||
expectedOutput: JSON.stringify([
|
||||
[
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"D",
|
||||
"E",
|
||||
"F"
|
||||
],
|
||||
[
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5",
|
||||
"6"
|
||||
],
|
||||
[
|
||||
",",
|
||||
";",
|
||||
"'",
|
||||
"\"",
|
||||
"",
|
||||
""
|
||||
],
|
||||
[
|
||||
"\"hello\"",
|
||||
"a\"1",
|
||||
"multi\r\nline",
|
||||
"",
|
||||
"",
|
||||
"end"
|
||||
]
|
||||
], null, 4),
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "CSV to JSON",
|
||||
args: [",", "\r\n", "Array of arrays"],
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JSON to CSV: Array of dictionaries",
|
||||
input: JSON.stringify([
|
||||
{
|
||||
"A": "1",
|
||||
"B": "2",
|
||||
"C": "3",
|
||||
"D": "4",
|
||||
"E": "5",
|
||||
"F": "6"
|
||||
},
|
||||
{
|
||||
"A": ",",
|
||||
"B": ";",
|
||||
"C": "'",
|
||||
"D": "\"",
|
||||
"E": "",
|
||||
"F": ""
|
||||
},
|
||||
{
|
||||
"A": "\"hello\"",
|
||||
"B": "a\"1",
|
||||
"C": "multi\r\nline",
|
||||
"D": "",
|
||||
"E": "",
|
||||
"F": "end"
|
||||
}
|
||||
]),
|
||||
expectedOutput: EXAMPLE_CSV,
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JSON to CSV",
|
||||
args: [",", "\r\n"],
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JSON to CSV: Array of arrays",
|
||||
input: JSON.stringify([
|
||||
[
|
||||
"A",
|
||||
"B",
|
||||
"C",
|
||||
"D",
|
||||
"E",
|
||||
"F"
|
||||
],
|
||||
[
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5",
|
||||
"6"
|
||||
],
|
||||
[
|
||||
",",
|
||||
";",
|
||||
"'",
|
||||
"\"",
|
||||
"",
|
||||
""
|
||||
],
|
||||
[
|
||||
"\"hello\"",
|
||||
"a\"1",
|
||||
"multi\r\nline",
|
||||
"",
|
||||
"",
|
||||
"end"
|
||||
]
|
||||
]),
|
||||
expectedOutput: EXAMPLE_CSV,
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JSON to CSV",
|
||||
args: [",", "\r\n"],
|
||||
}
|
||||
],
|
||||
},
|
||||
]);
|
||||
@@ -110,6 +110,39 @@ TestRegister.addTests([
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "A1Z26 Encode: normal",
|
||||
input: "This is the test sentence.",
|
||||
expectedOutput: "20 8 9 19 9 19 20 8 5 20 5 19 20 19 5 14 20 5 14 3 5",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "A1Z26 Cipher Encode",
|
||||
args: ["Space"]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "A1Z26 Decode: normal",
|
||||
input: "20 8 9 19 9 19 20 8 5 20 5 19 20 19 5 14 20 5 14 3 5",
|
||||
expectedOutput: "thisisthetestsentence",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "A1Z26 Cipher Decode",
|
||||
args: ["Space"]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "A1Z26 Decode: error",
|
||||
input: "20 8 9 27",
|
||||
expectedOutput: "Error: all numbers must be between 1 and 26.",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "A1Z26 Cipher Decode",
|
||||
args: ["Space"]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Atbash: no input",
|
||||
input: "",
|
||||
@@ -220,6 +253,39 @@ TestRegister.addTests([
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Citrix CTX1 Encode",
|
||||
input: "Password1",
|
||||
expectedOutput: "PFFAJEDBOHECJEDBODEGIMCJPOFLJKDPKLAO",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Citrix CTX1 Encode",
|
||||
"args": []
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Citrix CTX1 Decode: normal",
|
||||
input: "PFFAJEDBOHECJEDBODEGIMCJPOFLJKDPKLAO",
|
||||
expectedOutput: "Password1",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Citrix CTX1 Decode",
|
||||
"args": []
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Citrix CTX1 Decode: invalid length",
|
||||
input: "PFFAJEDBOHECJEDBODEGIMCJPOFLJKDPKLA",
|
||||
expectedOutput: "Incorrect hash length",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Citrix CTX1 Decode",
|
||||
"args": []
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Vigenère Encode: no input",
|
||||
input: "",
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*/
|
||||
import TestRegister from "../../TestRegister";
|
||||
|
||||
const JPATH_TEST_DATA = {
|
||||
const JSON_TEST_DATA = {
|
||||
"store": {
|
||||
"book": [{
|
||||
"category": "reference",
|
||||
@@ -184,7 +184,7 @@ TestRegister.addTests([
|
||||
},
|
||||
{
|
||||
name: "JPath Expression: Empty expression",
|
||||
input: JSON.stringify(JPATH_TEST_DATA),
|
||||
input: JSON.stringify(JSON_TEST_DATA),
|
||||
expectedOutput: "Invalid JPath expression: we need a path",
|
||||
recipeConfig: [
|
||||
{
|
||||
@@ -195,7 +195,7 @@ TestRegister.addTests([
|
||||
},
|
||||
{
|
||||
name: "JPath Expression: Fetch of values from specific object",
|
||||
input: JSON.stringify(JPATH_TEST_DATA),
|
||||
input: JSON.stringify(JSON_TEST_DATA),
|
||||
expectedOutput: [
|
||||
"\"Nigel Rees\"",
|
||||
"\"Evelyn Waugh\"",
|
||||
@@ -211,7 +211,7 @@ TestRegister.addTests([
|
||||
},
|
||||
{
|
||||
name: "JPath Expression: Fetch of all values with matching key",
|
||||
input: JSON.stringify(JPATH_TEST_DATA),
|
||||
input: JSON.stringify(JSON_TEST_DATA),
|
||||
expectedOutput: [
|
||||
"\"Sayings of the Century\"",
|
||||
"\"Sword of Honour\"",
|
||||
@@ -229,7 +229,7 @@ TestRegister.addTests([
|
||||
},
|
||||
{
|
||||
name: "JPath Expression: All data in object",
|
||||
input: JSON.stringify(JPATH_TEST_DATA),
|
||||
input: JSON.stringify(JSON_TEST_DATA),
|
||||
expectedOutput: [
|
||||
"[{\"category\":\"reference\",\"author\":\"Nigel Rees\",\"title\":\"Sayings of the Century\",\"price\":8.95},{\"category\":\"fiction\",\"author\":\"Evelyn Waugh\",\"title\":\"Sword of Honour\",\"price\":12.99},{\"category\":\"fiction\",\"author\":\"Herman Melville\",\"title\":\"Moby Dick\",\"isbn\":\"0-553-21311-3\",\"price\":8.99},{\"category\":\"fiction\",\"author\":\"J. R. R. Tolkien\",\"title\":\"The Lord of the Rings\",\"isbn\":\"0-395-19395-8\",\"price\":22.99}]",
|
||||
"{\"color\":\"red\",\"price\":19.95}",
|
||||
@@ -244,7 +244,7 @@ TestRegister.addTests([
|
||||
},
|
||||
{
|
||||
name: "JPath Expression: Last element in array",
|
||||
input: JSON.stringify(JPATH_TEST_DATA),
|
||||
input: JSON.stringify(JSON_TEST_DATA),
|
||||
expectedOutput: "{\"category\":\"fiction\",\"author\":\"J. R. R. Tolkien\",\"title\":\"The Lord of the Rings\",\"isbn\":\"0-395-19395-8\",\"price\":22.99}",
|
||||
recipeConfig: [
|
||||
{
|
||||
@@ -255,7 +255,7 @@ TestRegister.addTests([
|
||||
},
|
||||
{
|
||||
name: "JPath Expression: First 2 elements in array",
|
||||
input: JSON.stringify(JPATH_TEST_DATA),
|
||||
input: JSON.stringify(JSON_TEST_DATA),
|
||||
expectedOutput: [
|
||||
"{\"category\":\"reference\",\"author\":\"Nigel Rees\",\"title\":\"Sayings of the Century\",\"price\":8.95}",
|
||||
"{\"category\":\"fiction\",\"author\":\"Evelyn Waugh\",\"title\":\"Sword of Honour\",\"price\":12.99}"
|
||||
@@ -269,7 +269,7 @@ TestRegister.addTests([
|
||||
},
|
||||
{
|
||||
name: "JPath Expression: All elements in array with property",
|
||||
input: JSON.stringify(JPATH_TEST_DATA),
|
||||
input: JSON.stringify(JSON_TEST_DATA),
|
||||
expectedOutput: [
|
||||
"{\"category\":\"fiction\",\"author\":\"Herman Melville\",\"title\":\"Moby Dick\",\"isbn\":\"0-553-21311-3\",\"price\":8.99}",
|
||||
"{\"category\":\"fiction\",\"author\":\"J. R. R. Tolkien\",\"title\":\"The Lord of the Rings\",\"isbn\":\"0-395-19395-8\",\"price\":22.99}"
|
||||
@@ -283,7 +283,7 @@ TestRegister.addTests([
|
||||
},
|
||||
{
|
||||
name: "JPath Expression: All elements in array which meet condition",
|
||||
input: JSON.stringify(JPATH_TEST_DATA),
|
||||
input: JSON.stringify(JSON_TEST_DATA),
|
||||
expectedOutput: [
|
||||
"{\"category\":\"fiction\",\"author\":\"Evelyn Waugh\",\"title\":\"Sword of Honour\",\"price\":12.99}",
|
||||
"{\"category\":\"fiction\",\"author\":\"Herman Melville\",\"title\":\"Moby Dick\",\"isbn\":\"0-553-21311-3\",\"price\":8.99}",
|
||||
@@ -298,7 +298,7 @@ TestRegister.addTests([
|
||||
},
|
||||
{
|
||||
name: "JPath Expression: All elements in object",
|
||||
input: JSON.stringify(JPATH_TEST_DATA),
|
||||
input: JSON.stringify(JSON_TEST_DATA),
|
||||
expectedOutput: [
|
||||
"{\"category\":\"reference\",\"author\":\"Nigel Rees\",\"title\":\"Sayings of the Century\",\"price\":8.95}",
|
||||
"{\"category\":\"fiction\",\"author\":\"Herman Melville\",\"title\":\"Moby Dick\",\"isbn\":\"0-553-21311-3\",\"price\":8.99}"
|
||||
@@ -331,5 +331,65 @@ TestRegister.addTests([
|
||||
"args": ["/div/p[@class=\"a\"]", "\\n"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "To MessagePack: no content",
|
||||
input: "",
|
||||
expectedError: true,
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "To MessagePack",
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"op": "To Hex",
|
||||
"args": ["Space"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "From MessagePack: no content",
|
||||
input: "",
|
||||
expectedOutput: "Could not decode MessagePack to JSON: Error: Could not parse",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["Space"]
|
||||
},
|
||||
{
|
||||
"op": "From MessagePack",
|
||||
"args": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "To MessagePack: valid json",
|
||||
input: JSON.stringify(JSON_TEST_DATA),
|
||||
expectedOutput: "81 a5 73 74 6f 72 65 83 a4 62 6f 6f 6b 94 84 a8 63 61 74 65 67 6f 72 79 a9 72 65 66 65 72 65 6e 63 65 a6 61 75 74 68 6f 72 aa 4e 69 67 65 6c 20 52 65 65 73 a5 74 69 74 6c 65 b6 53 61 79 69 6e 67 73 20 6f 66 20 74 68 65 20 43 65 6e 74 75 72 79 a5 70 72 69 63 65 cb 40 21 e6 66 66 66 66 66 84 a8 63 61 74 65 67 6f 72 79 a7 66 69 63 74 69 6f 6e a6 61 75 74 68 6f 72 ac 45 76 65 6c 79 6e 20 57 61 75 67 68 a5 74 69 74 6c 65 af 53 77 6f 72 64 20 6f 66 20 48 6f 6e 6f 75 72 a5 70 72 69 63 65 cb 40 29 fa e1 47 ae 14 7b 85 a8 63 61 74 65 67 6f 72 79 a7 66 69 63 74 69 6f 6e a6 61 75 74 68 6f 72 af 48 65 72 6d 61 6e 20 4d 65 6c 76 69 6c 6c 65 a5 74 69 74 6c 65 a9 4d 6f 62 79 20 44 69 63 6b a4 69 73 62 6e ad 30 2d 35 35 33 2d 32 31 33 31 31 2d 33 a5 70 72 69 63 65 cb 40 21 fa e1 47 ae 14 7b 85 a8 63 61 74 65 67 6f 72 79 a7 66 69 63 74 69 6f 6e a6 61 75 74 68 6f 72 b0 4a 2e 20 52 2e 20 52 2e 20 54 6f 6c 6b 69 65 6e a5 74 69 74 6c 65 b5 54 68 65 20 4c 6f 72 64 20 6f 66 20 74 68 65 20 52 69 6e 67 73 a4 69 73 62 6e ad 30 2d 33 39 35 2d 31 39 33 39 35 2d 38 a5 70 72 69 63 65 cb 40 36 fd 70 a3 d7 0a 3d a7 62 69 63 79 63 6c 65 82 a5 63 6f 6c 6f 72 a3 72 65 64 a5 70 72 69 63 65 cb 40 33 f3 33 33 33 33 33 a9 6e 65 77 73 70 61 70 65 72 92 83 a6 66 6f 72 6d 61 74 aa 62 72 6f 61 64 73 68 65 65 74 a5 74 69 74 6c 65 af 46 69 6e 61 6e 63 69 61 6c 20 54 69 6d 65 73 a5 70 72 69 63 65 cb 40 06 00 00 00 00 00 00 83 a6 66 6f 72 6d 61 74 a7 74 61 62 6c 6f 69 64 a5 74 69 74 6c 65 ac 54 68 65 20 47 75 61 72 64 69 61 6e a5 70 72 69 63 65 02",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "To MessagePack",
|
||||
"args": []
|
||||
},
|
||||
{
|
||||
"op": "To Hex",
|
||||
"args": ["Space"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "From MessagePack: valid msgpack",
|
||||
input: "81 a5 73 74 6f 72 65 83 a4 62 6f 6f 6b 94 84 a8 63 61 74 65 67 6f 72 79 a9 72 65 66 65 72 65 6e 63 65 a6 61 75 74 68 6f 72 aa 4e 69 67 65 6c 20 52 65 65 73 a5 74 69 74 6c 65 b6 53 61 79 69 6e 67 73 20 6f 66 20 74 68 65 20 43 65 6e 74 75 72 79 a5 70 72 69 63 65 cb 40 21 e6 66 66 66 66 66 84 a8 63 61 74 65 67 6f 72 79 a7 66 69 63 74 69 6f 6e a6 61 75 74 68 6f 72 ac 45 76 65 6c 79 6e 20 57 61 75 67 68 a5 74 69 74 6c 65 af 53 77 6f 72 64 20 6f 66 20 48 6f 6e 6f 75 72 a5 70 72 69 63 65 cb 40 29 fa e1 47 ae 14 7b 85 a8 63 61 74 65 67 6f 72 79 a7 66 69 63 74 69 6f 6e a6 61 75 74 68 6f 72 af 48 65 72 6d 61 6e 20 4d 65 6c 76 69 6c 6c 65 a5 74 69 74 6c 65 a9 4d 6f 62 79 20 44 69 63 6b a4 69 73 62 6e ad 30 2d 35 35 33 2d 32 31 33 31 31 2d 33 a5 70 72 69 63 65 cb 40 21 fa e1 47 ae 14 7b 85 a8 63 61 74 65 67 6f 72 79 a7 66 69 63 74 69 6f 6e a6 61 75 74 68 6f 72 b0 4a 2e 20 52 2e 20 52 2e 20 54 6f 6c 6b 69 65 6e a5 74 69 74 6c 65 b5 54 68 65 20 4c 6f 72 64 20 6f 66 20 74 68 65 20 52 69 6e 67 73 a4 69 73 62 6e ad 30 2d 33 39 35 2d 31 39 33 39 35 2d 38 a5 70 72 69 63 65 cb 40 36 fd 70 a3 d7 0a 3d a7 62 69 63 79 63 6c 65 82 a5 63 6f 6c 6f 72 a3 72 65 64 a5 70 72 69 63 65 cb 40 33 f3 33 33 33 33 33 a9 6e 65 77 73 70 61 70 65 72 92 83 a6 66 6f 72 6d 61 74 aa 62 72 6f 61 64 73 68 65 65 74 a5 74 69 74 6c 65 af 46 69 6e 61 6e 63 69 61 6c 20 54 69 6d 65 73 a5 70 72 69 63 65 cb 40 06 00 00 00 00 00 00 83 a6 66 6f 72 6d 61 74 a7 74 61 62 6c 6f 69 64 a5 74 69 74 6c 65 ac 54 68 65 20 47 75 61 72 64 69 61 6e a5 70 72 69 63 65 02",
|
||||
expectedOutput: JSON.stringify(JSON_TEST_DATA, null, 4),
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["Space"]
|
||||
},
|
||||
{
|
||||
"op": "From MessagePack",
|
||||
"args": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]);
|
||||
|
||||
55
test/tests/operations/ExtractEmailAddresses.mjs
Normal file
55
test/tests/operations/ExtractEmailAddresses.mjs
Normal file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* extract email address tests.
|
||||
*
|
||||
* @author Klaxon [klaxon@veyr.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
import TestRegister from "../../TestRegister";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "Extract email address",
|
||||
input: "email@example.com\nfirstname.lastname@example.com\nemail@subdomain.example.com\nfirstname+lastname@example.com\n1234567890@example.com\nemail@example-one.com\n_______@example.com email@example.name\nemail@example.museum email@example.co.jp firstname-lastname@example.com",
|
||||
expectedOutput: "email@example.com\nfirstname.lastname@example.com\nemail@subdomain.example.com\nfirstname+lastname@example.com\n1234567890@example.com\nemail@example-one.com\n_______@example.com\nemail@example.name\nemail@example.museum\nemail@example.co.jp\nfirstname-lastname@example.com\n",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Extract email addresses",
|
||||
"args": [false]
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Extract email address - Display total",
|
||||
input: "email@example.com\nfirstname.lastname@example.com\nemail@subdomain.example.com\nfirstname+lastname@example.com\n1234567890@example.com\nemail@example-one.com\n_______@example.com email@example.name\nemail@example.museum email@example.co.jp firstname-lastname@example.com",
|
||||
expectedOutput: "Total found: 11\n\nemail@example.com\nfirstname.lastname@example.com\nemail@subdomain.example.com\nfirstname+lastname@example.com\n1234567890@example.com\nemail@example-one.com\n_______@example.com\nemail@example.name\nemail@example.museum\nemail@example.co.jp\nfirstname-lastname@example.com\n",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Extract email addresses",
|
||||
"args": [true]
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Extract email address (Internationalized)",
|
||||
input: "\u4f0a\u662d\u5091@\u90f5\u4ef6.\u5546\u52d9 \u093e\u092e@\u092e\u094b\u0939\u0928.\u0908\u0928\u094d\u092b\u094b\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c \u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc Jos\u1ec5Silv\u1ec5@googl\u1ec5.com\nJos\u1ec5Silv\u1ec5@google.com and Jos\u1ec5Silva@google.com\nFoO@BaR.CoM, john@192.168.10.100\ng\xf3mez@junk.br and Abc.123@example.com.\nuser+mailbox/department=shipping@example.com\n\u7528\u6237@\u4f8b\u5b50.\u5e7f\u544a\n\u0909\u092a\u092f\u094b\u0917\u0915\u0930\u094d\u0924\u093e@\u0909\u0926\u093e\u0939\u0930\u0923.\u0915\u0949\u092e\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nD\xf6rte@S\xf6rensen.example.com\n\u0430\u0434\u0436\u0430\u0439@\u044d\u043a\u0437\u0430\u043c\u043f\u043b.\u0440\u0443\u0441\ntest@xn--bcher-kva.com",
|
||||
expectedOutput: "\u4f0a\u662d\u5091@\u90f5\u4ef6.\u5546\u52d9\n\u093e\u092e@\u092e\u094b\u0939\u0928.\u0908\u0928\u094d\u092b\u094b\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nJos\u1ec5Silv\u1ec5@googl\u1ec5.com\nJos\u1ec5Silv\u1ec5@google.com\nJos\u1ec5Silva@google.com\nFoO@BaR.CoM\njohn@192.168.10.100\ng\xf3mez@junk.br\nAbc.123@example.com\nuser+mailbox/department=shipping@example.com\n\u7528\u6237@\u4f8b\u5b50.\u5e7f\u544a\n\u0909\u092a\u092f\u094b\u0917\u0915\u0930\u094d\u0924\u093e@\u0909\u0926\u093e\u0939\u0930\u0923.\u0915\u0949\u092e\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nD\xf6rte@S\xf6rensen.example.com\n\u0430\u0434\u0436\u0430\u0439@\u044d\u043a\u0437\u0430\u043c\u043f\u043b.\u0440\u0443\u0441\ntest@xn--bcher-kva.com\n",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Extract email addresses",
|
||||
"args": [false]
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Extract email address - Display total (Internationalized)",
|
||||
input: "\u4f0a\u662d\u5091@\u90f5\u4ef6.\u5546\u52d9 \u093e\u092e@\u092e\u094b\u0939\u0928.\u0908\u0928\u094d\u092b\u094b\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c \u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc Jos\u1ec5Silv\u1ec5@googl\u1ec5.com\nJos\u1ec5Silv\u1ec5@google.com and Jos\u1ec5Silva@google.com\nFoO@BaR.CoM, john@192.168.10.100\ng\xf3mez@junk.br and Abc.123@example.com.\nuser+mailbox/department=shipping@example.com\n\u7528\u6237@\u4f8b\u5b50.\u5e7f\u544a\n\u0909\u092a\u092f\u094b\u0917\u0915\u0930\u094d\u0924\u093e@\u0909\u0926\u093e\u0939\u0930\u0923.\u0915\u0949\u092e\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nD\xf6rte@S\xf6rensen.example.com\n\u0430\u0434\u0436\u0430\u0439@\u044d\u043a\u0437\u0430\u043c\u043f\u043b.\u0440\u0443\u0441\ntest@xn--bcher-kva.com",
|
||||
expectedOutput: "Total found: 19\n\n\u4f0a\u662d\u5091@\u90f5\u4ef6.\u5546\u52d9\n\u093e\u092e@\u092e\u094b\u0939\u0928.\u0908\u0928\u094d\u092b\u094b\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nJos\u1ec5Silv\u1ec5@googl\u1ec5.com\nJos\u1ec5Silv\u1ec5@google.com\nJos\u1ec5Silva@google.com\nFoO@BaR.CoM\njohn@192.168.10.100\ng\xf3mez@junk.br\nAbc.123@example.com\nuser+mailbox/department=shipping@example.com\n\u7528\u6237@\u4f8b\u5b50.\u5e7f\u544a\n\u0909\u092a\u092f\u094b\u0917\u0915\u0930\u094d\u0924\u093e@\u0909\u0926\u093e\u0939\u0930\u0923.\u0915\u0949\u092e\n\u044e\u0437\u0435\u0440@\u0435\u043a\u0437\u0430\u043c\u043f\u043b.\u043a\u043e\u043c\n\u03b8\u03c3\u03b5\u03c1@\u03b5\u03c7\u03b1\u03bc\u03c0\u03bb\u03b5.\u03c8\u03bf\u03bc\nD\xf6rte@S\xf6rensen.example.com\n\u0430\u0434\u0436\u0430\u0439@\u044d\u043a\u0437\u0430\u043c\u043f\u043b.\u0440\u0443\u0441\ntest@xn--bcher-kva.com\n",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Extract email addresses",
|
||||
"args": [true]
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
33
test/tests/operations/FromDecimal.mjs
Normal file
33
test/tests/operations/FromDecimal.mjs
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* From Decimal tests
|
||||
*
|
||||
* @author qistoph
|
||||
* @copyright Crown Copyright 2018
|
||||
* @licence Apache-2.0
|
||||
*/
|
||||
import TestRegister from "../../TestRegister";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "From Decimal",
|
||||
input: "83 97 109 112 108 101 32 84 101 120 116",
|
||||
expectedOutput: "Sample Text",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "From Decimal",
|
||||
args: ["Space", false]
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "From Decimal with negatives",
|
||||
input: "-130,-140,-152,-151,115,33,0,-1",
|
||||
expectedOutput: "~this!\u0000\u00ff",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "From Decimal",
|
||||
args: ["Comma", true]
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
55
test/tests/operations/FromGeohash.mjs
Normal file
55
test/tests/operations/FromGeohash.mjs
Normal file
@@ -0,0 +1,55 @@
|
||||
/**
|
||||
* To Geohash tests
|
||||
*
|
||||
* @author gchq77703
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
import TestRegister from "../../TestRegister";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "From Geohash",
|
||||
input: "ww8p1r4t8",
|
||||
expectedOutput: "37.83238649368286,112.55838632583618",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "From Geohash",
|
||||
args: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "From Geohash",
|
||||
input: "ww8p1r",
|
||||
expectedOutput: "37.83416748046875,112.5604248046875",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "From Geohash",
|
||||
args: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "From Geohash",
|
||||
input: "ww8",
|
||||
expectedOutput: "37.265625,113.203125",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "From Geohash",
|
||||
args: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "From Geohash",
|
||||
input: "w",
|
||||
expectedOutput: "22.5,112.5",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "From Geohash",
|
||||
args: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
@@ -405,13 +405,309 @@ TestRegister.addTests([
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "HMAC SHA256",
|
||||
name: "HMAC: SHA256",
|
||||
input: "Hello, World!",
|
||||
expectedOutput: "52589bd80ccfa4acbb3f9512dfaf4f700fa5195008aae0b77a9e47dcca75beac",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "HMAC",
|
||||
"args": ["test", "SHA256"]
|
||||
"args": [{"option": "Latin1", "string": "test"}, "SHA256"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "HMAC: RFC4231 Test Case 1 SHA-224",
|
||||
input: "Hi There",
|
||||
expectedOutput: "896fb1128abbdf196832107cd49df33f47b4b1169912ba4f53684b22",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "HMAC",
|
||||
"args": [{"option": "Hex", "string": "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"}, "SHA224"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "HMAC: RFC4231 Test Case 1 SHA-256",
|
||||
input: "Hi There",
|
||||
expectedOutput: "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "HMAC",
|
||||
"args": [{"option": "Hex", "string": "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"}, "SHA256"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "HMAC: RFC4231 Test Case 1 SHA-384",
|
||||
input: "Hi There",
|
||||
expectedOutput: "afd03944d84895626b0825f4ab46907f15f9dadbe4101ec682aa034c7cebc59cfaea9ea9076ede7f4af152e8b2fa9cb6",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "HMAC",
|
||||
"args": [{"option": "Hex", "string": "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"}, "SHA384"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "HMAC: RFC4231 Test Case 1 SHA-512",
|
||||
input: "Hi There",
|
||||
expectedOutput: "87aa7cdea5ef619d4ff0b4241a1d6cb02379f4e2ce4ec2787ad0b30545e17cdedaa833b7d6b8a702038b274eaea3f4e4be9d914eeb61f1702e696c203a126854",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "HMAC",
|
||||
"args": [{"option": "Hex", "string": "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b"}, "SHA512"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "HMAC: RFC4231 Test Case 2 SHA-224",
|
||||
input: "what do ya want for nothing?",
|
||||
expectedOutput: "a30e01098bc6dbbf45690f3a7e9e6d0f8bbea2a39e6148008fd05e44",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "HMAC",
|
||||
"args": [{"option": "Hex", "string": "4a656665"}, "SHA224"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "HMAC: RFC4231 Test Case 2 SHA-256",
|
||||
input: "what do ya want for nothing?",
|
||||
expectedOutput: "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "HMAC",
|
||||
"args": [{"option": "Hex", "string": "4a656665"}, "SHA256"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "HMAC: RFC4231 Test Case 2 SHA-384",
|
||||
input: "what do ya want for nothing?",
|
||||
expectedOutput: "af45d2e376484031617f78d2b58a6b1b9c7ef464f5a01b47e42ec3736322445e8e2240ca5e69e2c78b3239ecfab21649",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "HMAC",
|
||||
"args": [{"option": "Hex", "string": "4a656665"}, "SHA384"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "HMAC: RFC4231 Test Case 2 SHA-512",
|
||||
input: "what do ya want for nothing?",
|
||||
expectedOutput: "164b7a7bfcf819e2e395fbe73b56e0a387bd64222e831fd610270cd7ea2505549758bf75c05a994a6d034f65f8f0e6fdcaeab1a34d4a6b4b636e070a38bce737",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "HMAC",
|
||||
"args": [{"option": "Hex", "string": "4a656665"}, "SHA512"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "HMAC: RFC4231 Test Case 3 SHA-224",
|
||||
input: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
|
||||
expectedOutput: "7fb3cb3588c6c1f6ffa9694d7d6ad2649365b0c1f65d69d1ec8333ea",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["None"]
|
||||
},
|
||||
{
|
||||
"op": "HMAC",
|
||||
"args": [{"option": "Hex", "string": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, "SHA224"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "HMAC: RFC4231 Test Case 3 SHA-256",
|
||||
input: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
|
||||
expectedOutput: "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["None"]
|
||||
},
|
||||
{
|
||||
"op": "HMAC",
|
||||
"args": [{"option": "Hex", "string": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, "SHA256"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "HMAC: RFC4231 Test Case 3 SHA-384",
|
||||
input: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
|
||||
expectedOutput: "88062608d3e6ad8a0aa2ace014c8a86f0aa635d947ac9febe83ef4e55966144b2a5ab39dc13814b94e3ab6e101a34f27",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["None"]
|
||||
},
|
||||
{
|
||||
"op": "HMAC",
|
||||
"args": [{"option": "Hex", "string": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, "SHA384"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "HMAC: RFC4231 Test Case 3 SHA-512",
|
||||
input: "dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd",
|
||||
expectedOutput: "fa73b0089d56a284efb0f0756c890be9b1b5dbdd8ee81a3655f83e33b2279d39bf3e848279a722c806b485a47e67c807b946a337bee8942674278859e13292fb",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["None"]
|
||||
},
|
||||
{
|
||||
"op": "HMAC",
|
||||
"args": [{"option": "Hex", "string": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, "SHA512"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "HMAC: RFC4231 Test Case 4 SHA-224",
|
||||
input: "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
|
||||
expectedOutput: "6c11506874013cac6a2abc1bb382627cec6a90d86efc012de7afec5a",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["None"]
|
||||
},
|
||||
{
|
||||
"op": "HMAC",
|
||||
"args": [{"option": "Hex", "string": "0102030405060708090a0b0c0d0e0f10111213141516171819"}, "SHA224"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "HMAC: RFC4231 Test Case 4 SHA-256",
|
||||
input: "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
|
||||
expectedOutput: "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["None"]
|
||||
},
|
||||
{
|
||||
"op": "HMAC",
|
||||
"args": [{"option": "Hex", "string": "0102030405060708090a0b0c0d0e0f10111213141516171819"}, "SHA256"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "HMAC: RFC4231 Test Case 4 SHA-384",
|
||||
input: "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
|
||||
expectedOutput: "3e8a69b7783c25851933ab6290af6ca77a9981480850009cc5577c6e1f573b4e6801dd23c4a7d679ccf8a386c674cffb",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["None"]
|
||||
},
|
||||
{
|
||||
"op": "HMAC",
|
||||
"args": [{"option": "Hex", "string": "0102030405060708090a0b0c0d0e0f10111213141516171819"}, "SHA384"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "HMAC: RFC4231 Test Case 4 SHA-512",
|
||||
input: "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
|
||||
expectedOutput: "b0ba465637458c6990e5a8c5f61d4af7e576d97ff94b872de76f8050361ee3dba91ca5c11aa25eb4d679275cc5788063a5f19741120c4f2de2adebeb10a298dd",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "From Hex",
|
||||
"args": ["None"]
|
||||
},
|
||||
{
|
||||
"op": "HMAC",
|
||||
"args": [{"option": "Hex", "string": "0102030405060708090a0b0c0d0e0f10111213141516171819"}, "SHA512"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "HMAC: RFC4231 Test Case 6 SHA-224",
|
||||
input: "Test Using Larger Than Block-Size Key - Hash Key First",
|
||||
expectedOutput: "95e9a0db962095adaebe9b2d6f0dbce2d499f112f2d2b7273fa6870e",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "HMAC",
|
||||
"args": [{"option": "Hex", "string": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, "SHA224"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "HMAC: RFC4231 Test Case 6 SHA-256",
|
||||
input: "Test Using Larger Than Block-Size Key - Hash Key First",
|
||||
expectedOutput: "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "HMAC",
|
||||
"args": [{"option": "Hex", "string": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, "SHA256"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "HMAC: RFC4231 Test Case 6 SHA-384",
|
||||
input: "Test Using Larger Than Block-Size Key - Hash Key First",
|
||||
expectedOutput: "4ece084485813e9088d2c63a041bc5b44f9ef1012a2b588f3cd11f05033ac4c60c2ef6ab4030fe8296248df163f44952",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "HMAC",
|
||||
"args": [{"option": "Hex", "string": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, "SHA384"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "HMAC: RFC4231 Test Case 6 SHA-512",
|
||||
input: "Test Using Larger Than Block-Size Key - Hash Key First",
|
||||
expectedOutput: "80b24263c7c1a3ebb71493c1dd7be8b49b46d1f41b4aeec1121b013783f8f3526b56d037e05f2598bd0fd2215d6a1e5295e64f73f63f0aec8b915a985d786598",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "HMAC",
|
||||
"args": [{"option": "Hex", "string": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, "SHA512"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "HMAC: RFC4231 Test Case 7 SHA-224",
|
||||
input: "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.",
|
||||
expectedOutput: "3a854166ac5d9f023f54d517d0b39dbd946770db9c2b95c9f6f565d1",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "HMAC",
|
||||
"args": [{"option": "Hex", "string": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, "SHA224"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "HMAC: RFC4231 Test Case 7 SHA-256",
|
||||
input: "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.",
|
||||
expectedOutput: "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "HMAC",
|
||||
"args": [{"option": "Hex", "string": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, "SHA256"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "HMAC: RFC4231 Test Case 7 SHA-384",
|
||||
input: "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.",
|
||||
expectedOutput: "6617178e941f020d351e2f254e8fd32c602420feb0b8fb9adccebb82461e99c5a678cc31e799176d3860e6110c46523e",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "HMAC",
|
||||
"args": [{"option": "Hex", "string": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, "SHA384"]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "HMAC: RFC4231 Test Case 7 SHA-512",
|
||||
input: "This is a test using a larger than block-size key and a larger than block-size data. The key needs to be hashed before being used by the HMAC algorithm.",
|
||||
expectedOutput: "e37b6a775dc87dbaa4dfa9f96e5e3ffddebd71f8867289865df5a32d20cdc944b6022cac3c4982b10d5eeb55c3e4de15134676fb6de0446065c97440fa8c6a58",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "HMAC",
|
||||
"args": [{"option": "Hex", "string": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}, "SHA512"]
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
122
test/tests/operations/JSONBeautify.mjs
Normal file
122
test/tests/operations/JSONBeautify.mjs
Normal file
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* JSONBeautify tests.
|
||||
*
|
||||
* @author Phillip Nordwall [Phillip.Nordwall@gmail.com]
|
||||
*
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
import TestRegister from "../../TestRegister";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "JSON Beautify: space, ''",
|
||||
input: "",
|
||||
expectedOutput: "",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JSON Beautify",
|
||||
args: [" ", false],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JSON Beautify: space, number",
|
||||
input: "42",
|
||||
expectedOutput: "42",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JSON Beautify",
|
||||
args: [" ", false],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JSON Beautify: space, string",
|
||||
input: "\"string\"",
|
||||
expectedOutput: "\"string\"",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JSON Beautify",
|
||||
args: [" ", false],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JSON Beautify: space, boolean",
|
||||
input: "false",
|
||||
expectedOutput: "false",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JSON Beautify",
|
||||
args: [" ", false],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JSON Beautify: space, emptyList",
|
||||
input: "[]",
|
||||
expectedOutput: "[]",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JSON Beautify",
|
||||
args: [" ", false],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JSON Beautify: space, list",
|
||||
input: "[2,1]",
|
||||
expectedOutput: "[\n 2,\n 1\n]",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JSON Beautify",
|
||||
args: [" ", false],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JSON Beautify: tab, list",
|
||||
input: "[2,1]",
|
||||
expectedOutput: "[\n\t2,\n\t1\n]",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JSON Beautify",
|
||||
args: ["\t", false],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JSON Beautify: space, object",
|
||||
input: "{\"second\":2,\"first\":3}",
|
||||
expectedOutput: "{\n \"second\": 2,\n \"first\": 3\n}",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JSON Beautify",
|
||||
args: [" ", false],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JSON Beautify: tab, nested",
|
||||
input: "[2,{\"second\":2,\"first\":3,\"beginning\":{\"j\":\"3\",\"i\":[2,3,false]}},1,2,3]",
|
||||
expectedOutput: "[\n\t2,\n\t{\n\t\t\"second\": 2,\n\t\t\"first\": 3,\n\t\t\"beginning\": {\n\t\t\t\"j\": \"3\",\n\t\t\t\"i\": [\n\t\t\t\t2,\n\t\t\t\t3,\n\t\t\t\tfalse\n\t\t\t]\n\t\t}\n\t},\n\t1,\n\t2,\n\t3\n]",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JSON Beautify",
|
||||
args: ["\t", false],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JSON Beautify: tab, nested, sorted",
|
||||
input: "[2,{\"second\":2,\"first\":3,\"beginning\":{\"j\":\"3\",\"i\":[2,3,false]}},1,2,3]",
|
||||
expectedOutput: "[\n\t2,\n\t{\n\t\t\"beginning\": {\n\t\t\t\"i\": [\n\t\t\t\t2,\n\t\t\t\t3,\n\t\t\t\tfalse\n\t\t\t],\n\t\t\t\"j\": \"3\"\n\t\t},\n\t\t\"first\": 3,\n\t\t\"second\": 2\n\t},\n\t1,\n\t2,\n\t3\n]",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JSON Beautify",
|
||||
args: ["\t", true],
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
111
test/tests/operations/JSONMinify.mjs
Normal file
111
test/tests/operations/JSONMinify.mjs
Normal file
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* JSONMinify tests.
|
||||
*
|
||||
* @author Phillip Nordwall [Phillip.Nordwall@gmail.com]
|
||||
*
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
import TestRegister from "../../TestRegister";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "JSON Minify: ''",
|
||||
input: "",
|
||||
expectedOutput: "",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JSON Minify",
|
||||
args: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JSON Minify: number",
|
||||
input: "42",
|
||||
expectedOutput: "42",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JSON Minify",
|
||||
args: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JSON Minify: number",
|
||||
input: "4.2",
|
||||
expectedOutput: "4.2",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JSON Minify",
|
||||
args: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JSON Minify: string",
|
||||
input: "\"string\"",
|
||||
expectedOutput: "\"string\"",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JSON Minify",
|
||||
args: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JSON Minify: boolean",
|
||||
input: "false",
|
||||
expectedOutput: "false",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JSON Minify",
|
||||
args: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JSON Minify: emptyList",
|
||||
input: "[\n \n \t]",
|
||||
expectedOutput: "[]",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JSON Minify",
|
||||
args: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JSON Minify: list",
|
||||
input: "[2,\n \t1]",
|
||||
expectedOutput: "[2,1]",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JSON Minify",
|
||||
args: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JSON Minify: object",
|
||||
input: "{\n \"second\": 2,\n \"first\": 3\n}",
|
||||
expectedOutput: "{\"second\":2,\"first\":3}",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JSON Minify",
|
||||
args: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JSON Minify: tab, nested",
|
||||
input: "[\n\t2,\n\t{\n\t\t\"second\": 2,\n\t\t\"first\": 3,\n\t\t\"beginning\": {\n\t\t\t\"j\": \"3\",\n\t\t\t\"i\": [\n\t\t\t\t2,\n\t\t\t\t3,\n\t\t\t\tfalse\n\t\t\t]\n\t\t}\n\t},\n\t1,\n\t2,\n\t3\n]",
|
||||
expectedOutput: "[2,{\"second\":2,\"first\":3,\"beginning\":{\"j\":\"3\",\"i\":[2,3,false]}},1,2,3]",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JSON Minify",
|
||||
args: [],
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
51
test/tests/operations/JWTDecode.mjs
Normal file
51
test/tests/operations/JWTDecode.mjs
Normal file
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* JWT Decode tests
|
||||
*
|
||||
* @author gchq77703 []
|
||||
*
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
import TestRegister from "../../TestRegister";
|
||||
|
||||
const outputObject = JSON.stringify({
|
||||
String: "SomeString",
|
||||
Number: 42,
|
||||
iat: 1
|
||||
}, null, 4);
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "JWT Decode: HS",
|
||||
input: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJTdHJpbmciOiJTb21lU3RyaW5nIiwiTnVtYmVyIjo0MiwiaWF0IjoxfQ.0ha6-j4FwvEIKPVZ-hf3S_R9Hy_UtXzq4dnedXcUrXk",
|
||||
expectedOutput: outputObject,
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JWT Decode",
|
||||
args: [],
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JWT Decode: RS",
|
||||
input: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJTdHJpbmciOiJTb21lU3RyaW5nIiwiTnVtYmVyIjo0MiwiaWF0IjoxfQ.MjEJhtZk2nXzigi24piMzANmrj3mILHJcDl0xOjl5a8EgdKVL1oaMEjTkMQp5RA8YrqeRBFaX-BGGCKOXn5zPY1DJwWsBUyN9C-wGR2Qye0eogH_3b4M9EW00TPCUPXm2rx8URFj7Wg9VlsmrGzLV2oKkPgkVxuFSxnpO3yjn1Y",
|
||||
expectedOutput: outputObject,
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JWT Decode",
|
||||
args: [],
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JWT Decode: ES",
|
||||
input: "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJTdHJpbmciOiJTb21lU3RyaW5nIiwiTnVtYmVyIjo0MiwiaWF0IjoxfQ.WkECT51jSfpRkcpQ4x0h5Dwe7CFBI6u6Et2gWp91HC7mpN_qCFadRpsvJLtKubm6cJTLa68xtei0YrDD8fxIUA",
|
||||
expectedOutput: outputObject,
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JWT Decode",
|
||||
args: [],
|
||||
}
|
||||
],
|
||||
}
|
||||
]);
|
||||
163
test/tests/operations/JWTSign.mjs
Normal file
163
test/tests/operations/JWTSign.mjs
Normal file
@@ -0,0 +1,163 @@
|
||||
/**
|
||||
* JWT Sign tests
|
||||
*
|
||||
* @author gchq77703 []
|
||||
*
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
import TestRegister from "../../TestRegister";
|
||||
|
||||
const inputObject = JSON.stringify({
|
||||
String: "SomeString",
|
||||
Number: 42,
|
||||
iat: 1
|
||||
}, null, 4);
|
||||
|
||||
const hsKey = "secret_cat";
|
||||
const rsKey = `-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICWwIBAAKBgQDdlatRjRjogo3WojgGHFHYLugdUWAY9iR3fy4arWNA1KoS8kVw
|
||||
33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQsHUfQrSDv+MuSUMAe8jzKE4qW
|
||||
+jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5Do2kQ+X5xK9cipRgEKwIDAQAB
|
||||
AoGAD+onAtVye4ic7VR7V50DF9bOnwRwNXrARcDhq9LWNRrRGElESYYTQ6EbatXS
|
||||
3MCyjjX2eMhu/aF5YhXBwkppwxg+EOmXeh+MzL7Zh284OuPbkglAaGhV9bb6/5Cp
|
||||
uGb1esyPbYW+Ty2PC0GSZfIXkXs76jXAu9TOBvD0ybc2YlkCQQDywg2R/7t3Q2OE
|
||||
2+yo382CLJdrlSLVROWKwb4tb2PjhY4XAwV8d1vy0RenxTB+K5Mu57uVSTHtrMK0
|
||||
GAtFr833AkEA6avx20OHo61Yela/4k5kQDtjEf1N0LfI+BcWZtxsS3jDM3i1Hp0K
|
||||
Su5rsCPb8acJo5RO26gGVrfAsDcIXKC+bQJAZZ2XIpsitLyPpuiMOvBbzPavd4gY
|
||||
6Z8KWrfYzJoI/Q9FuBo6rKwl4BFoToD7WIUS+hpkagwWiz+6zLoX1dbOZwJACmH5
|
||||
fSSjAkLRi54PKJ8TFUeOP15h9sQzydI8zJU+upvDEKZsZc/UhT/SySDOxQ4G/523
|
||||
Y0sz/OZtSWcol/UMgQJALesy++GdvoIDLfJX5GBQpuFgFenRiRDabxrE9MNUZ2aP
|
||||
FaFp+DyAe+b4nDwuJaW2LURbr8AEZga7oQj0uYxcYw==
|
||||
-----END RSA PRIVATE KEY-----`;
|
||||
const esKey = `-----BEGIN PRIVATE KEY-----
|
||||
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgevZzL1gdAFr88hb2
|
||||
OF/2NxApJCzGCEDdfSp6VQO30hyhRANCAAQRWz+jn65BtOMvdyHKcvjBeBSDZH2r
|
||||
1RTwjmYSi9R/zpBnuQ4EiMnCqfMPWiZqB4QdbAd0E7oH50VpuZ1P087G
|
||||
-----END PRIVATE KEY-----`;
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "JWT Sign: HS256",
|
||||
input: inputObject,
|
||||
expectedOutput: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJTdHJpbmciOiJTb21lU3RyaW5nIiwiTnVtYmVyIjo0MiwiaWF0IjoxfQ.0ha6-j4FwvEIKPVZ-hf3S_R9Hy_UtXzq4dnedXcUrXk",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JWT Sign",
|
||||
args: [hsKey, "HS256"],
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JWT Sign: HS384",
|
||||
input: inputObject,
|
||||
expectedOutput: "eyJhbGciOiJIUzM4NCIsInR5cCI6IkpXVCJ9.eyJTdHJpbmciOiJTb21lU3RyaW5nIiwiTnVtYmVyIjo0MiwiaWF0IjoxfQ._bPK-Y3mIACConbJqkGFMQ_L3vbxgKXy9gSxtL9hA5XTganozTSXxD0vX0N1yT5s",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JWT Sign",
|
||||
args: [hsKey, "HS384"],
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JWT Sign: HS512",
|
||||
input: inputObject,
|
||||
expectedOutput: "eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJTdHJpbmciOiJTb21lU3RyaW5nIiwiTnVtYmVyIjo0MiwiaWF0IjoxfQ.vZIJU4XYMFt3FLE1V_RZOxEetmV4RvxtPZQGzJthK_d47pjwlEb6pQE23YxHFmOj8H5RLEdqqLPw4jNsOyHRzA",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JWT Sign",
|
||||
args: [hsKey, "HS512"],
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JWT Sign: ES256",
|
||||
input: inputObject,
|
||||
expectedOutput: inputObject,
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JWT Sign",
|
||||
args: [esKey, "ES256"],
|
||||
},
|
||||
{
|
||||
op: "JWT Decode",
|
||||
args: []
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JWT Sign: ES384",
|
||||
input: inputObject,
|
||||
expectedOutput: inputObject,
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JWT Sign",
|
||||
args: [esKey, "ES384"],
|
||||
},
|
||||
{
|
||||
op: "JWT Decode",
|
||||
args: []
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JWT Sign: ES512",
|
||||
input: inputObject,
|
||||
expectedOutput: inputObject,
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JWT Sign",
|
||||
args: [esKey, "ES512"],
|
||||
},
|
||||
{
|
||||
op: "JWT Decode",
|
||||
args: []
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JWT Sign: RS256",
|
||||
input: inputObject,
|
||||
expectedOutput: inputObject,
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JWT Sign",
|
||||
args: [rsKey, "RS256"],
|
||||
},
|
||||
{
|
||||
op: "JWT Decode",
|
||||
args: []
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JWT Sign: RS384",
|
||||
input: inputObject,
|
||||
expectedOutput: inputObject,
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JWT Sign",
|
||||
args: [rsKey, "RS384"],
|
||||
},
|
||||
{
|
||||
op: "JWT Decode",
|
||||
args: []
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JWT Sign: RS512",
|
||||
input: inputObject,
|
||||
expectedOutput: inputObject,
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JWT Sign",
|
||||
args: [esKey, "RS512"],
|
||||
},
|
||||
{
|
||||
op: "JWT Decode",
|
||||
args: []
|
||||
}
|
||||
],
|
||||
}
|
||||
]);
|
||||
75
test/tests/operations/JWTVerify.mjs
Normal file
75
test/tests/operations/JWTVerify.mjs
Normal file
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* JWT Verify tests
|
||||
*
|
||||
* @author gchq77703 []
|
||||
*
|
||||
* @copyright Crown Copyright 2018
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
import TestRegister from "../../TestRegister";
|
||||
|
||||
const outputObject = JSON.stringify({
|
||||
String: "SomeString",
|
||||
Number: 42,
|
||||
iat: 1
|
||||
}, null, 4);
|
||||
|
||||
const invalidAlgorithm = "JsonWebTokenError: invalid algorithm";
|
||||
|
||||
const hsKey = "secret_cat";
|
||||
const rsKey = `-----BEGIN RSA PRIVATE KEY-----
|
||||
MIICWwIBAAKBgQDdlatRjRjogo3WojgGHFHYLugdUWAY9iR3fy4arWNA1KoS8kVw
|
||||
33cJibXr8bvwUAUparCwlvdbH6dvEOfou0/gCFQsHUfQrSDv+MuSUMAe8jzKE4qW
|
||||
+jK+xQU9a03GUnKHkkle+Q0pX/g6jXZ7r1/xAK5Do2kQ+X5xK9cipRgEKwIDAQAB
|
||||
AoGAD+onAtVye4ic7VR7V50DF9bOnwRwNXrARcDhq9LWNRrRGElESYYTQ6EbatXS
|
||||
3MCyjjX2eMhu/aF5YhXBwkppwxg+EOmXeh+MzL7Zh284OuPbkglAaGhV9bb6/5Cp
|
||||
uGb1esyPbYW+Ty2PC0GSZfIXkXs76jXAu9TOBvD0ybc2YlkCQQDywg2R/7t3Q2OE
|
||||
2+yo382CLJdrlSLVROWKwb4tb2PjhY4XAwV8d1vy0RenxTB+K5Mu57uVSTHtrMK0
|
||||
GAtFr833AkEA6avx20OHo61Yela/4k5kQDtjEf1N0LfI+BcWZtxsS3jDM3i1Hp0K
|
||||
Su5rsCPb8acJo5RO26gGVrfAsDcIXKC+bQJAZZ2XIpsitLyPpuiMOvBbzPavd4gY
|
||||
6Z8KWrfYzJoI/Q9FuBo6rKwl4BFoToD7WIUS+hpkagwWiz+6zLoX1dbOZwJACmH5
|
||||
fSSjAkLRi54PKJ8TFUeOP15h9sQzydI8zJU+upvDEKZsZc/UhT/SySDOxQ4G/523
|
||||
Y0sz/OZtSWcol/UMgQJALesy++GdvoIDLfJX5GBQpuFgFenRiRDabxrE9MNUZ2aP
|
||||
FaFp+DyAe+b4nDwuJaW2LURbr8AEZga7oQj0uYxcYw==
|
||||
-----END RSA PRIVATE KEY-----`;
|
||||
const esKey = `-----BEGIN PRIVATE KEY-----
|
||||
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgevZzL1gdAFr88hb2
|
||||
OF/2NxApJCzGCEDdfSp6VQO30hyhRANCAAQRWz+jn65BtOMvdyHKcvjBeBSDZH2r
|
||||
1RTwjmYSi9R/zpBnuQ4EiMnCqfMPWiZqB4QdbAd0E7oH50VpuZ1P087G
|
||||
-----END PRIVATE KEY-----`;
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "JWT Verify: HS",
|
||||
input: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJTdHJpbmciOiJTb21lU3RyaW5nIiwiTnVtYmVyIjo0MiwiaWF0IjoxfQ.0ha6-j4FwvEIKPVZ-hf3S_R9Hy_UtXzq4dnedXcUrXk",
|
||||
expectedOutput: outputObject,
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JWT Verify",
|
||||
args: [hsKey],
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JWT Verify: RS",
|
||||
input: "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJTdHJpbmciOiJTb21lU3RyaW5nIiwiTnVtYmVyIjo0MiwiaWF0IjoxfQ.MjEJhtZk2nXzigi24piMzANmrj3mILHJcDl0xOjl5a8EgdKVL1oaMEjTkMQp5RA8YrqeRBFaX-BGGCKOXn5zPY1DJwWsBUyN9C-wGR2Qye0eogH_3b4M9EW00TPCUPXm2rx8URFj7Wg9VlsmrGzLV2oKkPgkVxuFSxnpO3yjn1Y",
|
||||
expectedOutput: invalidAlgorithm,
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JWT Verify",
|
||||
args: [rsKey],
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "JWT Verify: ES",
|
||||
input: "eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJTdHJpbmciOiJTb21lU3RyaW5nIiwiTnVtYmVyIjo0MiwiaWF0IjoxfQ.WkECT51jSfpRkcpQ4x0h5Dwe7CFBI6u6Et2gWp91HC7mpN_qCFadRpsvJLtKubm6cJTLa68xtei0YrDD8fxIUA",
|
||||
expectedOutput: invalidAlgorithm,
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "JWT Verify",
|
||||
args: [esKey],
|
||||
}
|
||||
],
|
||||
}
|
||||
]);
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user