2
0
mirror of https://github.com/gchq/CyberChef synced 2025-12-05 23:53:27 +00:00

Compare commits

...

361 Commits

Author SHA1 Message Date
n1474335
8148c1a8a8 8.24.2 2019-02-11 18:45:27 +00:00
n1474335
ce61bcc078 Merge branch 'd98762625-dynamic-import' 2019-02-11 18:45:00 +00:00
n1474335
49e2b05a11 Dynamic module loading is now cached and Webpack includes the import in the main chunk. 2019-02-11 18:44:41 +00:00
d98762625
481f2a4717 Merge branch 'master' of github.com:gchq/CyberChef into dynamic-import 2019-02-11 16:54:31 +00:00
d98762625
c01c076561 try/catch to allow chef to run from prod file 2019-02-11 16:51:23 +00:00
d98762625
2391e08ac1 tidy up 2019-02-11 15:47:28 +00:00
d98762625
a7a2fe243a prod working with mini css webpack plugin 2019-02-11 15:40:18 +00:00
n1474335
b5c655dd70 8.24.1 2019-02-11 14:48:45 +00:00
n1474335
d84a61d108 Merge branch 'j433866-open-file-button' 2019-02-11 14:48:38 +00:00
n1474335
13abbd2c5d Abstracted out loadFile logic to separate function 2019-02-11 14:48:25 +00:00
d98762625
d22eac9f35 WIP getting prod working with minicss webpack plugin 2019-02-11 14:29:29 +00:00
n1474335
d71aa8d7e2 Merge branch 'open-file-button' of https://github.com/j433866/CyberChef into j433866-open-file-button 2019-02-11 14:28:32 +00:00
n1474335
7a4e0301d2 8.24.0 2019-02-08 18:07:10 +00:00
n1474335
42826e542d Updated changelog 2019-02-08 18:07:03 +00:00
n1474335
42d1c9403c Merge branch 'h345983745-dnsoverhttps' 2019-02-08 18:02:39 +00:00
n1474335
ab43635583 Tidied up 'DNS over HTTPS' operation and fixed manualBake flag. 2019-02-08 18:02:13 +00:00
n1474335
b8ecd83bfd Merge branch 'dnsoverhttps' of https://github.com/h345983745/CyberChef into h345983745-dnsoverhttps 2019-02-08 17:34:33 +00:00
n1474335
0db0ced1ab 8.23.4 2019-02-08 17:28:16 +00:00
n1474335
3d20833d42 Fixed populateOption HTML escape bug. Closes #490 2019-02-08 17:28:10 +00:00
n1474335
7d09ba5669 8.23.3 2019-02-08 17:06:42 +00:00
n1474335
310ff30278 Merge branch 'j433866-xss_fixes' 2019-02-08 17:06:32 +00:00
n1474335
821bc9405c Merge branch 'xss_fixes' of https://github.com/j433866/CyberChef into j433866-xss_fixes 2019-02-08 17:05:51 +00:00
n1474335
d54d66cffc 8.23.2 2019-02-08 16:54:11 +00:00
n1474335
d2b4c40357 Fixed BigNumber/XRegExp incompatibility. CLoses #481 2019-02-08 16:54:04 +00:00
n1474335
f48af97ddc 8.23.1 2019-02-08 15:53:42 +00:00
n1474335
f1264d6310 Update package-lock.json 2019-02-08 15:53:40 +00:00
n1474335
4dc5a1499a Merge branch 'j433866-coords-fix' 2019-02-08 15:52:40 +00:00
d98762625
58a8af20a6 Highligting for Recipe now working. Discovered bug when highlighting on a test case 2019-02-08 14:28:53 +00:00
h345983745
75a58f465c Removed jpath import 2019-02-07 21:05:07 +00:00
h345983745
613cbaa556 Fixing Formating Issues 2019-02-07 08:28:23 +00:00
h345983745
0d0a634255 Added More Request Types 2019-02-06 23:27:27 +00:00
h345983745
105090db60 Spelling Check 2019-02-06 22:50:46 +00:00
h345983745
3e9c75f735 Added to Categories 2019-02-06 22:34:43 +00:00
h345983745
d42075072b Small Updates 2019-02-06 20:54:06 +00:00
h345983745
6a099f0813 Inital Commit 2019-02-06 20:20:20 +00:00
d98762625
9af5e40071 update linting to allow dybnamic import. Recipe highlight still broken 2019-02-01 14:05:48 +00:00
d98762625
4bf2a29070 WIP: bundle all css into main.css with mini-css-extract. Cannot split into vendor and styles without breaking at the moment. 2019-02-01 13:45:47 +00:00
d98762625
069d0e48c1 WIP: use mini-css-extract-plugin instead of extract-text, to work with dynamic import. Currently outputting only one css and recipe highlight doesnt work 2019-02-01 12:00:45 +00:00
d98762625
c8cb2692dd WIP: Recipe refactored to use dynamic import 2019-02-01 10:52:21 +00:00
j433866
74a22bcf9c Swap ordering of truncating and escaping 2019-01-31 15:22:25 +00:00
j433866
8b44927cb6 Fix XSS for To Table operation and Magic button 2019-01-31 15:18:37 +00:00
j433866
3209c94622 Fix conversion breaking when compass directions are used as delimiters 2019-01-21 12:50:30 +00:00
n1474335
6f8a5ea1be Merge branch 'j433866-coordinates' 2019-01-18 17:14:39 +00:00
n1474335
69837837b0 Tidied up co-ordinate operation 2019-01-18 17:14:25 +00:00
n1474335
03d8bf2836 Merge branch 'coordinates' of https://github.com/j433866/CyberChef into j433866-coordinates 2019-01-18 16:05:44 +00:00
n1474335
eca2c142f3 8.23.0 2019-01-18 15:37:42 +00:00
n1474335
715f7bbbc2 Lint 2019-01-18 15:37:25 +00:00
n1474335
291ebd5c12 Merge branch 'artemisbot-features/yara' 2019-01-18 15:35:14 +00:00
n1474335
ba04cac7ac Tidied up YARA operation 2019-01-18 15:34:56 +00:00
j433866
acb8c0b5af Change icon from folder to input 2019-01-18 15:12:03 +00:00
j433866
0c14bacea7 Add button to input to allow opening of files using the file prompt. 2019-01-18 15:07:19 +00:00
n1474335
4cabb849f3 Merge branch 'features/yara' of https://github.com/artemisbot/CyberChef into artemisbot-features/yara 2019-01-18 14:56:26 +00:00
n1474335
445a85798b 8.22.1 2019-01-18 14:50:00 +00:00
n1474335
55775f48e9 Merge branch 'picapi-b64-description-fix' 2019-01-18 14:49:53 +00:00
j433866
4bd923dc06 Improved handling of negative numbers and weirder inputs.
Negative numbers shouldn't make it go weird any more.
Automatic detection of input formats should be more reliable.
2019-01-17 13:53:42 +00:00
j433866
439654ed7f Add tests for new co-ordinate conversion module.
Removed To/From geohash tests
2019-01-17 13:49:36 +00:00
j433866
69797e58cb Add better error handling.
Also now doesn't do anything if there's no input
2019-01-16 16:57:58 +00:00
Matt
d1961ca3fa Marginally reduced size of libyara-wasm 2019-01-16 01:15:51 +00:00
Matt
2e9b1e079c Merge remote-tracking branch 'upstream/master' into features/yara 2019-01-15 23:46:49 +00:00
Matt
3dfaaf4c25 Update libyara for test pass 2019-01-15 23:45:40 +00:00
Matt
fcc39a0397 Added File upload support to textarea 2019-01-15 23:42:05 +00:00
Matt
0602f457ce Added initial tests & counts support 2019-01-15 16:24:29 +00:00
j433866
d00b0f4c0e Basically rewrote the whole thing using the new geodesy module 2019-01-15 15:55:49 +00:00
j433866
5e68959c03 Catch when OS grid references aren't calculated 2019-01-15 10:25:49 +00:00
j433866
ad4451a757 Rewrite MGRS to use new Geodesy module.
Added Ordnance Survey grid reference support
2019-01-15 10:13:11 +00:00
Callum Fraser
4d8127a7d9 Modified description of ToBase64 operation
Addresses #472
2019-01-14 22:25:49 +00:00
j433866
ee360521bb Remove MGRS npm module 2019-01-14 16:41:06 +00:00
j433866
04b0b8c723 Tidy up code 2019-01-14 14:58:41 +00:00
j433866
b3ac8d0835 Removed some debug logging 2019-01-14 13:49:49 +00:00
j433866
1a88a0164c Fix delimiter breaking Geohash detection 2019-01-14 13:00:14 +00:00
j433866
8b77ad7748 Stop delimiters breaking MGRS conversion 2019-01-14 12:49:28 +00:00
j433866
8d1f668fc5 Remove old Geohash modules 2019-01-14 11:56:27 +00:00
j433866
68fbbb64db Add new Convert co-ordinate format module.
Also added autodetect of co-ordinate format / delimiter
2019-01-14 11:49:57 +00:00
Matt
8bba4b2973 More speedrun stats (literally 10x faster) 2019-01-12 00:20:25 +00:00
j433866
abdd70c6fa Add ConvertCoordinates to lib folder 2019-01-11 11:59:13 +00:00
n1474335
9787ab04cd 8.22.0 2019-01-10 15:44:02 +00:00
n1474335
79d3c90026 Merge branch 'j433866-subsection' 2019-01-10 15:43:05 +00:00
n1474335
c2068b343b Tidied up and added global matching to Subsection operation 2019-01-10 15:42:48 +00:00
j433866
9e63e40dab Add new MGRS module and update webpack-dev-server 2019-01-10 15:24:29 +00:00
n1474335
6424839731 Merge branch 'subsection' of https://github.com/j433866/CyberChef into j433866-subsection 2019-01-10 15:11:34 +00:00
n1474335
863a525625 8.21.0 2019-01-10 15:02:26 +00:00
n1474335
f82a727e24 Merge branch 'masq-insense' 2019-01-10 15:01:22 +00:00
n1474335
995fcab071 Tidied up Case Insensitive Regex ops 2019-01-10 15:01:01 +00:00
n1474335
c5270d75a1 Merge branch 'insense' of https://github.com/masq/CyberChef into masq-insense 2019-01-10 14:53:21 +00:00
n1474335
324c409ff1 8.20.0 2019-01-09 16:38:53 +00:00
n1474335
1db8e6dddc Merge branch 'klaxon1-feature/lorem-ipsum-generator' 2019-01-09 16:38:46 +00:00
n1474335
c49a770c59 Tidied up Lorem Ipsum op 2019-01-09 16:36:34 +00:00
Matt
dd9ba4d250 Fixed problems flagged by n's review 2019-01-09 15:28:50 +00:00
n1474335
0e601d5b5f Merge branch 'feature/lorem-ipsum-generator' of https://github.com/klaxon1/CyberChef into klaxon1-feature/lorem-ipsum-generator 2019-01-09 14:50:48 +00:00
Matt
ebb632e888 Added metadata, string identifiers and operation args 2019-01-09 14:29:14 +00:00
Matt
4db2335107 Speedrunning strats (increased speed on big files) 2019-01-09 11:45:11 +00:00
Matt
26a2fb6662 Increased size of rule inp & expanded memory for wasm 2019-01-09 09:56:55 +00:00
Matt
4c1521a98e No data matches & warnings support 2019-01-08 23:26:14 +00:00
Matt
df8abb099c Added code argtype 2019-01-08 22:23:14 +00:00
n1474335
fe1332f18e 8.19.7 2019-01-08 18:29:14 +00:00
n1474335
cb9ab7a2c9 Fixed 'Maximise output' button functionality 2019-01-08 18:29:07 +00:00
n1474335
3a6b2875d5 8.19.6 2019-01-08 17:51:47 +00:00
n1474335
766de7e6fa Fixed bug in 'Regular expression' operation when highlighting lookaheads 2019-01-08 17:51:43 +00:00
Matt
13439e100e Merge remote-tracking branch 'upstream/master' into features/yara 2019-01-08 16:28:14 +00:00
Matt
5ac469b174 Added yara rule support 2019-01-08 16:19:58 +00:00
j433866
8ac5b48493 Update operation description 2019-01-08 11:51:33 +00:00
j433866
1a827ef44f Add Subsection to Flow Control category 2019-01-08 11:17:06 +00:00
j433866
0f0e346a02 Add new Subsection operation 2019-01-08 11:12:02 +00:00
n1474335
c82971f8db 8.19.5 2019-01-01 20:49:24 +00:00
n1474335
cb2c376c63 Increasing Node memory limit from 1G to 2G 2019-01-01 20:27:38 +00:00
n1474335
bc00fa0694 8.19.4 2019-01-01 20:15:29 +00:00
n1474335
c86007da71 Removed increase-memory-limit plugin in favour of NODE_OPTIONS environment variable. 2019-01-01 20:15:16 +00:00
n1474335
1bf513ca74 8.19.3 2019-01-01 19:56:20 +00:00
n1474335
29411c903f Added increase-memory-limit plugin to TravisCI build process to reduce 'JavaScript heap out of memory' errors. 2019-01-01 19:56:12 +00:00
n1474335
017dde364c 8.19.2 2019-01-01 19:22:10 +00:00
n1474335
c123d7370a Merge branch 'edwardwall-patch-2' 2019-01-01 19:21:11 +00:00
n1474335
76f1e5e8f3 Merge branch 'patch-2' of https://github.com/edwardwall/CyberChef into edwardwall-patch-2 2019-01-01 19:20:07 +00:00
n1474335
4e466c7886 8.19.1 2019-01-01 19:19:16 +00:00
n1474335
d469fb9c58 Updated dependencies 2019-01-01 19:19:07 +00:00
Edward Wall
050ab03448 Simplify to improve readability 2018-12-30 17:06:48 +00:00
Edward Wall
40acf751a8 Update to understand Generalized / UTC Time
Future proofing for when certificates with dates after 2049 begin being issued.
These certificates' dates will be in Generalized Time not UTC Time as per RFC 5280
2018-12-30 16:46:18 +00:00
Spencer Walden
126ad585c0 Registers tests for 'To/From Case Insensitive Regex' operations 2018-12-30 03:26:44 -08:00
Spencer Walden
1d04b649e0 Adds 'To/From Case Insensitive Regex' operations under 'Utils' 2018-12-30 03:26:44 -08:00
Spencer Walden
b750006cf0 Adds tests for 'To/From Case Insensitive Regex' operations 2018-12-30 03:26:44 -08:00
Spencer Walden
3c16b839b6 Adds 'From Case Insensitive Regex' operation 2018-12-30 03:26:44 -08:00
Spencer Walden
32aea6b86c Adds 'To Case Insensitive Regex' operation 2018-12-30 03:26:44 -08:00
Edward Wall
688c2d0df5 Update ParseX509Certificate.mjs 2018-12-30 03:15:07 +00:00
n1474335
0cea56dc62 8.19.0 2018-12-30 01:07:54 +00:00
n1474335
bb44268c30 Merge branch 'feature-browser-testsuite' 2018-12-30 01:07:42 +00:00
n1474335
19b3dcf1c2 Updated CHANGELOG 2018-12-30 01:07:26 +00:00
n1474335
71e0a4e0ce Increased UI test timeouts 2018-12-30 00:47:10 +00:00
n1474335
7f2e879e24 Added explicit bake after input added in test suite. 2018-12-30 00:37:44 +00:00
n1474335
840e44deac Tidied up UI tests 2018-12-30 00:26:28 +00:00
n1474335
f7707faece Added Chrome to TravisCI config 2018-12-30 00:02:41 +00:00
n1474335
b631e3fef6 Added nightwatch tests to TravisCI build process for prod and inline versions. 2018-12-29 23:46:13 +00:00
n1474335
b0fb9db4b8 Added nightwatch.js test suite for confirming that the app loads correctly and can run operations from each module. Currently only support the latest version of Chrome. 2018-12-29 02:58:05 +00:00
n1474335
c7e9115994 Restructured tests directory 2018-12-28 21:49:40 +00:00
Klaxon
f2d115ee4d add lorem ipsum generator 2018-12-29 00:44:59 +10:00
n1474335
a1b161493c 8.18.1 2018-12-26 16:50:36 +00:00
n1474335
5acee80463 'editableOption's are now full width. 'editableOptionShort' type added to replace the old style. 2018-12-26 16:50:32 +00:00
n1474335
e6932401ad 8.18.0 2018-12-26 16:35:34 +00:00
n1474335
7a4eff0f5c Merge branch 'artemisbot-features/colour-channel' 2018-12-26 16:33:26 +00:00
n1474335
8b533e9893 Tidied up 'Split Colour Channels' operation and added 'Multimedia' category 2018-12-26 16:33:10 +00:00
n1474335
02b92c7977 Merge branch 'features/colour-channel' of https://github.com/artemisbot/CyberChef into artemisbot-features/colour-channel 2018-12-26 16:10:44 +00:00
n1474335
e386863bdb 8.17.2 2018-12-26 00:39:38 +00:00
n1474335
16be7cb28a Fixed grunt-webpack circular reference issue 2018-12-26 00:39:30 +00:00
n1474335
f6d97c19d9 8.17.1 2018-12-26 00:01:21 +00:00
n1474335
8fef01d961 Fixed bundle analyzer filepath 2018-12-26 00:01:12 +00:00
n1474335
43dcd544f2 Added webpack-bundle-analyzer to production build. Refactored some modules to improve performance. Removed moment-timezone from Utils to drastically reduce module size. 2018-12-25 23:58:00 +00:00
n1474335
b29bb6fdd7 Added 'DishError' and refined test results. 2018-12-25 22:38:53 +00:00
n1474335
d2325306db 8.17.0 2018-12-25 21:55:51 +00:00
n1474335
dfe31980b7 Merge branch 'j433866-qrcodes' 2018-12-25 21:55:35 +00:00
n1474335
9734b78aeb Tidied up QR code operations 2018-12-25 21:54:38 +00:00
n1474335
4ee0800990 Merge branch 'qrcodes' of https://github.com/j433866/CyberChef into j433866-qrcodes 2018-12-25 19:07:59 +00:00
n1474335
387008bd9c 8.16.1 2018-12-25 19:02:13 +00:00
n1474335
bf24547202 The 'option' and 'editableOption' arguments can now specify a 'defaultIndex' to populate, instead of using the first in the provided list. 2018-12-25 19:02:05 +00:00
Matt C
454ef0076b Disabled tests 2018-12-21 17:19:33 +00:00
Matt C
18693d2471 Add tests, however non-functional due to lack of File in Node
Also add jimp to package.json
2018-12-21 17:17:11 +00:00
Matt C
5a9583c970 Add to categories 2018-12-21 17:15:30 +00:00
Matt C
0046f7e3d7 Added colour channel splitting support 2018-12-21 17:08:09 +00:00
j433866
c2f6b8df66 Add tests for Parse QR Code module 2018-12-21 11:26:03 +00:00
j433866
d0e428b728 Improve image normalising 2018-12-21 11:24:31 +00:00
j433866
ae5128a33a Always generate a PNG if the format isn't SVG 2018-12-21 11:23:51 +00:00
j433866
ed25017e2d Add process.browser to webpack config, so we don't include stuff we don't need 2018-12-20 14:46:24 +00:00
j433866
e5b2b84073 Add new ParseQRCode operation 2018-12-20 14:45:23 +00:00
j433866
1953d9a4c8 Add Jimp and jsqr modules 2018-12-20 14:42:32 +00:00
j433866
b3113c109b Change module to Image, change default format value to PNG 2018-12-20 14:42:12 +00:00
n1474335
8c3569ea63 8.16.0 2018-12-19 17:59:55 +00:00
n1474335
ae28d476de Merge branch 'anthony-arnold-play-media' 2018-12-19 17:58:51 +00:00
n1474335
01c4cfdc8d Tidied up 'Play Media' operation 2018-12-19 17:58:38 +00:00
n1474335
8c6c3a1c01 Merge branch 'play-media' of https://github.com/anthony-arnold/CyberChef into anthony-arnold-play-media 2018-12-19 17:39:07 +00:00
n1474335
f367c1f78b 8.15.1 2018-12-19 17:25:05 +00:00
n1474335
13d87d397d Merge branch 'j433866-master' 2018-12-19 17:24:52 +00:00
n1474335
ed2c886359 Magic crib now only applies after all branches have been explored. 2018-12-19 17:24:38 +00:00
n1474335
6337e84708 Merge branch 'master' of https://github.com/j433866/CyberChef into j433866-master 2018-12-19 16:38:34 +00:00
j433866
ae20a951be Add customisation arguments.
Add presentation of QR code in HTML.
2018-12-19 14:43:31 +00:00
Anthony Arnold
866dd546c8 Add the Play Media operation and place it under a new "Multimedia" category. Move the Render Image to this new category as well. 2018-12-20 00:05:10 +10:00
j433866
2070e1a96b Add new Generate QR Code module 2018-12-19 13:27:45 +00:00
j433866
952f49e2e1 Add qr-image to package 2018-12-19 13:27:18 +00:00
j433866
f600571c6d Fix to make the filter work when intensive mode was turned on. 2018-12-19 09:42:09 +00:00
j433866
5d4c7244e1 Add note about crib to operation description 2018-12-18 16:52:09 +00:00
j433866
b6bdcaa71f Rename output filter argument to Crib 2018-12-18 14:19:52 +00:00
j433866
c8eab5d218 Commenting 2018-12-18 14:06:39 +00:00
n1474335
8ab56a29ac 8.15.0 2018-12-18 13:50:30 +00:00
n1474335
973b5f3f5c Merge branch 'Cynser-text-brute-force' 2018-12-18 13:50:23 +00:00
n1474335
076a1f97c2 Tidied up 'Text Encoding Brute Force' operations and updated CHANGELOG 2018-12-18 13:50:10 +00:00
n1474335
d96ef37d81 Merge branch 'text-brute-force' of https://github.com/Cynser/CyberChef into Cynser-text-brute-force 2018-12-18 12:28:27 +00:00
n1474335
56f8302402 8.14.0 2018-12-18 12:20:03 +00:00
n1474335
97e6a7cbd8 Merge branch 'tcode2k16-master' 2018-12-18 12:19:56 +00:00
n1474335
d89d79116c Cleaned up Base62 ops and updated CHANGELOG 2018-12-18 12:19:42 +00:00
j433866
367d79e820 Fix filtering to work on all the data and not just the result snippet 2018-12-18 11:55:49 +00:00
j433866
283d7f2159 Add Output Filter option to Magic operation 2018-12-18 10:40:18 +00:00
Cynser
dacb3ef6c3 Added decode option 2018-12-17 19:39:12 +00:00
tcode2k16
22454ae842 Add "To Base62" and "From Base62" operations 2018-12-17 12:37:00 +08:00
n1474335
79b9b63982 8.13.0 2018-12-15 00:26:41 +00:00
n1474335
2f68bf30a4 Merge branch 'jarmovanlenthe-master' 2018-12-15 00:26:31 +00:00
n1474335
50f078cc45 Updated CHANGELOG 2018-12-15 00:26:15 +00:00
n1474335
47a410d6ab Merge branch 'master' of https://github.com/jarmovanlenthe/CyberChef into jarmovanlenthe-master 2018-12-15 00:19:16 +00:00
n1474335
31cbf8cccc 8.12.4 2018-12-15 00:16:23 +00:00
n1474335
88bd321e3e Merge branch 'imhotepisinvisible-master' 2018-12-15 00:16:13 +00:00
Jarmo van Lenthe
b4a586c0b9 Some lets to consts and removing of trailing spaces from grunt lint 2018-12-14 22:35:43 +01:00
Oliver Grubin
63593f1b6c Fix HMAC operation when hex key has bytes >= 0x80 (#437)
Add test vectors from RFC4231
2018-12-14 21:32:44 +00:00
Jarmo van Lenthe
dcff8971e8 Added simple A1Z26 'cipher' 2018-12-14 22:29:51 +01:00
Cynser
3f7059a235 Remove unnecessary escape character 2018-12-12 17:49:11 +00:00
Cynser
71c743ff5a Add Text Encoding Brute Force operation 2018-12-12 17:34:45 +00:00
n1474335
15fbe5a459 8.12.3 2018-11-23 16:07:30 +00:00
n1474335
cd47394709 Merge branch 'PhillipNordwall-JSON_Object_Sort' 2018-11-23 16:07:21 +00:00
n1474335
6f4ee8b7b6 Tidied JSON Beautify op. Changed default indent to 4 spaces instead of a tab. 2018-11-23 16:05:51 +00:00
n1474335
8c5d05b611 Merge branch 'JSON_Object_Sort' of https://github.com/PhillipNordwall/CyberChef into PhillipNordwall-JSON_Object_Sort 2018-11-23 15:56:59 +00:00
n1474335
3bdcf4d851 8.12.2 2018-11-23 14:58:38 +00:00
n1474335
1d1c69ca51 Updated magic pattern matches for QP and B64 encodings to handle whitespace better 2018-11-23 14:58:30 +00:00
Phillip Nordwall
c4c679021d Adding Sort Object Keys, and tests for it. 2018-11-22 11:10:10 -08:00
Phillip Nordwall
c16d13e2c9 Adding test cases for JSON Minify 2018-11-22 11:07:48 -08:00
Phillip Nordwall
97613eb3c7 Adding test cases for JSON Beautify 2018-11-22 10:31:22 -08:00
n1474335
a946d04a72 8.12.1 2018-11-21 17:48:03 +00:00
n1474335
cc35ec82eb Fixed babel transpilation of jsesc and crypto-api 2018-11-21 17:47:56 +00:00
n1474335
d6604e0008 Updated CHANGELOG 2018-11-21 12:48:27 +00:00
n1474335
b9e63efc37 Fixed version links in CHANGELOG 2018-11-21 12:40:55 +00:00
n1474335
b458707921 8.12.0 2018-11-21 12:29:25 +00:00
n1474335
6ec52c6cd2 Merge branch 'bwhitn-citrix' 2018-11-21 12:28:36 +00:00
n1474335
79d7a5dd87 Tidied up Citrix CTX1 operations and updated CHANGELOG 2018-11-21 12:28:19 +00:00
n1474335
1653d0212a Merge branch 'citrix' of https://github.com/bwhitn/CyberChef into bwhitn-citrix 2018-11-21 10:23:39 +00:00
Brian Whitney
c378bcb00b Fixed lint issues 2018-11-20 11:24:50 -05:00
Brian Whitney
215e7a5f5d Citrix CTX1 encoding/decoding 2018-11-20 11:09:52 -05:00
bwhitn
6b686681d5 Encoding ctx1 2018-11-19 23:48:33 -05:00
n1474335
20ea050728 Updated description for 'Substitute' to include note about escaping backslashes. 2018-11-19 14:54:37 +00:00
n1474335
4b6132a2d7 8.11.2 2018-11-19 14:34:56 +00:00
n1474335
4cf80e3ebb Added RFC numbers to relevant Base64 alphabets. Closes #410 2018-11-19 14:34:52 +00:00
n1474335
045747f543 8.11.1 2018-11-14 12:27:55 +00:00
n1474335
b10c5e3256 Fixed faulty package-lock.json 2018-11-14 12:27:47 +00:00
n1474335
69df2e4183 Updated comments 2018-11-13 18:05:52 +00:00
n1474335
12ebd35c4d 8.11.0 2018-11-13 17:56:46 +00:00
n1474335
30c5f76cf0 Updated changelog 2018-11-13 17:56:40 +00:00
n1474335
3a979b6cda 'JSON to CSV' operation now escapes characters correctly. Added tests for CSV/JSON operations. 2018-11-13 17:54:43 +00:00
n1474335
863bdffa84 Added 'CSV to JSON' and 'JSON to CSV' operations. Closes #277 2018-11-09 17:40:19 +00:00
n1474335
42b956e402 Fixed JSDoc comment 2018-11-09 15:28:47 +00:00
n1474335
4acf7b4e4f 8.10.2 2018-11-09 15:25:22 +00:00
n1474335
42e881326f Added 'Binary' key option to all bitwise operations. Closes #398 2018-11-09 15:25:16 +00:00
n1474335
3c4893d7c7 8.10.1 2018-11-07 15:20:51 +00:00
n1474335
027aca4ab2 Merge branch 'qistoph-NumSortHex' 2018-11-07 15:20:43 +00:00
n1474335
2d471f551f Lint 2018-11-07 15:20:09 +00:00
n1474335
5c598b69b0 Merge branch 'NumSortHex' of https://github.com/qistoph/CyberChef into qistoph-NumSortHex 2018-11-07 15:15:39 +00:00
n1474335
037300de79 8.10.0 2018-11-07 15:10:57 +00:00
n1474335
6990dcae89 Updated changelog 2018-11-07 15:10:25 +00:00
n1474335
6e81d6dfcd Merge branch 'klaxon1-feature/remove-letter-accents' 2018-11-07 15:08:09 +00:00
n1474335
cea30465d8 Changed 'Remove Letter Accents' to 'Remove Diacritics' 2018-11-07 15:07:54 +00:00
n1474335
b301d16cb2 Merge branch 'feature/remove-letter-accents' of https://github.com/klaxon1/CyberChef into klaxon1-feature/remove-letter-accents 2018-11-07 14:57:05 +00:00
n1474335
19c002fcdd 8.9.2 2018-11-07 14:40:13 +00:00
n1474335
ab3a73fe58 Merge branch 'qistoph-FromNegs' 2018-11-07 14:39:51 +00:00
n1474335
91fc2c28dc Added signed feature to 'To Decimal' 2018-11-07 14:39:33 +00:00
n1474335
ca47ba3c7c Merge branch 'FromNegs' of https://github.com/qistoph/CyberChef into qistoph-FromNegs 2018-11-07 14:23:39 +00:00
n1474335
e1b456c01c 8.9.1 2018-11-07 14:21:26 +00:00
n1474335
5eb7e00eac Merge branch 'qistoph-HmacToggleStr' 2018-11-07 14:21:18 +00:00
n1474335
8bcf68c8a1 Merge branch 'HmacToggleStr' of https://github.com/qistoph/CyberChef into qistoph-HmacToggleStr 2018-11-07 14:18:24 +00:00
n1474335
520eaedd9a 8.9.0 2018-11-07 13:23:26 +00:00
n1474335
4c5e664ce0 Merge branch 'arnydo-add_url_defang' 2018-11-07 13:23:17 +00:00
n1474335
53c500eb1b Added various options to the 'Defang URL' operation. 2018-11-07 13:23:05 +00:00
n1474335
253346a201 Merge branch 'add_url_defang' of https://github.com/arnydo/CyberChef into arnydo-add_url_defang 2018-11-07 12:29:58 +00:00
n1474335
c5d82a76ab 8.8.8 2018-11-07 12:29:32 +00:00
n1474335
18a9dfffc7 Updated dependencies. Removed shim from HMAC op and postinstall js-to-mjs step due to CryptoAPI fixes. 2018-11-07 12:29:23 +00:00
n1474335
38838e4dca 8.8.7 2018-11-06 18:52:31 +00:00
n1474335
5c151d727b Merge branch 'bwhitn-bugfixes' 2018-11-06 18:52:17 +00:00
n1474335
2d5b157c91 Merge branch 'bugfixes' of https://github.com/bwhitn/CyberChef into bwhitn-bugfixes 2018-11-06 18:51:40 +00:00
n1474335
10d3d27a33 8.8.6 2018-11-05 12:48:29 +00:00
n1474335
1614442bd7 Fixed theming issues 2018-11-05 12:48:22 +00:00
bwhitn
a3c5b1e107 Simplified while loop in FromBase58 to match ToBase58 2018-10-28 18:37:00 -04:00
Chris van Marle
3f0af9cdea Add tests for From Decimal 2018-10-22 17:51:26 +08:00
Brian Whitney
f4de4de8c1 Fixing the babel, scrypt, and base58 issues 2018-10-21 21:10:49 -04:00
arnydo
69033a7343 Add Defang URL 2018-10-16 15:03:29 -04:00
arnydo
5a22106731 Create DefangURL.mjs 2018-10-16 15:02:39 -04:00
d98762625
5155d0ed56 Merge branch 'qistoph-RegexTooltip' 2018-10-12 15:44:17 +01:00
Chris van Marle
9be674103f Tooltip regex matches #279
Tooltip shows offset and matched groups
2018-10-12 15:42:44 +01:00
Chris van Marle
ba24e12454 Update hexadecimal sort after review
- Use Array.map instead of for-loop
- Add test case
2018-10-12 15:39:06 +02:00
Chris van Marle
b76aa16143 Fix Hash test 2018-10-12 13:54:40 +02:00
d98762625
8f7bb3a7c9 Merge pull request #371 from OllieGeek/master
CSS label / register-list Aesthetics
2018-10-12 12:12:48 +01:00
Chris van Marle
be2b466376 Use toggleString for Key in HMAC #263 2018-10-12 13:05:32 +02:00
n1474335
f957925aac 8.8.5 2018-10-12 10:51:01 +00:00
n1474335
1bf8d63d1a Merge branch 'Cynser-fix-wiki-urls' 2018-10-12 10:50:27 +00:00
n1474335
8875144307 Merge branch 'fix-wiki-urls' of https://github.com/Cynser/CyberChef into Cynser-fix-wiki-urls 2018-10-12 10:45:54 +00:00
n1474335
d5c01f387a 8.8.4 2018-10-12 10:43:01 +00:00
n1474335
32709cd60f Merge branch 'klaxon1-feature/improve-email-extract' 2018-10-12 10:42:21 +00:00
n1474335
aaf0a91975 Fixed populateOption overflows 2018-10-12 10:42:03 +00:00
n1474335
6cc6230b91 Merge branch 'feature/improve-email-extract' of https://github.com/klaxon1/CyberChef into klaxon1-feature/improve-email-extract 2018-10-12 10:34:00 +00:00
n1474335
dd630f20f8 8.8.3 2018-10-12 10:28:23 +00:00
n1474335
0c6efd95fa Modified bzip2 library export to use ES6 syntax. Fixes #382. 2018-10-12 10:28:15 +00:00
Chris van Marle
a276378887 Enable parsing of negative decimals #176 2018-10-12 10:08:24 +02:00
Cynser
98d861a639 Add check for Forensics Wiki URLs 2018-10-11 17:27:51 +01:00
Chris van Marle
3b3c27072f Fix lint errors 2018-10-11 15:50:58 +02:00
Klaxon
3089c39369 add test 2018-10-11 22:26:44 +10:00
Chris van Marle
0cbb17f7ce Support hexadecimal and other bases in numeric sorting 2018-10-11 14:23:05 +02:00
Klaxon
54793f2b78 update operation 2018-10-11 21:52:49 +10:00
Klaxon
f1ffe19ec8 Merge branch 'master' into feature/remove-letter-accents 2018-10-11 21:28:04 +10:00
Klaxon
e638fb69b5 fix comment 2018-10-11 20:52:12 +10:00
Klaxon
718a94b5e0 add tests for internationalized email addresses 2018-10-11 20:42:16 +10:00
Klaxon
3079059ce3 Update regex to support a wider variety of email addresses. 2018-10-11 18:25:05 +10:00
n1474335
d6c6981bc0 8.8.2 2018-10-10 15:49:11 +00:00
n1474335
8aeb7b60a7 Updated dependencies 2018-10-10 15:49:07 +00:00
n1474335
9197ac6510 8.8.1 2018-10-10 14:08:32 +00:00
n1474335
b67ad3073c Merge branch 'Cynser-csv-escape' 2018-10-10 14:08:20 +00:00
n1474335
4a4f37f888 Merge branch 'csv-escape' of https://github.com/Cynser/CyberChef into Cynser-csv-escape 2018-10-10 14:06:49 +00:00
n1474335
c55331f220 8.8.0 2018-10-10 13:59:37 +00:00
n1474335
757ec98554 Updated CHANGELOG 2018-10-10 13:59:28 +00:00
n1474335
14309f2069 Merge branch 'GCHQ77703-tlv' 2018-10-10 13:56:47 +00:00
n1474335
e6b89d571e Tidied up TLV operation and tests 2018-10-10 13:56:20 +00:00
Cynser
d957198fd6 Make the check for Wikipedia URLs slightly stricter 2018-10-07 22:52:08 +01:00
Cynser
903bd22999 Stop treating backslashes in CSV as escape character 2018-10-07 22:20:43 +01:00
Klaxon
04ee2fb3e4 add function to replace accent chars with latin chars 2018-10-03 13:26:01 +10:00
Klaxon
ac2466a304 create operation from npm run newop 2018-10-03 13:11:22 +10:00
Klaxon
ab4c9ef0d6 fix comment 2018-10-02 15:12:51 +10:00
Klaxon
a69063de9b add tests 2018-10-02 13:51:55 +10:00
Klaxon
62b76777c0 update regex to match more email address variations 2018-10-02 13:40:47 +10:00
OllieGeek
32a91bda0a CSS label / register-list Aesthetics
Occasionally depending on the page width and the operation used, the label.bmd-label-floating's wraps and covers the input - CSS to hide the wrap

On register-list, if the regex match is not a word and longer than the div, it'll over run - CSS of word-break: break-all
2018-09-24 22:56:38 +01:00
n1474335
a15af602e0 Merge branch 'tlv' of https://github.com/GCHQ77703/CyberChef into GCHQ77703-tlv 2018-08-31 15:12:54 +00:00
n1474335
ec9dfd2918 Updated NPM token 2018-08-31 14:08:18 +00:00
n1474335
016086ef4e 8.7.0 2018-08-31 14:00:29 +00:00
n1474335
2e5ea968ee Updated CHANGELOG 2018-08-31 14:00:24 +00:00
n1474335
5dde1c1c04 Merge branch 'GCHQ77703-jwt' 2018-08-31 13:58:33 +00:00
n1474335
be14d56eae Tidied up JWT operations 2018-08-31 13:58:06 +00:00
n1474335
100b097ace Merge branch 'jwt' of https://github.com/GCHQ77703/CyberChef into GCHQ77703-jwt 2018-08-31 12:20:37 +00:00
GCHQ 77703
3833c5f9fe Rename operation, add working tests, add info URL 2018-08-31 13:20:28 +01:00
n1474335
3470dd9f3b Merge branch 'GCHQ77703-alphabetical' 2018-08-31 11:41:43 +00:00
GCHQ 77703
c5e8649284 alphabetically sort tests 2018-08-29 22:48:47 +01:00
GCHQ 77703
a95f43aa4d Implement tests, fix options argument 2018-08-29 22:43:10 +01:00
n1474335
0420aa8edb Merge branch 'Sam-Dowling-patch-1' 2018-08-29 19:09:53 +00:00
n1474335
806b43dfec Merge branch 'patch-1' of https://github.com/Sam-Dowling/CyberChef into Sam-Dowling-patch-1 2018-08-29 19:09:19 +00:00
n1474335
98f4fe4c2b 8.6.2 2018-08-29 19:06:02 +00:00
n1474335
0d63b3cbae JSON output is now indented by default. Closes #350. 2018-08-29 19:05:58 +00:00
n1474335
7061c05f77 8.6.1 2018-08-29 18:58:01 +00:00
n1474335
9b9a182f9f Merge branch 'klaxon1-feature/improve-parse-ip-range' 2018-08-29 18:57:08 +00:00
n1474335
2d9e7fcc6d Added full stop to operation description 2018-08-29 18:56:50 +00:00
n1474335
56946a66aa Merge branch 'feature/improve-parse-ip-range' of https://github.com/klaxon1/CyberChef into klaxon1-feature/improve-parse-ip-range 2018-08-29 18:48:29 +00:00
n1474335
c9242e32fe Auto-generated configs and modules are now cleaned when starting a new dev or prod task 2018-08-29 18:21:46 +00:00
n1474335
22e8883934 8.6.0 2018-08-29 18:04:55 +00:00
n1474335
552a18d89a Updated CHANGELOG 2018-08-29 18:04:49 +00:00
n1474335
6b725e9114 Merge branch 'GCHQ77703-master' 2018-08-29 18:00:06 +00:00
n1474335
415beaa0b0 Tidied up Geohash operations 2018-08-29 17:59:48 +00:00
n1474335
e9fe227ed7 Merge branch 'master' of https://github.com/GCHQ77703/CyberChef into GCHQ77703-master 2018-08-29 17:48:23 +00:00
n1474335
c1be109592 8.5.1 2018-08-29 17:36:05 +00:00
n1474335
88e603bbf1 Merge branch 'PenguinGeorge-cascadexor-new' 2018-08-29 17:35:13 +00:00
n1474335
c7b2095bb4 Updated package-lock.json 2018-08-29 17:34:47 +00:00
n1474335
7396117d89 Merge branch 'cascadexor-new' of https://github.com/PenguinGeorge/CyberChef into PenguinGeorge-cascadexor-new 2018-08-29 17:31:59 +00:00
Sam Dowling
fd96bf345b Fixed typo
Fixed typo in operation description.
Wirlpool -> Whirlpool
2018-08-29 17:15:52 +01:00
Klaxon
2820660264 fix regex issues and ESlint errors and warnings
fix comment

fix ESlint errors and warnings

fix regex

add author
2018-08-28 23:07:53 +10:00
Klaxon
86145dbf67 add tests 2018-08-28 23:07:48 +10:00
Klaxon
135b17186e update description 2018-08-28 23:07:40 +10:00
Klaxon
ce494339ef add parse IPv6 list 2018-08-28 23:07:32 +10:00
Klaxon
dd5af7eb10 add parse IPv4 list 2018-08-28 23:07:04 +10:00
GCHQ 77703
3abe99078e Fix linting 2018-08-27 16:03:15 +01:00
GCHQ 77703
edbd540c68 Add Dysfunctional Test 2018-08-27 15:42:07 +01:00
GCHQ 77703
06d9302d96 Implement TLV / KLV 2018-08-27 14:57:24 +01:00
GCHQ 77703
032b4bed7f Add Length Value Decoder Operatoin 2018-08-27 01:17:06 +01:00
GCHQ 77703
8559f5c8ea Add JWT Verify, Decode and Sign 2018-08-26 23:16:13 +01:00
GCHQ 77703
91133172d5 Remove subdomain from Wikipedia 2018-08-26 18:51:52 +01:00
GCHQ 77703
001f3f30cd Remove multi-line operations 2018-08-26 18:06:02 +01:00
GCHQ 77703
a1b1059ad1 Revert package-lock.json changes 2018-08-26 17:39:33 +01:00
GCHQ 77703
69a0122fea Fix "From Geohash" test 2018-08-26 17:20:50 +01:00
GCHQ 77703
3d505b4248 Add ToGeohash and FromGeohash operations 2018-08-26 14:27:15 +01:00
George J
70d4e3394c Updated XOR to include Cascade scheme 2018-08-24 22:33:24 +01:00
n1474335
3905c01a0d 8.5.0 2018-08-24 01:07:56 +01:00
n1474335
2a49af1ec3 'To Braille' and 'From Braille' operations added. Closes #255 2018-08-24 01:07:51 +01:00
n1474335
3d4f54e8bc 8.4.3 2018-08-24 00:32:57 +01:00
n1474335
61f2f2d2e3 'Show Base64 offsets' operation show supports base64 input. Closes #276 2018-08-24 00:32:52 +01:00
n1474335
00058bd5c7 8.4.2 2018-08-23 23:24:05 +01:00
n1474335
383fe50fc9 Support for negative values in 'Drop bytes' and 'Take bytes'. Closes #266 2018-08-23 23:23:00 +01:00
n1474335
e4fdadc573 8.4.1 2018-08-23 22:56:46 +01:00
n1474335
032f8808ef Fixed typo in Z85 alphabet 2018-08-23 22:56:18 +01:00
216 changed files with 12010 additions and 3320 deletions

View File

@@ -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"]
}]
]
}

View File

@@ -9,6 +9,6 @@ trim_trailing_whitespace = true
indent_style = space
indent_size = 4
[{package.json,.travis.yml}]
[{package.json,.travis.yml,nightwatch.json}]
indent_style = space
indent_size = 2

View File

@@ -1,10 +1,12 @@
{
"parser": "babel-eslint",
"parserOptions": {
"ecmaVersion": 9,
"ecmaFeatures": {
"impliedStrict": true
},
"sourceType": "module"
"sourceType": "module",
"allowImportExportEverywhere": true
},
"env": {
"browser": true,
@@ -87,6 +89,15 @@
"no-var": "error",
"prefer-const": "error"
},
"overrides": [
{
"files": "tests/**/*",
"rules": {
"no-unused-expressions": "off",
"no-console": "off"
}
}
],
"globals": {
"$": false,
"jQuery": false,

1
.gitignore vendored
View File

@@ -9,4 +9,5 @@ docs/*
src/core/config/modules/*
src/core/config/OperationConfig.json
src/core/operations/index.mjs
tests/browser/output/*

View File

@@ -1,15 +1,19 @@
language: node_js
node_js:
- node
addons:
chrome: stable
install: npm install
before_script:
- npm install -g grunt
- export NODE_OPTIONS=--max_old_space_size=2048
script:
- grunt lint
- grunt test
- grunt docs
- grunt node
- grunt prod --msg="$COMPILE_MSG"
- xvfb-run --server-args="-screen 0 1200x800x24" grunt testui
before_deploy:
- grunt exec:sitemap
- grunt copy:ghPages
@@ -36,7 +40,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

View File

@@ -1,5 +1,69 @@
# Changelog
All notable changes to CyberChef 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.24.0] - 2019-02-08
- 'DNS over HTTPS' operation added [@h345983745] | [#489]
### [8.23.1] - 2019-01-18
- 'Convert co-ordinate format' operation added [@j433866] | [#476]
### [8.23.0] - 2019-01-18
- 'YARA Rules' operation added [@artemisbot] | [#468]
### [8.22.0] - 2019-01-10
- 'Subsection' operation added [@j433866] | [#467]
### [8.21.0] - 2019-01-10
- 'To Case Insensitive Regex' and 'From Case Insensitive Regex' operations added [@masq] | [#461]
### [8.20.0] - 2019-01-09
- 'Generate Lorem Ipsum' operation added [@klaxon1] | [#455]
### [8.19.0] - 2018-12-30
- UI test suite added to confirm that the app loads correctly in a reasonable time and that various operations from each module can be run [@n1474335] | [#458]
### [8.18.0] - 2018-12-26
- 'Split Colour Channels' operation added [@artemisbot] | [#449]
### [8.17.0] - 2018-12-25
- 'Generate QR Code' and 'Parse QR Code' operations added [@j433866] | [#448]
### [8.16.0] - 2018-12-19
- 'Play Media' operation added [@anthony-arnold] | [#446]
### [8.15.0] - 2018-12-18
- '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]
@@ -31,7 +95,7 @@ All notable changes to CyberChef will be documented in this file.
- Added support for loading, processing and downloading files up to 500MB [@n1474335] | [#224]
## [6.0.0] - 2017-09-19
- 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 allowing long-running operations to be cancelled [@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
@@ -41,6 +105,28 @@ All notable changes to CyberChef will be documented in this file.
- Initial open source commit [@n1474335] | [b1d73a72](https://github.com/gchq/CyberChef/commit/b1d73a725dc7ab9fb7eb789296efd2b7e4b08306)
[8.24.0]: https://github.com/gchq/CyberChef/releases/tag/v8.24.0
[8.23.1]: https://github.com/gchq/CyberChef/releases/tag/v8.23.1
[8.23.0]: https://github.com/gchq/CyberChef/releases/tag/v8.23.0
[8.22.0]: https://github.com/gchq/CyberChef/releases/tag/v8.22.0
[8.21.0]: https://github.com/gchq/CyberChef/releases/tag/v8.21.0
[8.20.0]: https://github.com/gchq/CyberChef/releases/tag/v8.20.0
[8.19.0]: https://github.com/gchq/CyberChef/releases/tag/v8.19.0
[8.18.0]: https://github.com/gchq/CyberChef/releases/tag/v8.18.0
[8.17.0]: https://github.com/gchq/CyberChef/releases/tag/v8.17.0
[8.16.0]: https://github.com/gchq/CyberChef/releases/tag/v8.16.0
[8.15.0]: https://github.com/gchq/CyberChef/releases/tag/v8.15.0
[8.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
@@ -53,18 +139,31 @@ All notable changes to CyberChef will be documented in this file.
[@n1474335]: https://github.com/n1474335
[@d98762625]: https://github.com/d98762625
[@j433866]: https://github.com/j433866
[@GCHQ77703]: https://github.com/GCHQ77703
[@h345983745]: https://github.com/h345983745
[@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
[@masq]: https://github.com/masq
[#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
@@ -74,3 +173,22 @@ All notable changes to CyberChef will be documented in this file.
[#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
[#449]: https://github.com/gchq/CyberChef/pull/449
[#455]: https://github.com/gchq/CyberChef/pull/455
[#458]: https://github.com/gchq/CyberChef/pull/458
[#461]: https://github.com/gchq/CyberChef/pull/461
[#467]: https://github.com/gchq/CyberChef/pull/467
[#468]: https://github.com/gchq/CyberChef/pull/468
[#476]: https://github.com/gchq/CyberChef/pull/476
[#489]: https://github.com/gchq/CyberChef/pull/489

View File

@@ -2,6 +2,7 @@
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
const NodeExternals = require("webpack-node-externals");
const Inliner = require("web-resource-inliner");
const glob = require("glob");
@@ -22,15 +23,19 @@ 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.",
["clean:node", "clean:config", "exec:generateConfig", "webpack:node", "chmod:build"]);
grunt.registerTask("test",
"A task which runs all the tests in test/tests.",
["exec:generateConfig", "exec:tests"]);
"A task which runs all the operation tests in the tests directory.",
["exec:generateConfig", "exec:opTests"]);
grunt.registerTask("testui",
"A task which runs all the UI tests in the tests directory. The prod task must already have been run.",
["connect:prod", "exec:browserTests"]);
grunt.registerTask("docs",
"Compiles documentation in the /docs directory.",
@@ -38,7 +43,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",
@@ -66,6 +71,7 @@ module.exports = function (grunt) {
grunt.loadNpmTasks("grunt-exec");
grunt.loadNpmTasks("grunt-accessibility");
grunt.loadNpmTasks("grunt-concurrent");
grunt.loadNpmTasks("grunt-contrib-connect");
// Project configuration
@@ -143,11 +149,11 @@ module.exports = function (grunt) {
options: {
configFile: "./.eslintrc.json"
},
configs: ["Gruntfile.js"],
configs: ["*.{js,mjs}"],
core: ["src/core/**/*.{js,mjs}", "!src/core/vendor/**/*", "!src/core/operations/legacy/**/*"],
web: ["src/web/**/*.{js,mjs}"],
node: ["src/node/**/*.{js,mjs}"],
tests: ["test/**/*.{js,mjs}"],
tests: ["tests/**/*.{js,mjs}"],
},
jsdoc: {
options: {
@@ -179,37 +185,45 @@ module.exports = function (grunt) {
},
webpack: {
options: webpackConfig,
web: {
mode: "production",
target: "web",
entry: Object.assign({
main: "./src/web/index.js",
sitemap: "./src/web/static/sitemap.js"
}, moduleEntryPoints),
output: {
path: __dirname + "/build/prod"
},
resolve: {
alias: {
"./config/modules/OpModules": "./config/modules/Default"
}
},
plugins: [
new webpack.DefinePlugin(BUILD_CONSTANTS),
new HtmlWebpackPlugin({
filename: "index.html",
template: "./src/web/html/index.html",
chunks: ["main"],
compileTime: compileTime,
version: pkg.version,
minify: {
removeComments: true,
collapseWhitespace: true,
minifyJS: true,
minifyCSS: true
web: () => {
return {
mode: "production",
target: "web",
entry: Object.assign({
main: "./src/web/index.js",
sitemap: "./src/web/static/sitemap.js"
}, moduleEntryPoints),
output: {
path: __dirname + "/build/prod",
globalObject: "this"
},
resolve: {
alias: {
"./config/modules/OpModules": "./config/modules/Default"
}
}),
]
},
plugins: [
new webpack.DefinePlugin(BUILD_CONSTANTS),
new HtmlWebpackPlugin({
filename: "index.html",
template: "./src/web/html/index.html",
chunks: ["main"],
compileTime: compileTime,
version: pkg.version,
minify: {
removeComments: true,
collapseWhitespace: true,
minifyJS: true,
minifyCSS: true
}
}),
new BundleAnalyzerPlugin({
analyzerMode: "static",
reportFilename: "BundleAnalyzerReport.html",
openAnalyzer: false
}),
]
};
},
webInline: {
mode: "production",
@@ -238,19 +252,6 @@ module.exports = function (grunt) {
}),
]
},
tests: {
mode: "development",
target: "node",
entry: "./test/index.mjs",
externals: [NodeExternals()],
output: {
filename: "index.js",
path: __dirname + "/build/test"
},
plugins: [
new webpack.DefinePlugin(BUILD_CONSTANTS)
]
},
node: {
mode: "production",
target: "node",
@@ -280,7 +281,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: {
@@ -295,6 +300,9 @@ module.exports = function (grunt) {
"./config/modules/OpModules": "./config/modules/Default"
}
},
output: {
globalObject: "this",
},
plugins: [
new webpack.DefinePlugin(BUILD_CONSTANTS),
new HtmlWebpackPlugin({
@@ -308,6 +316,14 @@ module.exports = function (grunt) {
}
}
},
connect: {
prod: {
options: {
port: 8000,
base: "build/prod/"
}
}
},
copy: {
ghPages: {
options: {
@@ -379,16 +395,17 @@ module.exports = function (grunt) {
generateConfig: {
command: [
"echo '\n--- Regenerating config files. ---'",
"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",
"echo [] > src/core/config/OperationConfig.json",
"node --experimental-modules --no-warnings --no-deprecation src/core/config/scripts/generateOpsIndex.mjs",
"node --experimental-modules --no-warnings --no-deprecation src/core/config/scripts/generateConfig.mjs",
"echo '--- Config scripts finished. ---\n'"
].join(";")
},
tests: {
command: "node --experimental-modules test/index.mjs"
opTests: {
command: "node --experimental-modules --no-warnings --no-deprecation tests/operations/index.mjs"
},
browserTests: {
command: "./node_modules/.bin/nightwatch --env prod,inline"
}
},
});

24
babel.config.js Normal file
View File

@@ -0,0 +1,24 @@
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-syntax-dynamic-import",
["babel-plugin-transform-builtin-extend", {
"globals": ["Error"]
}]
]
};
};

34
nightwatch.json Normal file
View File

@@ -0,0 +1,34 @@
{
"src_folders": ["tests/browser"],
"output_folder": "tests/browser/output",
"test_settings": {
"default": {
"launch_url": "http://localhost:8080",
"webdriver": {
"start_process": true,
"server_path": "./node_modules/.bin/chromedriver",
"port": 9515,
"log_path": false
},
"desiredCapabilities": {
"browserName": "chrome"
}
},
"dev": {
"launch_url": "http://localhost:8080"
},
"prod": {
"launch_url": "http://localhost:8000/index.html"
},
"inline": {
"launch_url": "http://localhost:8000/cyberchef.htm"
}
}
}

7806
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "cyberchef",
"version": "8.4.0",
"version": "8.24.2",
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
"author": "n1474335 <n1474335@gmail.com>",
"homepage": "https://gchq.github.io/CyberChef",
@@ -30,45 +30,50 @@
"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",
"bootstrap": "^4.1.3",
"colors": "^1.3.1",
"css-loader": "^1.0.0",
"eslint": "^5.3.0",
"@babel/core": "^7.2.2",
"@babel/preset-env": "^7.2.3",
"autoprefixer": "^9.4.3",
"babel-eslint": "^10.0.1",
"babel-loader": "^8.0.4",
"babel-plugin-syntax-dynamic-import": "^6.18.0",
"bootstrap": "^4.2.1",
"chromedriver": "^2.45.0",
"colors": "^1.3.3",
"css-loader": "^2.1.0",
"eslint": "^5.12.1",
"exports-loader": "^0.7.0",
"extract-text-webpack-plugin": "^4.0.0-alpha0",
"file-loader": "^1.1.11",
"file-loader": "^3.0.1",
"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-connect": "^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",
"mini-css-extract-plugin": "^0.5.0",
"nightwatch": "^1.0.18",
"node-sass": "^4.11.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.28.3",
"webpack-bundle-analyzer": "^3.0.3",
"webpack-dev-server": "^3.1.14",
"webpack-node-externals": "^1.7.2",
"worker-loader": "^2.0.0"
},
@@ -77,61 +82,67 @@
"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.2",
"bootstrap-colorpicker": "^2.5.3",
"bootstrap-material-design": "^4.1.1",
"bson": "^3.0.2",
"bson": "^4.0.1",
"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",
"geodesy": "^1.1.3",
"highlight.js": "^9.13.1",
"jimp": "^0.6.0",
"jquery": "^3.3.1",
"js-crc": "^0.2.0",
"js-sha3": "^0.7.0",
"jsbn": "^1.1.0",
"jsesc": "^2.5.1",
"js-sha3": "^0.8.0",
"jsesc": "^2.5.2",
"jsonpath": "^1.0.0",
"jsonwebtoken": "^8.4.0",
"jsqr": "^1.1.1",
"jsrsasign": "8.0.12",
"kbpgp": "^2.0.77",
"lodash": "^4.17.10",
"kbpgp": "^2.0.82",
"libyara-wasm": "0.0.11",
"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": "^2.23.0",
"moment-timezone": "^0.5.23",
"ngeohash": "^0.6.3",
"node-forge": "^0.7.6",
"node-md6": "^0.1.0",
"notepack.io": "^2.1.3",
"notepack.io": "^2.2.0",
"nwmatcher": "^1.4.4",
"otp": "^0.1.3",
"popper.js": "^1.14.4",
"popper.js": "^1.14.6",
"qr-image": "^3.2.0",
"scryptsy": "^2.0.0",
"snackbarjs": "^1.1.0",
"sortablejs": "^1.7.0",
"split.js": "^1.3.5",
"sortablejs": "^1.8.0-rc1",
"split.js": "^1.5.10",
"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",
"xpath": "0.0.27",
"xregexp": "^4.2.0",
"xregexp": "^4.2.4",
"zlibjs": "^0.3.1"
},
"scripts": {
"start": "grunt dev",
"build": "grunt prod",
"test": "grunt test",
"testui": "grunt testui",
"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"
}
}

View File

@@ -157,9 +157,9 @@ class Chef {
* @param {number} pos.end - The end offset.
* @returns {Object}
*/
calculateHighlights(recipeConfig, direction, pos) {
async calculateHighlights(recipeConfig, direction, pos) {
const recipe = new Recipe(recipeConfig);
const highlights = recipe.generateHighlightList();
const highlights = await recipe.generateHighlightList();
if (!highlights) return false;

View File

@@ -157,8 +157,8 @@ async function getDishAs(data) {
* @param {number} pos.start - The start offset.
* @param {number} pos.end - The end offset.
*/
function calculateHighlights(recipeConfig, direction, pos) {
pos = self.chef.calculateHighlights(recipeConfig, direction, pos);
async function calculateHighlights(recipeConfig, direction, pos) {
pos = await self.chef.calculateHighlights(recipeConfig, direction, pos);
self.postMessage({
action: "highlightsCalculated",

View File

@@ -6,6 +6,7 @@
*/
import Utils from "./Utils";
import DishError from "./errors/DishError";
import BigNumber from "bignumber.js";
import log from "loglevel";
@@ -61,7 +62,7 @@ class Dish {
case "list<file>":
return Dish.LIST_FILE;
default:
throw "Invalid data type string. No matching enum.";
throw new DishError("Invalid data type string. No matching enum.");
}
}
@@ -93,7 +94,7 @@ class Dish {
case Dish.LIST_FILE:
return "List<File>";
default:
throw "Invalid data type enum. No matching type.";
throw new DishError("Invalid data type enum. No matching type.");
}
}
@@ -117,7 +118,7 @@ class Dish {
if (!this.valid()) {
const sample = Utils.truncate(JSON.stringify(this.value), 13);
throw "Data is not a valid " + Dish.enumLookup(type) + ": " + sample;
throw new DishError(`Data is not a valid ${Dish.enumLookup(type)}: ${sample}`);
}
}
@@ -151,77 +152,85 @@ class Dish {
const byteArrayToStr = notUTF8 ? Utils.byteArrayToChars : Utils.byteArrayToUtf8;
// Convert data to intermediate byteArray type
switch (this.type) {
case Dish.STRING:
this.value = this.value ? Utils.strToByteArray(this.value) : [];
break;
case Dish.NUMBER:
this.value = typeof this.value === "number" ? Utils.strToByteArray(this.value.toString()) : [];
break;
case Dish.HTML:
this.value = this.value ? Utils.strToByteArray(Utils.unescapeHtml(Utils.stripHtmlTags(this.value, true))) : [];
break;
case Dish.ARRAY_BUFFER:
// Array.from() would be nicer here, but it's slightly slower
this.value = Array.prototype.slice.call(new Uint8Array(this.value));
break;
case Dish.BIG_NUMBER:
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)) : [];
break;
case Dish.FILE:
this.value = await Utils.readFile(this.value);
this.value = Array.prototype.slice.call(this.value);
break;
case Dish.LIST_FILE:
this.value = await Promise.all(this.value.map(async f => Utils.readFile(f)));
this.value = this.value.map(b => Array.prototype.slice.call(b));
this.value = [].concat.apply([], this.value);
break;
default:
break;
try {
switch (this.type) {
case Dish.STRING:
this.value = this.value ? Utils.strToByteArray(this.value) : [];
break;
case Dish.NUMBER:
this.value = typeof this.value === "number" ? Utils.strToByteArray(this.value.toString()) : [];
break;
case Dish.HTML:
this.value = this.value ? Utils.strToByteArray(Utils.unescapeHtml(Utils.stripHtmlTags(this.value, true))) : [];
break;
case Dish.ARRAY_BUFFER:
// Array.from() would be nicer here, but it's slightly slower
this.value = Array.prototype.slice.call(new Uint8Array(this.value));
break;
case Dish.BIG_NUMBER:
this.value = BigNumber.isBigNumber(this.value) ? Utils.strToByteArray(this.value.toFixed()) : [];
break;
case Dish.JSON:
this.value = this.value ? Utils.strToByteArray(JSON.stringify(this.value, null, 4)) : [];
break;
case Dish.FILE:
this.value = await Utils.readFile(this.value);
this.value = Array.prototype.slice.call(this.value);
break;
case Dish.LIST_FILE:
this.value = await Promise.all(this.value.map(async f => Utils.readFile(f)));
this.value = this.value.map(b => Array.prototype.slice.call(b));
this.value = [].concat.apply([], this.value);
break;
default:
break;
}
} catch (err) {
throw new DishError(`Error translating from ${Dish.enumLookup(this.type)} to byteArray: ${err}`);
}
this.type = Dish.BYTE_ARRAY;
// Convert from byteArray to toType
switch (toType) {
case Dish.STRING:
case Dish.HTML:
this.value = this.value ? byteArrayToStr(this.value) : "";
this.type = Dish.STRING;
break;
case Dish.NUMBER:
this.value = this.value ? parseFloat(byteArrayToStr(this.value)) : 0;
this.type = Dish.NUMBER;
break;
case Dish.ARRAY_BUFFER:
this.value = new Uint8Array(this.value).buffer;
this.type = Dish.ARRAY_BUFFER;
break;
case Dish.BIG_NUMBER:
try {
this.value = new BigNumber(byteArrayToStr(this.value));
} catch (err) {
this.value = new BigNumber(NaN);
}
this.type = Dish.BIG_NUMBER;
break;
case Dish.JSON:
this.value = JSON.parse(byteArrayToStr(this.value));
this.type = Dish.JSON;
break;
case Dish.FILE:
this.value = new File(this.value, "unknown");
break;
case Dish.LIST_FILE:
this.value = [new File(this.value, "unknown")];
this.type = Dish.LIST_FILE;
break;
default:
break;
try {
switch (toType) {
case Dish.STRING:
case Dish.HTML:
this.value = this.value ? byteArrayToStr(this.value) : "";
this.type = Dish.STRING;
break;
case Dish.NUMBER:
this.value = this.value ? parseFloat(byteArrayToStr(this.value)) : 0;
this.type = Dish.NUMBER;
break;
case Dish.ARRAY_BUFFER:
this.value = new Uint8Array(this.value).buffer;
this.type = Dish.ARRAY_BUFFER;
break;
case Dish.BIG_NUMBER:
try {
this.value = new BigNumber(byteArrayToStr(this.value));
} catch (err) {
this.value = new BigNumber(NaN);
}
this.type = Dish.BIG_NUMBER;
break;
case Dish.JSON:
this.value = JSON.parse(byteArrayToStr(this.value));
this.type = Dish.JSON;
break;
case Dish.FILE:
this.value = new File(this.value, "unknown");
break;
case Dish.LIST_FILE:
this.value = [new File(this.value, "unknown")];
this.type = Dish.LIST_FILE;
break;
default:
break;
}
} catch (err) {
throw new DishError(`Error translating from byteArray to ${Dish.enumLookup(toType)}: ${err}`);
}
}
@@ -256,7 +265,7 @@ class Dish {
case Dish.ARRAY_BUFFER:
return this.value instanceof ArrayBuffer;
case Dish.BIG_NUMBER:
return this.value instanceof BigNumber;
return BigNumber.isBigNumber(this.value);
case Dish.JSON:
// All values can be serialised in some manner, so we return true in all cases
return true;
@@ -357,7 +366,7 @@ class Dish {
);
break;
default:
throw new Error("Cannot clone Dish, unknown type");
throw new DishError("Cannot clone Dish, unknown type");
}
return newDish;

View File

@@ -23,8 +23,10 @@ class Ingredient {
this._value = null;
this.disabled = false;
this.hint = "";
this.rows = 0;
this.toggleValues = [];
this.target = null;
this.defaultIndex = 0;
if (ingredientConfig) {
this._parseConfig(ingredientConfig);
@@ -44,8 +46,10 @@ class Ingredient {
this.defaultValue = ingredientConfig.value;
this.disabled = !!ingredientConfig.disabled;
this.hint = ingredientConfig.hint || false;
this.rows = ingredientConfig.rows || false;
this.toggleValues = ingredientConfig.toggleValues;
this.target = typeof ingredientConfig.target !== "undefined" ? ingredientConfig.target : null;
this.defaultIndex = typeof ingredientConfig.defaultIndex !== "undefined" ? ingredientConfig.defaultIndex : 0;
}
@@ -93,6 +97,7 @@ class Ingredient {
case "binaryString":
case "binaryShortString":
case "editableOption":
case "editableOptionShort":
return Utils.parseEscapedChars(data);
case "byteArray":
if (typeof data == "string") {

View File

@@ -23,6 +23,7 @@ class Operation {
this._breakpoint = false;
this._disabled = false;
this._flowControl = false;
this._manualBake = false;
this._ingList = [];
// Public fields
@@ -179,8 +180,10 @@ class Operation {
if (ing.toggleValues) conf.toggleValues = ing.toggleValues;
if (ing.hint) conf.hint = ing.hint;
if (ing.rows) conf.rows = ing.rows;
if (ing.disabled) conf.disabled = ing.disabled;
if (ing.target) conf.target = ing.target;
if (ing.defaultIndex) conf.defaultIndex = ing.defaultIndex;
return conf;
});
}
@@ -280,6 +283,7 @@ class Operation {
return this._flowControl;
}
/**
* Set whether this Operation is a flowcontrol op.
*
@@ -289,6 +293,26 @@ class Operation {
this._flowControl = !!value;
}
/**
* Returns true if this Operation should not trigger AutoBake.
*
* @returns {boolean}
*/
get manualBake() {
return this._manualBake;
}
/**
* Set whether this Operation should trigger AutoBake.
*
* @param {boolean} value
*/
set manualBake(value) {
this._manualBake = !!value;
}
}
export default Operation;

View File

@@ -4,12 +4,15 @@
* @license Apache-2.0
*/
// import Operation from "./Operation.js";
import OpModules from "./config/modules/OpModules";
import OperationConfig from "./config/OperationConfig.json";
import OperationError from "./errors/OperationError";
import Operation from "./Operation";
import DishError from "./errors/DishError";
import log from "loglevel";
// Cache container for modules
let modules = null;
/**
* The Recipe controls a list of Operations and the Dish they operate on.
*/
@@ -36,16 +39,43 @@ class Recipe {
* @param {Object} recipeConfig
*/
_parseConfig(recipeConfig) {
for (let c = 0; c < recipeConfig.length; c++) {
const operationName = recipeConfig[c].op;
const opConf = OperationConfig[operationName];
const opObj = OpModules[opConf.module][operationName];
const operation = new opObj();
operation.ingValues = recipeConfig[c].args;
operation.breakpoint = recipeConfig[c].breakpoint;
operation.disabled = recipeConfig[c].disabled;
this.addOperation(operation);
recipeConfig.forEach(c => {
this.opList.push({
name: c.op,
module: OperationConfig[c.op].module,
ingValues: c.args,
breakpoint: c.breakpoint,
disabled: c.disabled,
});
});
}
/**
* Populate elements of opList with operation instances.
* Dynamic import here removes top-level cyclic dependency issue.
*
* @private
*/
async _hydrateOpList() {
if (!modules) {
// Using Webpack Magic Comments to force the dynamic import to be included in the main chunk
// https://webpack.js.org/api/module-methods/
modules = await import(/* webpackMode: "eager" */ "./config/modules/OpModules");
modules = modules.default;
}
this.opList = this.opList.map(o => {
if (o instanceof Operation) {
return o;
} else {
const op = new modules[o.module][o.name]();
op.ingValues = o.ingValues;
op.breakpoint = o.breakpoint;
op.disabled = o.disabled;
return op;
}
});
}
@@ -55,7 +85,10 @@ class Recipe {
* @returns {Object[]}
*/
get config() {
return this.opList.map(op => op.config);
return this.opList.map(op => ({
op: op.name,
args: op.ingValues,
}));
}
@@ -75,7 +108,19 @@ class Recipe {
* @param {Operation[]} operations
*/
addOperations(operations) {
this.opList = this.opList.concat(operations);
operations.forEach(o => {
if (o instanceof Operation) {
this.opList.push(o);
} else {
this.opList.push({
name: o.name,
module: o.module,
ingValues: o.args,
breakpoint: o.breakpoint,
disabled: o.disabled,
});
}
});
}
@@ -108,7 +153,7 @@ class Recipe {
/**
* Returns true if there is an Flow Control Operation in this Recipe.
* Returns true if there is a Flow Control Operation in this Recipe.
*
* @returns {boolean}
*/
@@ -137,6 +182,8 @@ class Recipe {
if (startFrom === 0) this.lastRunOp = null;
await this._hydrateOpList();
log.debug(`[*] Executing recipe of ${this.opList.length} operations, starting at ${startFrom}`);
for (let i = startFrom; i < this.opList.length; i++) {
@@ -183,6 +230,10 @@ class Recipe {
// native types is not fully supported yet.
dish.set(err.message, "string");
return i;
} else if (err instanceof DishError ||
(err.type && err.type === "DishError")) {
dish.set(err.message, "string");
return i;
} else {
const e = typeof err == "string" ? { message: err } : err;
@@ -250,7 +301,8 @@ class Recipe {
* @returns {function} highlights[].b
* @returns {Object[]} highlights[].args
*/
generateHighlightList() {
async generateHighlightList() {
await this._hydrateOpList();
const highlights = [];
for (let i = 0; i < this.opList.length; i++) {

View File

@@ -5,10 +5,10 @@
*/
import utf8 from "utf8";
import moment from "moment-timezone";
import {fromBase64} from "./lib/Base64";
import {fromBase64, toBase64} from "./lib/Base64";
import {fromHex} from "./lib/Hex";
import {fromDecimal} from "./lib/Decimal";
import {fromBinary} from "./lib/Binary";
/**
@@ -298,7 +298,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 +313,8 @@ class Utils {
*/
static convertToByteArray(str, type) {
switch (type.toLowerCase()) {
case "binary":
return fromBinary(str);
case "hex":
return fromHex(str);
case "decimal":
@@ -333,7 +335,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 +350,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 +559,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 +572,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;
}
@@ -790,38 +796,6 @@ class Utils {
}
/**
* Expresses a number of milliseconds in a human readable format.
*
* Range | Sample Output
* -----------------------------|-------------------------------
* 0 to 45 seconds | a few seconds ago
* 45 to 90 seconds | a minute ago
* 90 seconds to 45 minutes | 2 minutes ago ... 45 minutes ago
* 45 to 90 minutes | an hour ago
* 90 minutes to 22 hours | 2 hours ago ... 22 hours ago
* 22 to 36 hours | a day ago
* 36 hours to 25 days | 2 days ago ... 25 days ago
* 25 to 45 days | a month ago
* 45 to 345 days | 2 months ago ... 11 months ago
* 345 to 545 days (1.5 years) | a year ago
* 546 days+ | 2 years ago ... 20 years ago
*
* @param {number} ms
* @returns {string}
*
* @example
* // returns "3 minutes"
* Utils.fuzzyTime(152435);
*
* // returns "5 days"
* Utils.fuzzyTime(456851321);
*/
static fuzzyTime(ms) {
return moment.duration(ms, "milliseconds").humanize();
}
/**
* Formats a list of files or directories.
*
@@ -843,6 +817,17 @@ class Utils {
return html;
};
const formatContent = function (buff, type) {
if (type.startsWith("image")) {
let dataURI = "data:";
dataURI += type + ";";
dataURI += "base64," + toBase64(buff);
return "<img style='max-width: 100%;' src='" + dataURI + "'>";
} else {
return `<pre>${Utils.escapeHtml(Utils.arrayBufferToStr(buff.buffer))}</pre>`;
}
};
const formatFile = async function(file, i) {
const buff = await Utils.readFile(file);
const blob = new Blob(
@@ -872,7 +857,7 @@ class Utils {
</div>
<div id='collapse${i}' class='collapse' aria-labelledby='heading${i}' data-parent="#files">
<div class='card-body'>
<pre>${Utils.escapeHtml(Utils.arrayBufferToStr(buff.buffer))}</pre>
${formatContent(buff, file.type)}
</div>
</div>
</div>`;

View File

@@ -25,6 +25,8 @@
"From Base32",
"To Base58",
"From Base58",
"To Base62",
"From Base62",
"To Base85",
"From Base85",
"To Base",
@@ -49,9 +51,15 @@
"Change IP format",
"Encode text",
"Decode text",
"Text Encoding Brute Force",
"Swap endianness",
"To MessagePack",
"From MessagePack"
"From MessagePack",
"To Braille",
"From Braille",
"Parse TLV",
"CSV to JSON",
"JSON to CSV"
]
},
{
@@ -81,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"
]
},
@@ -140,6 +155,7 @@
"name": "Networking",
"ops": [
"HTTP request",
"DNS over HTTPS",
"Strip HTTP headers",
"Dechunk HTTP response",
"Parse User Agent",
@@ -153,7 +169,8 @@
"Change IP format",
"Group IP addresses",
"Encode NetBIOS Name",
"Decode NetBIOS Name"
"Decode NetBIOS Name",
"Defang URL"
]
},
{
@@ -161,6 +178,7 @@
"ops": [
"Encode text",
"Decode text",
"Remove Diacritics",
"Unescape Unicode Characters"
]
},
@@ -172,6 +190,8 @@
"Remove null bytes",
"To Upper case",
"To Lower case",
"To Case Insensitive Regex",
"From Case Insensitive Regex",
"Add line numbers",
"Remove line numbers",
"To Table",
@@ -196,6 +216,7 @@
"Convert mass",
"Convert speed",
"Convert data units",
"Convert co-ordinate format",
"Parse UNIX file permissions",
"Swap endianness",
"Parse colour code",
@@ -322,23 +343,40 @@
"From MessagePack"
]
},
{
"name": "Forensics",
"ops": [
"Detect File Type",
"Scan for Embedded Files",
"Remove EXIF",
"Extract EXIF"
]
},
{
"name": "Multimedia",
"ops": [
"Render Image",
"Play Media",
"Remove EXIF",
"Extract EXIF",
"Split Colour Channels"
]
},
{
"name": "Other",
"ops": [
"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",
"Generate Lorem Ipsum",
"Numberwang",
"XKCD Random Number"
]
@@ -348,6 +386,7 @@
"ops": [
"Magic",
"Fork",
"Subsection",
"Merge",
"Register",
"Label",

View File

@@ -41,6 +41,7 @@ for (const opObj in Ops) {
inputType: op.inputType,
outputType: op.presentType,
flowControl: op.flowControl,
manualBake: op.manualBake,
args: op.args
};

View File

@@ -222,7 +222,7 @@ export default ${moduleName};
console.log(`\nNext steps:
1. Add your operation to ${colors.green("src/core/config/Categories.json")}
2. Write your operation code.
3. Write tests in ${colors.green("test/tests/operations/")}
3. Write tests in ${colors.green("tests/operations/tests/")}
4. Run ${colors.cyan("npm run lint")} and ${colors.cyan("npm run test")}
5. Submit a Pull Request to get your operation added to the official CyberChef repository.`);

View File

@@ -0,0 +1,26 @@
/**
* Custom error type for handling Dish type errors.
* i.e. where the Dish cannot be successfully translated between types
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
class DishError extends Error {
/**
* Standard error constructor. Adds no new behaviour.
*
* @param args - Standard error args
*/
constructor(...args) {
super(...args);
this.type = "DishError";
if (Error.captureStackTrace) {
Error.captureStackTrace(this, DishError);
}
}
}
export default DishError;

View File

@@ -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"},

View File

@@ -16,7 +16,7 @@ export const ALPHABET_OPTIONS = [
},
{
name: "Z85 (ZeroMQ)",
value: "0-9a-zA-Z.#\\-:+=^!/*?&<>()[]{}@%$#",
value: "0-9a-zA-Z.\\-:+=^!/*?&<>()[]{}@%$#",
},
{
name: "IPv6",

70
src/core/lib/Binary.mjs Normal file
View 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;
}

View File

@@ -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
View 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: "⠀⠁⠂⠃⠄⠅⠆⠇⠈⠉⠊⠋⠌⠍⠎⠏⠐⠑⠒⠓⠔⠕⠖⠗⠘⠙⠚⠛⠜⠝⠞⠟⠠⠡⠢⠣⠤⠥⠦⠧⠨⠩⠪⠫⠬⠭⠮⠯⠰⠱⠲⠳⠴⠵⠶⠷⠸⠹⠺⠻⠼⠽⠾⠿"
};

View File

@@ -0,0 +1,655 @@
/**
* Co-ordinate conversion resources.
*
* @author j433866 [j433866@gmail.com]
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
import geohash from "ngeohash";
import geodesy from "geodesy";
import OperationError from "../errors/OperationError";
/**
* Co-ordinate formats
*/
export const FORMATS = [
"Degrees Minutes Seconds",
"Degrees Decimal Minutes",
"Decimal Degrees",
"Geohash",
"Military Grid Reference System",
"Ordnance Survey National Grid",
"Universal Transverse Mercator"
];
/**
* Formats that should be passed to the conversion module as-is
*/
const NO_CHANGE = [
"Geohash",
"Military Grid Reference System",
"Ordnance Survey National Grid",
"Universal Transverse Mercator",
];
/**
* Convert a given latitude and longitude into a different format.
*
* @param {string} input - Input string to be converted
* @param {string} inFormat - Format of the input coordinates
* @param {string} inDelim - The delimiter splitting the lat/long of the input
* @param {string} outFormat - Format to convert to
* @param {string} outDelim - The delimiter to separate the output with
* @param {string} includeDir - Whether or not to include the compass direction in the output
* @param {number} precision - Precision of the result
* @returns {string} A formatted string of the converted co-ordinates
*/
export function convertCoordinates (input, inFormat, inDelim, outFormat, outDelim, includeDir, precision) {
let isPair = false,
split,
latlon,
convLat,
convLon,
conv,
hash,
utm,
mgrs,
osng,
splitLat,
splitLong,
lat,
lon;
// Can't have a precision less than 0!
if (precision < 0) {
precision = 0;
}
if (inDelim === "Auto") {
// Try to detect a delimiter in the input.
inDelim = findDelim(input);
if (inDelim === null) {
throw new OperationError("Unable to detect the input delimiter automatically.");
}
} else if (!inDelim.includes("Direction")) {
// Convert the delimiter argument value to the actual character
inDelim = realDelim(inDelim);
}
if (inFormat === "Auto") {
// Try to detect the format of the input data
inFormat = findFormat(input, inDelim);
if (inFormat === null) {
throw new OperationError("Unable to detect the input format automatically.");
}
}
// Convert the output delimiter argument to the real character
outDelim = realDelim(outDelim);
if (!NO_CHANGE.includes(inFormat)) {
if (inDelim.includes("Direction")) {
// Split on directions
split = input.split(/[NnEeSsWw]/g);
if (split[0] === "") {
// Remove first element if direction preceding
split = split.slice(1);
}
} else {
split = input.split(inDelim);
}
// Replace any co-ordinate symbols with spaces so we can split on them later
for (let i = 0; i < split.length; i++) {
split[i] = split[i].replace(/[°˝´'"]/g, " ");
}
if (split.length > 1) {
isPair = true;
}
} else {
// Remove any delimiters from the input
input = input.replace(inDelim, "");
isPair = true;
}
// Conversions from the input format into a geodesy latlon object
switch (inFormat) {
case "Geohash":
hash = geohash.decode(input.replace(/[^A-Za-z0-9]/g, ""));
latlon = new geodesy.LatLonEllipsoidal(hash.latitude, hash.longitude);
break;
case "Military Grid Reference System":
utm = geodesy.Mgrs.parse(input.replace(/[^A-Za-z0-9]/g, "")).toUtm();
latlon = utm.toLatLonE();
break;
case "Ordnance Survey National Grid":
osng = geodesy.OsGridRef.parse(input.replace(/[^A-Za-z0-9]/g, ""));
latlon = geodesy.OsGridRef.osGridToLatLon(osng);
break;
case "Universal Transverse Mercator":
// Geodesy needs a space between the first 2 digits and the next letter
if (/^[\d]{2}[A-Za-z]/.test(input)) {
input = input.slice(0, 2) + " " + input.slice(2);
}
utm = geodesy.Utm.parse(input);
latlon = utm.toLatLonE();
break;
case "Degrees Minutes Seconds":
if (isPair) {
// Split up the lat/long into degrees / minutes / seconds values
splitLat = splitInput(split[0]);
splitLong = splitInput(split[1]);
if (splitLat.length >= 3 && splitLong.length >= 3) {
lat = convDMSToDD(splitLat[0], splitLat[1], splitLat[2], 10);
lon = convDMSToDD(splitLong[0], splitLong[1], splitLong[2], 10);
latlon = new geodesy.LatLonEllipsoidal(lat.degrees, lon.degrees);
} else {
throw new OperationError("Invalid co-ordinate format for Degrees Minutes Seconds");
}
} else {
// Not a pair, so only try to convert one set of co-ordinates
splitLat = splitInput(split[0]);
if (splitLat.length >= 3) {
lat = convDMSToDD(splitLat[0], splitLat[1], splitLat[2]);
latlon = new geodesy.LatLonEllipsoidal(lat.degrees, lat.degrees);
} else {
throw new OperationError("Invalid co-ordinate format for Degrees Minutes Seconds");
}
}
break;
case "Degrees Decimal Minutes":
if (isPair) {
splitLat = splitInput(split[0]);
splitLong = splitInput(split[1]);
if (splitLat.length !== 2 || splitLong.length !== 2) {
throw new OperationError("Invalid co-ordinate format for Degrees Decimal Minutes.");
}
// Convert to decimal degrees, and then convert to a geodesy object
lat = convDDMToDD(splitLat[0], splitLat[1], 10);
lon = convDDMToDD(splitLong[0], splitLong[1], 10);
latlon = new geodesy.LatLonEllipsoidal(lat.degrees, lon.degrees);
} else {
// Not a pair, so only try to convert one set of co-ordinates
splitLat = splitInput(input);
if (splitLat.length !== 2) {
throw new OperationError("Invalid co-ordinate format for Degrees Decimal Minutes.");
}
lat = convDDMToDD(splitLat[0], splitLat[1], 10);
latlon = new geodesy.LatLonEllipsoidal(lat.degrees, lat.degrees);
}
break;
case "Decimal Degrees":
if (isPair) {
splitLat = splitInput(split[0]);
splitLong = splitInput(split[1]);
if (splitLat.length !== 1 || splitLong.length !== 1) {
throw new OperationError("Invalid co-ordinate format for Decimal Degrees.");
}
latlon = new geodesy.LatLonEllipsoidal(splitLat[0], splitLong[0]);
} else {
// Not a pair, so only try to convert one set of co-ordinates
splitLat = splitInput(split[0]);
if (splitLat.length !== 1) {
throw new OperationError("Invalid co-ordinate format for Decimal Degrees.");
}
latlon = new geodesy.LatLonEllipsoidal(splitLat[0], splitLat[0]);
}
break;
default:
throw new OperationError(`Unknown input format '${inFormat}'`);
}
// Everything is now a geodesy latlon object
// These store the latitude and longitude as decimal
if (inFormat.includes("Degrees")) {
// If the input string contains directions, we need to check if they're S or W.
// If either of the directions are, we should make the decimal value negative
const dirs = input.toUpperCase().match(/[NESW]/g);
if (dirs && dirs.length >= 1) {
// Make positive lat/lon values with S/W directions into negative values
if (dirs[0] === "S" || dirs[0] === "W" && latlon.lat > 0) {
latlon.lat = -latlon.lat;
}
if (dirs.length >= 2) {
if (dirs[1] === "S" || dirs[1] === "W" && latlon.lon > 0) {
latlon.lon = -latlon.lon;
}
}
}
}
// Try to find the compass directions of the lat and long
const [latDir, longDir] = findDirs(latlon.lat + "," + latlon.lon, ",");
// Output conversions for each output format
switch (outFormat) {
case "Decimal Degrees":
// We could use the built in latlon.toString(),
// but this makes adjusting the output harder
lat = convDDToDD(latlon.lat, precision);
lon = convDDToDD(latlon.lon, precision);
convLat = lat.string;
convLon = lon.string;
break;
case "Degrees Decimal Minutes":
lat = convDDToDDM(latlon.lat, precision);
lon = convDDToDDM(latlon.lon, precision);
convLat = lat.string;
convLon = lon.string;
break;
case "Degrees Minutes Seconds":
lat = convDDToDMS(latlon.lat, precision);
lon = convDDToDMS(latlon.lon, precision);
convLat = lat.string;
convLon = lon.string;
break;
case "Geohash":
convLat = geohash.encode(latlon.lat, latlon.lon, precision);
break;
case "Military Grid Reference System":
utm = latlon.toUtm();
mgrs = utm.toMgrs();
// MGRS wants a precision that's an even number between 2 and 10
if (precision % 2 !== 0) {
precision = precision + 1;
}
if (precision > 10) {
precision = 10;
}
convLat = mgrs.toString(precision);
break;
case "Ordnance Survey National Grid":
osng = geodesy.OsGridRef.latLonToOsGrid(latlon);
if (osng.toString() === "") {
throw new OperationError("Could not convert co-ordinates to OS National Grid. Are the co-ordinates in range?");
}
// OSNG wants a precision that's an even number between 2 and 10
if (precision % 2 !== 0) {
precision = precision + 1;
}
if (precision > 10) {
precision = 10;
}
convLat = osng.toString(precision);
break;
case "Universal Transverse Mercator":
utm = latlon.toUtm();
convLat = utm.toString(precision);
break;
}
if (convLat === undefined) {
throw new OperationError("Error converting co-ordinates.");
}
if (outFormat.includes("Degrees")) {
// Format DD/DDM/DMS for output
// If we're outputting a compass direction, remove the negative sign
if (latDir === "S" && includeDir !== "None") {
convLat = convLat.replace("-", "");
}
if (longDir === "W" && includeDir !== "None") {
convLon = convLon.replace("-", "");
}
let outConv = "";
if (includeDir === "Before") {
outConv += latDir + " ";
}
outConv += convLat;
if (includeDir === "After") {
outConv += " " + latDir;
}
outConv += outDelim;
if (isPair) {
if (includeDir === "Before") {
outConv += longDir + " ";
}
outConv += convLon;
if (includeDir === "After") {
outConv += " " + longDir;
}
outConv += outDelim;
}
conv = outConv;
} else {
conv = convLat + outDelim;
}
return conv;
}
/**
* Split up the input using a space or degrees signs, and sanitise the result
*
* @param {string} input - The input data to be split
* @returns {number[]} An array of the different items in the string, stored as floats
*/
function splitInput (input){
const split = [];
input.split(/\s+/).forEach(item => {
// Remove any character that isn't a digit, decimal point or negative sign
item = item.replace(/[^0-9.-]/g, "");
if (item.length > 0){
// Turn the item into a float
split.push(parseFloat(item));
}
});
return split;
}
/**
* Convert Degrees Minutes Seconds to Decimal Degrees
*
* @param {number} degrees - The degrees of the input co-ordinates
* @param {number} minutes - The minutes of the input co-ordinates
* @param {number} seconds - The seconds of the input co-ordinates
* @param {number} precision - The precision the result should be rounded to
* @returns {{string: string, degrees: number}} An object containing the raw converted value (obj.degrees), and a formatted string version (obj.string)
*/
function convDMSToDD (degrees, minutes, seconds, precision){
const absDegrees = Math.abs(degrees);
let conv = absDegrees + (minutes / 60) + (seconds / 3600);
let outString = round(conv, precision) + "°";
if (isNegativeZero(degrees) || degrees < 0) {
conv = -conv;
outString = "-" + outString;
}
return {
"degrees": conv,
"string": outString
};
}
/**
* Convert Decimal Degrees Minutes to Decimal Degrees
*
* @param {number} degrees - The input degrees to be converted
* @param {number} minutes - The input minutes to be converted
* @param {number} precision - The precision which the result should be rounded to
* @returns {{string: string, degrees: number}} An object containing the raw converted value (obj.degrees), and a formatted string version (obj.string)
*/
function convDDMToDD (degrees, minutes, precision) {
const absDegrees = Math.abs(degrees);
let conv = absDegrees + minutes / 60;
let outString = round(conv, precision) + "°";
if (isNegativeZero(degrees) || degrees < 0) {
conv = -conv;
outString = "-" + outString;
}
return {
"degrees": conv,
"string": outString
};
}
/**
* Convert Decimal Degrees to Decimal Degrees
*
* Doesn't affect the input, just puts it into an object
* @param {number} degrees - The input degrees to be converted
* @param {number} precision - The precision which the result should be rounded to
* @returns {{string: string, degrees: number}} An object containing the raw converted value (obj.degrees), and a formatted string version (obj.string)
*/
function convDDToDD (degrees, precision) {
return {
"degrees": degrees,
"string": round(degrees, precision) + "°"
};
}
/**
* Convert Decimal Degrees to Degrees Minutes Seconds
*
* @param {number} decDegrees - The input data to be converted
* @param {number} precision - The precision which the result should be rounded to
* @returns {{string: string, degrees: number, minutes: number, seconds: number}} An object containing the raw converted value as separate numbers (.degrees, .minutes, .seconds), and a formatted string version (obj.string)
*/
function convDDToDMS (decDegrees, precision) {
const absDegrees = Math.abs(decDegrees);
let degrees = Math.floor(absDegrees);
const minutes = Math.floor(60 * (absDegrees - degrees)),
seconds = round(3600 * (absDegrees - degrees) - 60 * minutes, precision);
let outString = degrees + "° " + minutes + "' " + seconds + "\"";
if (isNegativeZero(decDegrees) || decDegrees < 0) {
degrees = -degrees;
outString = "-" + outString;
}
return {
"degrees": degrees,
"minutes": minutes,
"seconds": seconds,
"string": outString
};
}
/**
* Convert Decimal Degrees to Degrees Decimal Minutes
*
* @param {number} decDegrees - The input degrees to be converted
* @param {number} precision - The precision the input data should be rounded to
* @returns {{string: string, degrees: number, minutes: number}} An object containing the raw converted value as separate numbers (.degrees, .minutes), and a formatted string version (obj.string)
*/
function convDDToDDM (decDegrees, precision) {
const absDegrees = Math.abs(decDegrees);
let degrees = Math.floor(absDegrees);
const minutes = absDegrees - degrees,
decMinutes = round(minutes * 60, precision);
let outString = degrees + "° " + decMinutes + "'";
if (decDegrees < 0 || isNegativeZero(decDegrees)) {
degrees = -degrees;
outString = "-" + outString;
}
return {
"degrees": degrees,
"minutes": decMinutes,
"string": outString,
};
}
/**
* Finds and returns the compass directions in an input string
*
* @param {string} input - The input co-ordinates containing the direction
* @param {string} delim - The delimiter separating latitide and longitude
* @returns {string[]} String array containing the latitude and longitude directions
*/
export function findDirs(input, delim) {
const upperInput = input.toUpperCase();
const dirExp = new RegExp(/[NESW]/g);
const dirs = upperInput.match(dirExp);
if (dirs) {
// If there's actually compass directions
// in the input, use these to work out the direction
if (dirs.length <= 2 && dirs.length >= 1) {
return dirs.length === 2 ? [dirs[0], dirs[1]] : [dirs[0], ""];
}
}
// Nothing was returned, so guess the directions
let lat = upperInput,
long,
latDir = "",
longDir = "";
if (!delim.includes("Direction")) {
if (upperInput.includes(delim)) {
const split = upperInput.split(delim);
if (split.length >= 1) {
if (split[0] !== "") {
lat = split[0];
}
if (split.length >= 2 && split[1] !== "") {
long = split[1];
}
}
}
} else {
const split = upperInput.split(dirExp);
if (split.length > 1) {
lat = split[0] === "" ? split[1] : split[0];
if (split.length > 2 && split[2] !== "") {
long = split[2];
}
}
}
if (lat) {
lat = parseFloat(lat);
latDir = lat < 0 ? "S" : "N";
}
if (long) {
long = parseFloat(long);
longDir = long < 0 ? "W" : "E";
}
return [latDir, longDir];
}
/**
* Detects the co-ordinate format of the input data
*
* @param {string} input - The input data whose format we need to detect
* @param {string} delim - The delimiter separating the data in input
* @returns {string} The input format
*/
export function findFormat (input, delim) {
let testData;
const mgrsPattern = new RegExp(/^[0-9]{2}\s?[C-HJ-NP-X]{1}\s?[A-HJ-NP-Z][A-HJ-NP-V]\s?[0-9\s]+/),
osngPattern = new RegExp(/^[A-HJ-Z]{2}\s+[0-9\s]+$/),
geohashPattern = new RegExp(/^[0123456789BCDEFGHJKMNPQRSTUVWXYZ]+$/),
utmPattern = new RegExp(/^[0-9]{2}\s?[C-HJ-NP-X]\s[0-9.]+\s?[0-9.]+$/),
degPattern = new RegExp(/[°'"]/g);
input = input.trim();
if (delim !== null && delim.includes("Direction")) {
const split = input.split(/[NnEeSsWw]/);
if (split.length > 1) {
testData = split[0] === "" ? split[1] : split[0];
}
} else if (delim !== null && delim !== "") {
if (input.includes(delim)) {
const split = input.split(delim);
if (split.length > 1) {
testData = split[0] === "" ? split[1] : split[0];
}
} else {
testData = input;
}
}
// Test non-degrees formats
if (!degPattern.test(input)) {
const filteredInput = input.toUpperCase().replace(delim, "");
if (utmPattern.test(filteredInput)) {
return "Universal Transverse Mercator";
}
if (mgrsPattern.test(filteredInput)) {
return "Military Grid Reference System";
}
if (osngPattern.test(filteredInput)) {
return "Ordnance Survey National Grid";
}
if (geohashPattern.test(filteredInput)) {
return "Geohash";
}
}
// Test DMS/DDM/DD formats
if (testData !== undefined) {
const split = splitInput(testData);
switch (split.length){
case 3:
return "Degrees Minutes Seconds";
case 2:
return "Degrees Decimal Minutes";
case 1:
return "Decimal Degrees";
}
}
return null;
}
/**
* Automatically find the delimeter type from the given input
*
* @param {string} input
* @returns {string} Delimiter type
*/
export function findDelim (input) {
input = input.trim();
const delims = [",", ";", ":"];
const testDir = input.match(/[NnEeSsWw]/g);
if (testDir !== null && testDir.length > 0 && testDir.length < 3) {
// Possibly contains a direction
const splitInput = input.split(/[NnEeSsWw]/);
if (splitInput.length <= 3 && splitInput.length > 0) {
// If there's 3 splits (one should be empty), then assume we have directions
if (splitInput[0] === "") {
return "Direction Preceding";
} else if (splitInput[splitInput.length - 1] === "") {
return "Direction Following";
}
}
}
// Loop through the standard delimiters, and try to find them in the input
for (let i = 0; i < delims.length; i++) {
const delim = delims[i];
if (input.includes(delim)) {
const splitInput = input.split(delim);
if (splitInput.length <= 3 && splitInput.length > 0) {
// Don't want to try and convert more than 2 co-ordinates
return delim;
}
}
}
return null;
}
/**
* Gets the real string for a delimiter name.
*
* @param {string} delim The delimiter to be matched
* @returns {string}
*/
export function realDelim (delim) {
return {
"Auto": "Auto",
"Space": " ",
"\\n": "\n",
"Comma": ",",
"Semi-colon": ";",
"Colon": ":"
}[delim];
}
/**
* Returns true if a zero is negative
*
* @param {number} zero
* @returns {boolean}
*/
function isNegativeZero(zero) {
return zero === 0 && (1/zero < 0);
}
/**
* Rounds a number to a specified number of decimal places
*
* @param {number} input - The number to be rounded
* @param {precision} precision - The number of decimal places the number should be rounded to
* @returns {number}
*/
function round(input, precision) {
precision = Math.pow(10, precision);
return Math.round(input * precision) / precision;
}

View File

@@ -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;

View File

@@ -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.";
/**

230
src/core/lib/LoremIpsum.mjs Normal file
View File

@@ -0,0 +1,230 @@
/**
* Lorem Ipsum generator.
*
* @author Klaxon [klaxon@veyr.com]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
/**
* Generate lorem ipsum paragraphs.
*
* @param {number} length
* @returns {string}
*/
export function GenerateParagraphs(length=3) {
const paragraphs = [];
while (paragraphs.length < length) {
const paragraphLength = getRandomLength(PARAGRAPH_LENGTH_MEAN, PARAGRAPH_LENGTH_STD_DEV);
const sentences = [];
while (sentences.length < paragraphLength) {
const sentenceLength = getRandomLength(SENTENCE_LENGTH_MEAN, SENTENCE_LENGTH_STD_DEV);
const sentence = getWords(sentenceLength);
sentences.push(formatSentence(sentence));
}
paragraphs.push(formatParagraph(sentences));
}
paragraphs[paragraphs.length-1] = paragraphs[paragraphs.length-1].slice(0, -2);
paragraphs[0] = replaceStart(paragraphs[0]);
return paragraphs.join("");
}
/**
* Generate lorem ipsum sentences.
*
* @param {number} length
* @returns {string}
*/
export function GenerateSentences(length=3) {
const sentences = [];
while (sentences.length < length) {
const sentenceLength = getRandomLength(SENTENCE_LENGTH_MEAN, SENTENCE_LENGTH_STD_DEV);
const sentence = getWords(sentenceLength);
sentences.push(formatSentence(sentence));
}
const paragraphs = sentencesToParagraphs(sentences);
return paragraphs.join("");
}
/**
* Generate lorem ipsum words.
*
* @param {number} length
* @returns {string}
*/
export function GenerateWords(length=3) {
const words = getWords(length);
const sentences = wordsToSentences(words);
const paragraphs = sentencesToParagraphs(sentences);
return paragraphs.join("");
}
/**
* Generate lorem ipsum bytes.
*
* @param {number} length
* @returns {string}
*/
export function GenerateBytes(length=3) {
const str = GenerateWords(length/3);
return str.slice(0, length);
}
/**
* Get array of randomly selected words from the lorem ipsum wordList.
*
* @param {number} length
* @returns {string[]}
* @private
*/
function getWords(length=3) {
const words = [];
let word;
let previousWord;
while (words.length < length){
do {
word = wordList[Math.floor(Math.random() * wordList.length)];
} while (previousWord === word);
words.push(word);
previousWord = word;
}
return words;
}
/**
* Convert an array of words into an array of sentences
*
* @param {string[]} words
* @returns {string[]}
* @private
*/
function wordsToSentences(words) {
const sentences = [];
while (words.length > 0) {
const sentenceLength = getRandomLength(SENTENCE_LENGTH_MEAN, SENTENCE_LENGTH_STD_DEV);
if (sentenceLength <= words.length) {
sentences.push(formatSentence(words.splice(0, sentenceLength)));
} else {
sentences.push(formatSentence(words.splice(0, words.length)));
}
}
return sentences;
}
/**
* Convert an array of sentences into an array of paragraphs
*
* @param {string[]} sentences
* @returns {string[]}
* @private
*/
function sentencesToParagraphs(sentences) {
const paragraphs = [];
while (sentences.length > 0) {
const paragraphLength = getRandomLength(PARAGRAPH_LENGTH_MEAN, PARAGRAPH_LENGTH_STD_DEV);
paragraphs.push(formatParagraph(sentences.splice(0, paragraphLength)));
}
paragraphs[paragraphs.length-1] = paragraphs[paragraphs.length-1].slice(0, -1);
paragraphs[0] = replaceStart(paragraphs[0]);
return paragraphs;
}
/**
* Format an array of words into a sentence.
*
* @param {string[]} words
* @returns {string}
* @private
*/
function formatSentence(words) {
// 0.35 chance of a comma being added randomly to the sentence.
if (Math.random() < PROBABILITY_OF_A_COMMA) {
const pos = Math.round(Math.random()*(words.length-1));
words[pos] +=",";
}
let sentence = words.join(" ");
sentence = sentence.charAt(0).toUpperCase() + sentence.slice(1);
sentence += ".";
return sentence;
}
/**
* Format an array of sentences into a paragraph.
*
* @param {string[]} sentences
* @returns {string}
* @private
*/
function formatParagraph(sentences) {
let paragraph = sentences.join(" ");
paragraph += "\n\n";
return paragraph;
}
/**
* Get a random number based on a mean and standard deviation.
*
* @param {number} mean
* @param {number} stdDev
* @returns {number}
* @private
*/
function getRandomLength(mean, stdDev) {
let length;
do {
length = Math.round((Math.random()*2-1)+(Math.random()*2-1)+(Math.random()*2-1)*stdDev+mean);
} while (length <= 0);
return length;
}
/**
* Replace first 5 words with "Lorem ipsum dolor sit amet"
*
* @param {string[]} str
* @returns {string[]}
* @private
*/
function replaceStart(str) {
let words = str.split(" ");
if (words.length > 5) {
words.splice(0, 5, "Lorem", "ipsum", "dolor", "sit", "amet");
return words.join(" ");
} else {
const lorem = ["Lorem", "ipsum", "dolor", "sit", "amet"];
words = lorem.slice(0, words.length);
str = words.join(" ");
str += ".";
return str;
}
}
const SENTENCE_LENGTH_MEAN = 15;
const SENTENCE_LENGTH_STD_DEV = 9;
const PARAGRAPH_LENGTH_MEAN = 5;
const PARAGRAPH_LENGTH_STD_DEV = 2;
const PROBABILITY_OF_A_COMMA = 0.35;
const wordList = [
"ad", "adipisicing", "aliqua", "aliquip", "amet", "anim",
"aute", "cillum", "commodo", "consectetur", "consequat", "culpa",
"cupidatat", "deserunt", "do", "dolor", "dolore", "duis",
"ea", "eiusmod", "elit", "enim", "esse", "est",
"et", "eu", "ex", "excepteur", "exercitation", "fugiat",
"id", "in", "incididunt", "ipsum", "irure", "labore",
"laboris", "laborum", "Lorem", "magna", "minim", "mollit",
"nisi", "non", "nostrud", "nulla", "occaecat", "officia",
"pariatur", "proident", "qui", "quis", "reprehenderit", "sint",
"sit", "sunt", "tempor", "ullamco", "ut", "velit",
"veniam", "voluptate",
];

View File

@@ -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);
}));

View 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;
}
}

View 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;

View 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;

View File

@@ -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
}
];
}

View File

@@ -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
}
];
}

View File

@@ -19,7 +19,7 @@ class Adler32Checksum extends Operation {
super();
this.name = "Adler-32 Checksum";
this.module = "Hashing";
this.module = "Crypto";
this.description = "Adler-32 is a checksum algorithm which was invented by Mark Adler in 1995, and is a modification of the Fletcher checksum. Compared to a cyclic redundancy check of the same length, it trades reliability for speed (preferring the latter).<br><br>Adler-32 is more reliable than Fletcher-16, and slightly less reliable than Fletcher-32.";
this.infoURL = "https://wikipedia.org/wiki/Adler-32";
this.inputType = "byteArray";

View File

@@ -19,7 +19,7 @@ class AnalyseHash extends Operation {
super();
this.name = "Analyse hash";
this.module = "Hashing";
this.module = "Crypto";
this.description = "Tries to determine information about a given hash and suggests which algorithm may have been used to generate it based on its length.";
this.infoURL = "https://wikipedia.org/wiki/Comparison_of_cryptographic_hash_functions";
this.inputType = "string";

View File

@@ -5,7 +5,7 @@
*/
import Operation from "../Operation";
import bsonjs from "bson";
import bson from "bson";
import OperationError from "../errors/OperationError";
/**
@@ -36,8 +36,6 @@ class BSONDeserialise extends Operation {
run(input, args) {
if (!input.byteLength) return "";
const bson = new bsonjs();
try {
const data = bson.deserialize(new Buffer(input));
return JSON.stringify(data, null, 2);

View File

@@ -5,7 +5,7 @@
*/
import Operation from "../Operation";
import bsonjs from "bson";
import bson from "bson";
import OperationError from "../errors/OperationError";
/**
@@ -36,8 +36,6 @@ class BSONSerialise extends Operation {
run(input, args) {
if (!input) return new ArrayBuffer();
const bson = new bsonjs();
try {
const data = JSON.parse(input);
return bson.serialize(data).buffer;

View File

@@ -19,7 +19,7 @@ class Bcrypt extends Operation {
super();
this.name = "Bcrypt";
this.module = "Hashing";
this.module = "Crypto";
this.description = "bcrypt is a password hashing function designed by Niels Provos and David Mazi\xe8res, based on the Blowfish cipher, and presented at USENIX in 1999. Besides incorporating a salt to protect against rainbow table attacks, bcrypt is an adaptive function: over time, the iteration count (rounds) can be increased to make it slower, so it remains resistant to brute-force search attacks even with increasing computation power.<br><br>Enter the password in the input to generate its hash.";
this.infoURL = "https://wikipedia.org/wiki/Bcrypt";
this.inputType = "string";

View File

@@ -19,7 +19,7 @@ class BcryptCompare extends Operation {
super();
this.name = "Bcrypt compare";
this.module = "Hashing";
this.module = "Crypto";
this.description = "Tests whether the input matches the given bcrypt hash. To test multiple possible passwords, use the 'Fork' operation.";
this.infoURL = "https://wikipedia.org/wiki/Bcrypt";
this.inputType = "string";

View File

@@ -20,7 +20,7 @@ class BcryptParse extends Operation {
super();
this.name = "Bcrypt parse";
this.module = "Hashing";
this.module = "Crypto";
this.description = "Parses a bcrypt hash to determine the number of rounds used, the salt, and the password hash.";
this.infoURL = "https://wikipedia.org/wiki/Bcrypt";
this.inputType = "string";

View File

@@ -5,7 +5,7 @@
*/
import Operation from "../Operation";
import bzip2 from "../vendor/bzip2.js";
import bzip2 from "../vendor/bzip2";
import OperationError from "../errors/OperationError";
/**

View File

@@ -19,7 +19,7 @@ class CRC16Checksum extends Operation {
super();
this.name = "CRC-16 Checksum";
this.module = "Hashing";
this.module = "Crypto";
this.description = "A cyclic redundancy check (CRC) is an error-detecting code commonly used in digital networks and storage devices to detect accidental changes to raw data.<br><br>The CRC was invented by W. Wesley Peterson in 1961.";
this.infoURL = "https://wikipedia.org/wiki/Cyclic_redundancy_check";
this.inputType = "ArrayBuffer";

View File

@@ -19,7 +19,7 @@ class CRC32Checksum extends Operation {
super();
this.name = "CRC-32 Checksum";
this.module = "Hashing";
this.module = "Crypto";
this.description = "A cyclic redundancy check (CRC) is an error-detecting code commonly used in digital networks and storage devices to detect accidental changes to raw data.<br><br>The CRC was invented by W. Wesley Peterson in 1961; the 32-bit CRC function of Ethernet and many other standards is the work of several researchers and was published in 1975.";
this.infoURL = "https://wikipedia.org/wiki/Cyclic_redundancy_check";
this.inputType = "ArrayBuffer";

View 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;

View File

@@ -19,7 +19,7 @@ class CTPH extends Operation {
super();
this.name = "CTPH";
this.module = "Hashing";
this.module = "Crypto";
this.description = "Context Triggered Piecewise Hashing, also called Fuzzy Hashing, can match inputs that have homologies. Such inputs have sequences of identical bytes in the same order, although bytes in between these sequences may be different in both content and length.<br><br>CTPH was originally based on the work of Dr. Andrew Tridgell and a spam email detector called SpamSum. This method was adapted by Jesse Kornblum and published at the DFRWS conference in 2006 in a paper 'Identifying Almost Identical Files Using Context Triggered Piecewise Hashing'.";
this.infoURL = "https://forensicswiki.org/wiki/Context_Triggered_Piecewise_Hashing";
this.inputType = "string";

View 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;

View 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;

View File

@@ -22,7 +22,7 @@ class CompareCTPHHashes extends Operation {
super();
this.name = "Compare CTPH hashes";
this.module = "Hashing";
this.module = "Crypto";
this.description = "Compares two Context Triggered Piecewise Hashing (CTPH) fuzzy hashes to determine the similarity between them on a scale of 0 to 100.";
this.infoURL = "https://forensicswiki.org/wiki/Context_Triggered_Piecewise_Hashing";
this.inputType = "string";

View File

@@ -22,7 +22,7 @@ class CompareSSDEEPHashes extends Operation {
super();
this.name = "Compare SSDEEP hashes";
this.module = "Hashing";
this.module = "Crypto";
this.description = "Compares two SSDEEP fuzzy hashes to determine the similarity between them on a scale of 0 to 100.";
this.infoURL = "https://forensicswiki.org/wiki/Ssdeep";
this.inputType = "string";

View File

@@ -0,0 +1,95 @@
/**
* @author j433866 [j433866@gmail.com]
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
import Operation from "../Operation";
import {FORMATS, convertCoordinates} from "../lib/ConvertCoordinates";
/**
* Convert co-ordinate format operation
*/
class ConvertCoordinateFormat extends Operation {
/**
* ConvertCoordinateFormat constructor
*/
constructor() {
super();
this.name = "Convert co-ordinate format";
this.module = "Hashing";
this.description = "Converts geographical coordinates between different formats.<br><br>Supported formats:<ul><li>Degrees Minutes Seconds (DMS)</li><li>Degrees Decimal Minutes (DDM)</li><li>Decimal Degrees (DD)</li><li>Geohash</li><li>Military Grid Reference System (MGRS)</li><li>Ordnance Survey National Grid (OSNG)</li><li>Universal Transverse Mercator (UTM)</li></ul><br>The operation can try to detect the input co-ordinate format and delimiter automatically, but this may not always work correctly.";
this.infoURL = "https://wikipedia.org/wiki/Geographic_coordinate_conversion";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
"name": "Input Format",
"type": "option",
"value": ["Auto"].concat(FORMATS)
},
{
"name": "Input Delimiter",
"type": "option",
"value": [
"Auto",
"Direction Preceding",
"Direction Following",
"\\n",
"Comma",
"Semi-colon",
"Colon"
]
},
{
"name": "Output Format",
"type": "option",
"value": FORMATS
},
{
"name": "Output Delimiter",
"type": "option",
"value": [
"Space",
"\\n",
"Comma",
"Semi-colon",
"Colon"
]
},
{
"name": "Include Compass Directions",
"type": "option",
"value": [
"None",
"Before",
"After"
]
},
{
"name": "Precision",
"type": "number",
"value": 3
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
if (input.replace(/[\s+]/g, "") !== "") {
const [inFormat, inDelim, outFormat, outDelim, incDirection, precision] = args;
const result = convertCoordinates(input, inFormat, inDelim, outFormat, outDelim, incDirection, precision);
return result;
} else {
return input;
}
}
}
export default ConvertCoordinateFormat;

View File

@@ -0,0 +1,125 @@
/**
* @author h345983745
* @copyright Crown Copyright 2019
* @license Apache-2.0
*/
import Operation from "../Operation";
import OperationError from "../errors/OperationError";
/**
* DNS over HTTPS operation
*/
class DNSOverHTTPS extends Operation {
/**
* DNSOverHTTPS constructor
*/
constructor() {
super();
this.name = "DNS over HTTPS";
this.module = "Default";
this.description = [
"Takes a single domain name and performs a DNS lookup using DNS over HTTPS.",
"<br><br>",
"By default, <a href='https://developers.cloudflare.com/1.1.1.1/dns-over-https/'>Cloudflare</a> and <a href='https://developers.google.com/speed/public-dns/docs/dns-over-https'>Google</a> DNS over HTTPS services are supported.",
"<br><br>",
"Can be used with any service that supports the GET parameters <code>name</code> and <code>type</code>."
].join("\n");
this.infoURL = "https://wikipedia.org/wiki/DNS_over_HTTPS";
this.inputType = "string";
this.outputType = "JSON";
this.manualBake = true;
this.args = [
{
name: "Resolver",
type: "editableOption",
value: [
{
name: "Google",
value: "https://dns.google.com/resolve"
},
{
name: "Cloudflare",
value: "https://cloudflare-dns.com/dns-query"
}
]
},
{
name: "Request Type",
type: "option",
value: [
"A",
"AAAA",
"TXT",
"MX",
"DNSKEY",
"NS"
]
},
{
name: "Answer Data Only",
type: "boolean",
value: false
},
{
name: "Validate DNSSEC",
type: "boolean",
value: true
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {JSON}
*/
run(input, args) {
const [resolver, requestType, justAnswer, DNSSEC] = args;
let url = URL;
try {
url = new URL(resolver);
} catch (error) {
throw new OperationError(error.toString() +
"\n\nThis error could be caused by one of the following:\n" +
" - An invalid Resolver URL\n");
}
const params = {name: input, type: requestType, cd: DNSSEC};
url.search = new URLSearchParams(params);
return fetch(url, {headers: {"accept": "application/dns-json"}}).then(response => {
return response.json();
}).then(data => {
if (justAnswer) {
return extractData(data.Answer);
}
return data;
}).catch(e => {
throw new OperationError(`Error making request to ${url}\n${e.toString()}`);
});
}
}
/**
* Construct an array of just data from a DNS Answer section
*
* @private
* @param {JSON} data
* @returns {JSON}
*/
function extractData(data) {
if (typeof(data) == "undefined"){
return [];
} else {
const dataValues = [];
data.forEach(element => {
dataValues.push(element.data);
});
return dataValues;
}
}
export default DNSOverHTTPS;

View File

@@ -20,7 +20,7 @@ class DecodeText extends Operation {
super();
this.name = "Decode text";
this.module = "CharEnc";
this.module = "Encodings";
this.description = [
"Decodes text from the chosen character encoding.",
"<br><br>",

View 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;

View File

@@ -43,7 +43,7 @@ class Divide extends Operation {
*/
run(input, args) {
const val = div(createNumArray(input, args[0]));
return val instanceof BigNumber ? val : new BigNumber(NaN);
return BigNumber.isBigNumber(val) ? val : new BigNumber(NaN);
}
}

View File

@@ -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;
}

View File

@@ -20,7 +20,7 @@ class EncodeText extends Operation {
super();
this.name = "Encode text";
this.module = "CharEnc";
this.module = "Encodings";
this.description = [
"Encodes text into the chosen character encoding.",
"<br><br>",

View File

@@ -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);
}
}

View File

@@ -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);
}

View File

@@ -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);
}
}

View File

@@ -19,7 +19,7 @@ class Fletcher16Checksum extends Operation {
super();
this.name = "Fletcher-16 Checksum";
this.module = "Hashing";
this.module = "Crypto";
this.description = "The Fletcher checksum is an algorithm for computing a position-dependent checksum devised by John Gould Fletcher at Lawrence Livermore Labs in the late 1970s.<br><br>The objective of the Fletcher checksum was to provide error-detection properties approaching those of a cyclic redundancy check but with the lower computational effort associated with summation techniques.";
this.infoURL = "https://wikipedia.org/wiki/Fletcher%27s_checksum#Fletcher-16";
this.inputType = "byteArray";

View File

@@ -19,7 +19,7 @@ class Fletcher32Checksum extends Operation {
super();
this.name = "Fletcher-32 Checksum";
this.module = "Hashing";
this.module = "Crypto";
this.description = "The Fletcher checksum is an algorithm for computing a position-dependent checksum devised by John Gould Fletcher at Lawrence Livermore Labs in the late 1970s.<br><br>The objective of the Fletcher checksum was to provide error-detection properties approaching those of a cyclic redundancy check but with the lower computational effort associated with summation techniques.";
this.infoURL = "https://wikipedia.org/wiki/Fletcher%27s_checksum#Fletcher-32";
this.inputType = "byteArray";

View File

@@ -19,7 +19,7 @@ class Fletcher64Checksum extends Operation {
super();
this.name = "Fletcher-64 Checksum";
this.module = "Hashing";
this.module = "Crypto";
this.description = "The Fletcher checksum is an algorithm for computing a position-dependent checksum devised by John Gould Fletcher at Lawrence Livermore Labs in the late 1970s.<br><br>The objective of the Fletcher checksum was to provide error-detection properties approaching those of a cyclic redundancy check but with the lower computational effort associated with summation techniques.";
this.infoURL = "https://wikipedia.org/wiki/Fletcher%27s_checksum#Fletcher-64";
this.inputType = "byteArray";

View File

@@ -19,7 +19,7 @@ class Fletcher8Checksum extends Operation {
super();
this.name = "Fletcher-8 Checksum";
this.module = "Hashing";
this.module = "Crypto";
this.description = "The Fletcher checksum is an algorithm for computing a position-dependent checksum devised by John Gould Fletcher at Lawrence Livermore Labs in the late 1970s.<br><br>The objective of the Fletcher checksum was to provide error-detection properties approaching those of a cyclic redundancy check but with the lower computational effort associated with summation techniques.";
this.infoURL = "https://wikipedia.org/wiki/Fletcher%27s_checksum";
this.inputType = "byteArray";

View File

@@ -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();
}

View 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;

View File

@@ -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]
},
];
}

View File

@@ -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]);
}
/**

View 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;

View File

@@ -0,0 +1,39 @@
/**
* @author masq [github.cyberchef@masq.cc]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
import Operation from "../Operation";
/**
* From Case Insensitive Regex operation
*/
class FromCaseInsensitiveRegex extends Operation {
/**
* FromCaseInsensitiveRegex constructor
*/
constructor() {
super();
this.name = "From Case Insensitive Regex";
this.module = "Default";
this.description = "Converts a case-insensitive regex string to a case sensitive regex string (no guarantee on it being the proper original casing) in case the i flag wasn't available at the time but now is, or you need it to be case-sensitive again.<br><br>e.g. <code>[mM][oO][zZ][iI][lL][lL][aA]/[0-9].[0-9] .*</code> becomes <code>Mozilla/[0-9].[0-9] .*</code>";
this.infoURL = "https://wikipedia.org/wiki/Regular_expression";
this.inputType = "string";
this.outputType = "string";
this.args = [];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
return input.replace(/\[[a-z]{2}\]/ig, m => m[1].toUpperCase() === m[2].toUpperCase() ? m[1] : m);
}
}
export default FromCaseInsensitiveRegex;

View File

@@ -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;
}
}

View File

@@ -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: []
},

View File

@@ -41,7 +41,7 @@ class GenerateAllHashes extends Operation {
super();
this.name = "Generate all hashes";
this.module = "Hashing";
this.module = "Crypto";
this.description = "Generates all available hashes and checksums for the input.";
this.infoURL = "https://wikipedia.org/wiki/Comparison_of_cryptographic_hash_functions";
this.inputType = "ArrayBuffer";

View File

@@ -0,0 +1,70 @@
/**
* @author klaxon [klaxon@veyr.com]
* @copyright Crown Copyright 2018
* @license Apache-2.0
*/
import Operation from "../Operation";
import OperationError from "../errors/OperationError";
import { GenerateParagraphs, GenerateSentences, GenerateWords, GenerateBytes } from "../lib/LoremIpsum";
/**
* Generate Lorem Ipsum operation
*/
class GenerateLoremIpsum extends Operation {
/**
* GenerateLoremIpsum constructor
*/
constructor() {
super();
this.name = "Generate Lorem Ipsum";
this.module = "Default";
this.description = "Generate varying length lorem ipsum placeholder text.";
this.infoURL = "https://wikipedia.org/wiki/Lorem_ipsum";
this.inputType = "string";
this.outputType = "string";
this.args = [
{
"name": "Length",
"type": "number",
"value": "3"
},
{
"name": "Length in",
"type": "option",
"value": ["Paragraphs", "Sentences", "Words", "Bytes"]
}
];
}
/**
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
run(input, args) {
const [length, lengthType] = args;
if (length < 1){
throw new OperationError("Length must be greater than 0");
}
switch (lengthType) {
case "Paragraphs":
return GenerateParagraphs(length);
case "Sentences":
return GenerateSentences(length);
case "Words":
return GenerateWords(length);
case "Bytes":
return GenerateBytes(length);
default:
throw new OperationError("Invalid length type");
}
}
}
export default GenerateLoremIpsum;

View 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;

View File

@@ -22,7 +22,7 @@ class GroupIPAddresses extends Operation {
super();
this.name = "Group IP addresses";
this.module = "JSBN";
this.module = "Default";
this.description = "Groups a list of IP addresses into subnets. Supports both IPv4 and IPv6 addresses.";
this.infoURL = "https://wikipedia.org/wiki/Subnetwork";
this.inputType = "string";

View File

@@ -19,7 +19,7 @@ class HAS160 extends Operation {
super();
this.name = "HAS-160";
this.module = "Hashing";
this.module = "Crypto";
this.description = "HAS-160 is a cryptographic hash function designed for use with the Korean KCDSA digital signature algorithm. It is derived from SHA-1, with assorted changes intended to increase its security. It produces a 160-bit output.<br><br>HAS-160 is used in the same way as SHA-1. First it divides input in blocks of 512 bits each and pads the final block. A digest function updates the intermediate hash value by processing the input blocks in turn.<br><br>The message digest algorithm consists of 80 rounds.";
this.infoURL = "https://wikipedia.org/wiki/HAS-160";
this.inputType = "ArrayBuffer";

View File

@@ -20,7 +20,7 @@ class HMAC extends Operation {
super();
this.name = "HMAC";
this.module = "Hashing";
this.module = "Crypto";
this.description = "Keyed-Hash Message Authentication Codes (HMAC) are a mechanism for message authentication using cryptographic hash functions.";
this.infoURL = "https://wikipedia.org/wiki/HMAC";
this.inputType = "ArrayBuffer";
@@ -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());
}

View File

@@ -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;

View 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;

View 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;

View 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;

View 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;

View File

@@ -20,7 +20,7 @@ class Keccak extends Operation {
super();
this.name = "Keccak";
this.module = "Hashing";
this.module = "Crypto";
this.description = "The Keccak hash algorithm was designed by Guido Bertoni, Joan Daemen, Micha\xebl Peeters, and Gilles Van Assche, building upon RadioGat\xfan. It was selected as the winner of the SHA-3 design competition.<br><br>This version of the algorithm is Keccak[c=2d] and differs from the SHA-3 specification.";
this.infoURL = "https://wikipedia.org/wiki/SHA-3";
this.inputType = "ArrayBuffer";

View File

@@ -19,7 +19,7 @@ class MD2 extends Operation {
super();
this.name = "MD2";
this.module = "Hashing";
this.module = "Crypto";
this.description = "The MD2 (Message-Digest 2) algorithm is a cryptographic hash function developed by Ronald Rivest in 1989. The algorithm is optimized for 8-bit computers.<br><br>Although MD2 is no longer considered secure, even as of 2014, it remains in use in public key infrastructures as part of certificates generated with MD2 and RSA.";
this.infoURL = "https://wikipedia.org/wiki/MD2_(cryptography)";
this.inputType = "ArrayBuffer";

View File

@@ -19,7 +19,7 @@ class MD4 extends Operation {
super();
this.name = "MD4";
this.module = "Hashing";
this.module = "Crypto";
this.description = "The MD4 (Message-Digest 4) algorithm is a cryptographic hash function developed by Ronald Rivest in 1990. The digest length is 128 bits. The algorithm has influenced later designs, such as the MD5, SHA-1 and RIPEMD algorithms.<br><br>The security of MD4 has been severely compromised.";
this.infoURL = "https://wikipedia.org/wiki/MD4";
this.inputType = "ArrayBuffer";

View File

@@ -19,7 +19,7 @@ class MD5 extends Operation {
super();
this.name = "MD5";
this.module = "Hashing";
this.module = "Crypto";
this.description = "MD5 (Message-Digest 5) is a widely used hash function. It has been used in a variety of security applications and is also commonly used to check the integrity of files.<br><br>However, MD5 is not collision resistant and it isn't suitable for applications like SSL/TLS certificates or digital signatures that rely on this property.";
this.infoURL = "https://wikipedia.org/wiki/MD5";
this.inputType = "ArrayBuffer";

View File

@@ -20,7 +20,7 @@ class MD6 extends Operation {
super();
this.name = "MD6";
this.module = "Hashing";
this.module = "Crypto";
this.description = "The MD6 (Message-Digest 6) algorithm is a cryptographic hash function. It uses a Merkle tree-like structure to allow for immense parallel computation of hashes for very long inputs.";
this.infoURL = "https://wikipedia.org/wiki/MD6";
this.inputType = "string";

View File

@@ -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;

View File

@@ -43,7 +43,7 @@ class Mean extends Operation {
*/
run(input, args) {
const val = mean(createNumArray(input, args[0]));
return val instanceof BigNumber ? val : new BigNumber(NaN);
return BigNumber.isBigNumber(val) ? val : new BigNumber(NaN);
}
}

View File

@@ -43,7 +43,7 @@ class Median extends Operation {
*/
run(input, args) {
const val = median(createNumArray(input, args[0]));
return val instanceof BigNumber ? val : new BigNumber(NaN);
return BigNumber.isBigNumber(val) ? val : new BigNumber(NaN);
}
}

View File

@@ -44,7 +44,7 @@ class Multiply extends Operation {
*/
run(input, args) {
const val = multi(createNumArray(input, args[0]));
return val instanceof BigNumber ? val : new BigNumber(NaN);
return BigNumber.isBigNumber(val) ? val : new BigNumber(NaN);
}
}

View File

@@ -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
}
];
}

View File

@@ -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
@@ -20,8 +21,8 @@ class ParseIPRange extends Operation {
super();
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.module = "Default";
this.description = "Given a CIDR range (e.g. <code>10.0.0.0/24</code>), hyphenated range (e.g. <code>10.0.0.0 - 10.0.1.0</code>), or a list of IPs and/or CIDR ranges (separated by a new line), this operation provides network information and enumerates all IP addresses in the range.<br><br>IPv6 is supported but will not be enumerated.";
this.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.");
}

View File

@@ -23,7 +23,7 @@ class ParseIPv4Header extends Operation {
super();
this.name = "Parse IPv4 header";
this.module = "JSBN";
this.module = "Default";
this.description = "Given an IPv4 header, this operations parses and displays each field in an easily readable format.";
this.infoURL = "https://wikipedia.org/wiki/IPv4#Header";
this.inputType = "string";

View File

@@ -8,7 +8,7 @@ import Operation from "../Operation";
import Utils from "../Utils";
import OperationError from "../errors/OperationError";
import {strToIpv6, ipv6ToStr, ipv4ToStr, IPV6_REGEX} from "../lib/IP";
import BigInteger from "jsbn";
import BigNumber from "bignumber.js";
/**
* Parse IPv6 address operation
@@ -22,7 +22,7 @@ class ParseIPv6Address extends Operation {
super();
this.name = "Parse IPv6 address";
this.module = "JSBN";
this.module = "Default";
this.description = "Displays the longhand and shorthand versions of a valid IPv6 address.<br><br>Recognises all reserved ranges and parses encapsulated or tunnelled addresses including Teredo and 6to4.";
this.infoURL = "https://wikipedia.org/wiki/IPv6_address";
this.inputType = "string";
@@ -147,7 +147,7 @@ class ParseIPv6Address extends Operation {
const v4Addr = ipv4ToStr((ipv6[1] << 16) + ipv6[2]),
slaId = ipv6[3],
interfaceIdStr = ipv6[4].toString(16) + ipv6[5].toString(16) + ipv6[6].toString(16) + ipv6[7].toString(16),
interfaceId = new BigInteger(interfaceIdStr, 16);
interfaceId = new BigNumber(interfaceIdStr, 16);
output += "\n\nEncapsulated IPv4 address: " + v4Addr +
"\nSLA ID: " + slaId +

View 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;

Some files were not shown because too many files have changed in this diff Show More