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

Compare commits

...

302 Commits

Author SHA1 Message Date
n1474335
33b606d48f 5.16.2 2017-08-21 15:25:41 +00:00
n1474335
cc44be7ef9 Fixed recipe saving 2017-08-21 15:25:35 +00:00
n1474335
e0eb972a54 Operations with no arguments can now be added to the recipe without causing errors 2017-08-18 16:12:49 +00:00
n1474335
19c54a99cd Improved web app title construction 2017-08-18 16:01:55 +00:00
n1474335
9d60ec22ee Updated links in index.html 2017-08-18 15:55:04 +01:00
n1474335
cb4eeccfd3 Updated links in README 2017-08-18 15:47:38 +01:00
n1474335
62e50caa99 5.16.1 2017-08-16 14:11:55 +00:00
n1474335
0192566d19 Improved recipe config generation for complex objects. Fixes #180 2017-08-16 14:11:50 +00:00
n1474335
8a8b70f2ab 5.16.0 2017-08-16 13:01:50 +00:00
n1474335
af311001cf Merge branch 'feature-pretty-recipe-format' 2017-08-16 13:01:08 +00:00
n1474335
040229418e 5.15.0 2017-08-15 17:32:31 +00:00
n1474335
c259963542 Fixed string escape test configs 2017-08-15 17:32:21 +00:00
n1474335
ca75f7fa0b Merge branch 'artemisbot-features/string_escape_unescape' 2017-08-15 17:30:12 +00:00
n1474335
4b22a409e7 Tidied up string escape operations 2017-08-15 17:29:48 +00:00
n1474335
55806db00f Merge branch 'features/string_escape_unescape' of https://github.com/artemisbot/CyberChef into artemisbot-features/string_escape_unescape 2017-08-15 17:16:39 +00:00
n1474335
83c757ebd4 Lint 2017-08-15 17:12:09 +00:00
n1474335
a19b02aa8c Updated URL regexes to match more unescaped special characters 2017-08-15 16:44:45 +00:00
n1474335
cf1ba60a10 Added new 'pretty' recipe format to make URLs more readable 2017-08-15 16:26:42 +00:00
n1474335
2a4c9afdf2 5.14.0 2017-08-10 12:42:00 +00:00
n1474335
ab76933158 Merge branch 'feature-themes' 2017-08-10 12:41:18 +00:00
n1474335
d4d7bcab7a Added GeoCities theme 2017-08-10 12:35:30 +00:00
n1474335
146a307b59 5.13.1 2017-08-08 14:47:55 +00:00
n1474335
875946b4e8 Modified babel to target Node 6.5 2017-08-08 14:47:48 +00:00
n1474335
81f2a460ed Added apploaded event to signify when the app has completed loading 2017-08-08 13:08:06 +00:00
Matt C
6698a2ac13 Added tests + fixes for PR
- actually removed prev func
- shuffled some stuff around
2017-08-07 16:08:50 +01:00
Matt C
9161cc693d Removes need for runParseEscapedString
- Fixes examples
- Actually makes it work
2017-08-04 15:54:00 +01:00
n1474335
be689e293d Removed dev commands from PublicKey.js 2017-08-04 14:44:12 +00:00
n1474335
53c22d5e29 5.13.0 2017-08-04 14:00:24 +00:00
n1474335
5c0c80829e Merge branch 'artemisbot-features/jpath' 2017-08-04 14:00:05 +00:00
n1474335
55aedfe901 Jsonpath lib now imported from npm with workaround instead of serving locally. 2017-08-04 13:59:32 +00:00
n1474335
4b87d66131 Merge branch 'features/jpath' of https://github.com/artemisbot/CyberChef into artemisbot-features/jpath 2017-08-04 13:36:03 +00:00
n1474335
fc9497f067 Updated dependencies 2017-08-04 13:35:52 +00:00
Matt C
3186335f47 Merge Vel0z/string_escaping_unescaping
Updated to new project format
2017-08-04 11:50:45 +01:00
Matt C
31bfd8664a Added JSONPath tests & changed lib 2017-08-03 14:50:16 +01:00
n1474335
ab1c9e27dc Added more loading messages 2017-08-03 10:57:54 +00:00
n1474335
c07cc913c8 5.12.4 2017-08-01 19:27:24 +00:00
n1474335
b8fb5493c5 Merge branch 'artemisbot-bug/text-overflow' 2017-08-01 19:25:04 +00:00
n1474335
e8e5eb9c53 Fixed some edge cases for popover triggering 2017-08-01 19:23:30 +00:00
n1474335
a15034b03e Merge branch 'bug/text-overflow' of https://github.com/artemisbot/CyberChef into artemisbot-bug/text-overflow 2017-08-01 15:40:31 +00:00
n1474335
1435acdc28 5.12.3 2017-08-01 14:42:52 +00:00
n1474335
37f164f11c Merge branch 'master' of github.com:gchq/CyberChef 2017-08-01 14:42:17 +00:00
n1474335
7a2f071269 Dependencies in the node version are now kept external in the webpack build 2017-08-01 14:42:09 +00:00
Matt C
9ee0964d0e Fixed hover issue - now allows scrolling 2017-07-29 00:45:41 +01:00
Matt C
33ecbfa95b Fixed arrow issue 2017-07-28 21:47:47 +01:00
n1474335
559c13a003 5.12.2 2017-07-28 16:44:48 +01:00
n1474335
8f00345430 Merge branch 'seo-structured-data' 2017-07-28 16:44:28 +01:00
n1474335
7a56af8ffa Page title changes to reflect recipe 2017-07-27 15:33:24 +00:00
n1474335
ed2bfbd27c Added structured data to help search engines 2017-07-27 15:33:01 +00:00
Matt C
e0905255ba Forgot about package-lock.json
oops
2017-07-25 16:36:01 +01:00
Matt C
de80db73f2 Adds initial JPath functionality 2017-07-25 16:27:59 +01:00
Matt C
90ed62add2 Fixes gchq/CyberChef#137
Changes data-trigger to focus so scrolling works and sets max height.
2017-07-25 11:49:23 +01:00
n1474335
d46e279933 Added link to 'Last build' notice showing commits since last release 2017-07-24 16:38:38 +00:00
n1474335
77e074efc2 5.12.1 2017-07-24 15:27:14 +00:00
n1474335
bd000d2d2c Merge branch 'lib-update' 2017-07-24 15:26:12 +00:00
n1474335
5f1c88104d Introduced key-spacing eslint rule 2017-07-24 14:55:48 +00:00
n1474335
a61df0832f Updated dependencies and linted 2017-07-24 13:49:16 +00:00
n1474335
58361e58f8 5.12.0 2017-07-19 16:03:24 +00:00
n1474335
96b4361b31 Merge branch 'feature-bcd' 2017-07-19 15:55:36 +00:00
n1474335
c773edceb9 Added BCD operations with tests 2017-07-19 15:29:37 +00:00
n1474335
bcaef8ba54 5.11.7 2017-07-18 16:17:59 +00:00
n1474335
c7d0b0ccc5 Merge branch 'feature-xor-brute-scheme' 2017-07-18 16:17:13 +00:00
n1474335
38792a0f02 Added differential schemes to 'XOR Brute Force' operation 2017-07-18 16:09:22 +00:00
n1474335
cda557e1b9 Removed sessionStorage as it is no longer used and marginally affects performance 2017-07-18 14:28:51 +00:00
n1474335
8d09f7c7eb 5.11.6 2017-07-17 13:31:37 +00:00
n1474335
4845a56435 Fixed Diff test for new higlighting class 2017-07-17 13:31:28 +00:00
n1474335
f164dcdd70 Fixed Diff highlighting classes 2017-07-17 13:19:08 +00:00
n1474335
6c8da6b070 Added ellipsis to overflowing args 2017-07-13 15:11:21 +00:00
n1474335
09df753ca9 5.11.5 2017-07-12 14:34:50 +00:00
n1474335
72ec9df1b1 Fixed option naming conventions 2017-07-12 14:34:45 +00:00
n1474335
086d5272ac 5.11.4 2017-07-12 12:49:22 +00:00
n1474335
2555de7712 Fixed bug in firefox where recipes containing an = character would not load from the URL 2017-07-12 12:49:10 +00:00
n1474335
645e540c66 5.11.3 2017-07-10 11:49:48 +00:00
n1474335
d16e1a4451 Fixed bug in 'Show Base64 offsets' where highlights did not show 2017-07-10 11:49:41 +00:00
n1474335
7c5dd2bd78 5.11.2 2017-07-07 13:30:27 +00:00
n1474335
2f0121f0e4 Merge branch 'bwhitn-unzipmod' 2017-07-07 13:28:21 +00:00
n1474335
7e310a8de7 Moved file switch listener to correct block 2017-07-07 13:27:47 +00:00
n1474335
c460c2bf6b Replaced hexToByteArray with fromHex and byteArrayToHex with toHex. Switched displayFilesAsHTML operation to use template strings and introduced markup formatting method. 2017-07-07 13:23:58 +00:00
n1474335
2400de337b Merge branch 'unzipmod' of https://github.com/bwhitn/CyberChef into bwhitn-unzipmod 2017-07-03 15:28:12 +00:00
n1474335
85d41085de 5.11.1 2017-07-03 15:25:52 +00:00
n1474335
48d45d026e Merge branch 'bwhitn-filetimemod' 2017-07-03 15:25:39 +00:00
n1474335
183c57643b Tidied up changes to filetime operations and brought tests up to date 2017-07-03 15:25:14 +00:00
n1474335
e7cea889ab Merge branch 'filetimemod' of https://github.com/bwhitn/CyberChef into bwhitn-filetimemod 2017-07-03 15:19:42 +00:00
n1474335
61c799447b Improved banner CSS 2017-07-03 15:18:47 +00:00
bwhitn
ad25daf206 Allow hex and decimal format for Windows Filetime format as those are the formats they are typically represented in 2017-07-02 20:04:25 -04:00
bwhitn
4143bba89f This adds the ability to move the file data from Utils.displayFilesAsHTML to the input. 2017-07-01 00:40:22 -04:00
n1474335
8eb7d65b74 5.11.0 2017-06-28 19:56:07 +01:00
n1474335
51798553e1 Merge branch 'artemisbot-features/bifid' 2017-06-28 19:55:19 +01:00
n1474335
323928ff86 Tidied up Bifid operations 2017-06-28 19:54:34 +01:00
n1474335
fe3aeabd0a Merge branch 'features/bifid' of https://github.com/artemisbot/CyberChef into artemisbot-features/bifid 2017-06-28 19:27:42 +01:00
n1474335
ec7a55dba6 5.10.7 2017-06-27 14:13:30 +00:00
n1474335
b4fe708d70 Merge branch 'bug-display-as-html' 2017-06-27 14:13:24 +00:00
n1474335
c3469bd545 Correctly escape filenames in displayFilesAsHTML 2017-06-27 14:04:30 +00:00
n1474335
92018b761d 5.10.6 2017-06-26 21:54:15 +01:00
n1474335
bb45ff0515 Merge branch 'bug-preloader' 2017-06-26 21:53:21 +01:00
n1474335
df1405e998 Fixed mildly infuriating bug where the preloader rings overlap 2017-06-26 21:47:57 +01:00
n1474335
62ec018bb2 Update README.md 2017-06-26 16:35:51 +01:00
n1474335
14b7c4bf23 Improved support for different alphabets in 'Substitute' operation 2017-06-23 13:21:19 +00:00
n1474335
5c774a3ce2 Updated to allow delimiter to be set 2017-06-23 12:18:08 +00:00
Matt C
246480daef Fixed styling errors 2017-06-22 17:13:31 +01:00
Matt C
91c6f682e7 Added Bifid Cipher Encode & Decode
Bifid Cipher + Tests
2017-06-21 22:28:17 +01:00
n1474335
a417a6469c Added package-lock.json 2017-06-20 14:45:20 +00:00
n1474335
2821bdd52b 5.10.5 2017-06-19 16:50:07 +00:00
n1474335
d37300be39 Merge branch 'bug-astral' 2017-06-19 16:49:17 +00:00
n1474335
15b83072bb Added support for astral characters to charcode ops 2017-06-19 15:40:36 +00:00
n1474335
6d2e2259db 5.10.4 2017-06-16 15:44:42 +00:00
n1474335
5b70614212 Merge branch 'tidy-links' 2017-06-16 15:38:37 +00:00
n1474335
4363da534d Updated links to new hash variant and cleaned up About and Option panes 2017-06-16 15:36:42 +00:00
n1474335
685f7a4f00 Create CODE_OF_CONDUCT.md 2017-06-16 15:32:55 +01:00
n1474335
6e26f25418 5.10.3 2017-06-16 11:26:03 +00:00
n1474335
d8051ce9a2 Merge branch 'feature-hashurls' 2017-06-16 11:23:16 +00:00
n1474335
00e7d8a390 The recipe and input are now stored in the hash part of the URL 2017-06-16 11:04:35 +00:00
bwhitn
213ec028b8 Merge pull request #2 from gchq/master
Current
2017-06-15 19:43:22 -04:00
n1474335
61951e76ac 5.10.2 2017-06-15 14:25:03 +00:00
n1474335
47cf763b3f Merge branch 'bug-findreplace' 2017-06-15 14:23:35 +00:00
n1474335
04aac03d6e Fixed global matching for simple strings in 'Find / Replace' operation. Closes #25. 2017-06-15 14:21:30 +00:00
n1474335
3faef2c9c9 5.10.1 2017-06-13 16:31:00 +00:00
n1474335
eda17d1671 Added mixed content note to 'HTTP request' error message. 2017-06-13 16:30:55 +00:00
n1474335
fbd6ead6b7 5.10.0 2017-06-13 15:34:36 +00:00
n1474335
bf2950abdd Merge branch 'bwhitn-master' 2017-06-13 15:33:59 +00:00
n1474335
3eacc325a3 Improved descriptions for timestamp operations. 2017-06-13 15:33:37 +00:00
n1474335
15decd9cd9 Merge branch 'master' of https://github.com/bwhitn/CyberChef into bwhitn-master 2017-06-13 14:12:20 +00:00
Bwhit1
c0142adba9 changed error to conform with the rest of the functions and simplified repetative math. 2017-06-12 15:39:54 -04:00
bwhitn
ec01333c83 removed decimal.min.js 2017-06-12 05:48:22 -07:00
bwhitn
8110384ea2 Fixed the names under the DateTime Category 2017-06-12 05:33:24 -07:00
bwhitn
0c2c0d7b8b Added DateTime test, added filetime functions to Catagories, and removed unused variables. 2017-06-12 05:28:41 -07:00
Bwhit1
ae38bb0927 Completion of simple filetime conversion 2017-06-11 20:05:30 -04:00
Bwhit1
003e076b00 modifications to FILETIME 2017-06-10 23:42:02 -04:00
n1474335
2c2a0eb7d9 5.9.2 2017-06-09 15:36:53 +00:00
n1474335
e7f5b17184 Manual bake now triggers when recipes are loaded from the URL. Fixes #93. 2017-06-09 15:36:15 +00:00
n1474335
69e12b1067 5.9.1 2017-06-09 15:21:45 +00:00
n1474335
fef446687a Loading messages won't repeat as often and cycle more slowly 2017-06-09 15:21:39 +00:00
n1474335
3affce8f98 5.9.0 2017-06-09 14:54:27 +00:00
n1474335
0b91468edc Merge branch 'tlwr-feature-http-request' 2017-06-09 14:53:39 +00:00
n1474335
127364e8a4 Added error handling for non-CORS requests. 2017-06-09 14:53:15 +00:00
bwhitn
a144f65dcf Create DateTime.js 2017-06-08 08:28:21 -07:00
bwhitn
96ec3a869b Use decimal.min.js and add the file. 2017-06-08 08:19:26 -07:00
n1474335
52426bc1a4 Merge branch 'master' into feature-http-request 2017-06-08 16:08:20 +01:00
n1474335
cbab995c6d Added error handling and CORS support 2017-06-08 15:03:55 +00:00
bwhitn
d27fa43120 Add conversions for from/to Windows Filetime to UNIX Epoch. Decimal.js is used to prevent rounding errors during conversion. 2017-06-08 07:23:11 -07:00
n1474335
45a9da5b30 5.8.0 2017-06-08 11:10:35 +00:00
n1474335
aed22aebb2 Merge branch 'davejm-feature-remove-exif' 2017-06-08 11:09:53 +00:00
n1474335
369d213da5 Tidying 'Remove EXIF' 2017-06-08 11:09:31 +00:00
n1474335
e92775eec2 Merge branch 'feature-remove-exif' of https://github.com/davejm/CyberChef into davejm-feature-remove-exif 2017-06-08 10:56:06 +00:00
bwhitn
2c0f48f4e5 Merge pull request #1 from gchq/master
update
2017-06-07 23:55:41 -04:00
toby
a5f1c430a3 Add "HTTP request" operation 2017-06-07 22:46:05 -04:00
David Moodie
e4a91b5397 Use functions from utils 2017-06-07 21:41:02 +01:00
David Moodie
cbcd45cd70 Do nothing if input is empty for removeEXIF operation 2017-06-07 20:01:45 +01:00
David Moodie
0968912954 Only reference JPEGs in removeEXIF description to be more clear 2017-06-07 19:51:09 +01:00
David Moodie
3bfe22c0f7 Remove piexifjs dep and extract removeEXIF to lib module 2017-06-07 19:49:44 +01:00
David Moodie
6cf64d794f Change == to === 2017-06-04 17:23:53 +01:00
David Moodie
6741ba0783 Add remove EXIF operation 2017-06-04 17:08:39 +01:00
n1474335
f1e7bc3363 5.7.3 2017-06-01 10:24:38 +00:00
n1474335
2dbe2d044e Merge branch 'qistoph-numsort' 2017-06-01 10:23:49 +00:00
n1474335
ea3630e018 Tidied _numericSort and added @author tag 2017-06-01 10:21:10 +00:00
Chris van Marle
c6391d958d Add numeric sorting tests 2017-05-30 08:53:18 +02:00
Chris van Marle
71aa4033a4 Add numeric sorting 2017-05-29 15:24:41 +02:00
n1474335
57dcd961d5 Option selects now default to the first option if not previously set 2017-05-24 10:29:47 +01:00
n1474335
83878d6b05 Update ControlsWaiter.js 2017-05-23 16:53:37 +01:00
n1474335
9055fc72d2 Added Boostrap grid CSS 2017-05-23 13:09:55 +01:00
n1474335
fb4ab56b47 Merge pull request #141 from tlwr/master
Add repo option to Travis
2017-05-21 19:36:12 +01:00
toby
51e195ed17 Add repo option to Travis 2017-05-20 23:56:58 -04:00
n1474335
9947c574d2 5.7.2 2017-05-20 13:49:29 +01:00
n1474335
693abdacf6 Merge branch 'tlwr-master' 2017-05-20 13:49:17 +01:00
toby
dd3b42fb53 Fix bug with UTF16LE in Encode/Decode ops 2017-05-19 16:11:08 -04:00
n1474335
8e72d7d0d6 5.7.1 2017-05-19 16:28:43 +00:00
n1474335
a6317212d9 Merge branch 'feature-loading-messages' 2017-05-19 16:25:30 +00:00
n1474335
347adf688a Added loading messages to preloader 2017-05-19 16:23:52 +00:00
n1474335
3ee67927a5 Moved bootstrap from devDependencies to dependencies and removed bootstrap-sass. 2017-05-19 14:17:34 +00:00
n1474335
7ecd36efcf Cleaned up extraneous character encoding functions in Utils.js 2017-05-19 14:05:57 +00:00
n1474335
714ce8a8a3 5.7.0 2017-05-19 13:45:30 +00:00
n1474335
7b18a2f46f Merge branch 'tlwr-feature-ebcdic' 2017-05-19 13:44:18 +00:00
n1474335
19103a64e5 Tidied up character encoding names 2017-05-19 13:43:55 +00:00
n1474335
a13f1d27e2 Merge branch 'feature-ebcdic' of https://github.com/tlwr/CyberChef into tlwr-feature-ebcdic 2017-05-19 13:16:54 +00:00
n1474335
9a6e4b1e85 5.6.0 2017-05-19 13:12:04 +00:00
n1474335
67b78fc230 Merge branch 'feature-render-images' 2017-05-19 13:11:12 +00:00
n1474335
5e79187176 Added ico and removed tiff from supported image types 2017-05-19 12:58:42 +00:00
n1474335
491a82cd67 Added 'Render Image' operation 2017-05-19 11:15:48 +00:00
n1474335
87c2ec678f 5.5.0 2017-05-19 00:22:50 +01:00
n1474335
70135ab3ea Really fix compile message formatting 2017-05-19 00:22:41 +01:00
n1474335
ad18d84f14 Fix option defaults and compile message formatting 2017-05-19 00:10:36 +01:00
n1474335
77e47e3fa4 Merge branch 'feature-sass' 2017-05-18 23:51:29 +01:00
n1474335
04432385b3 Merge branch 'master' into feature-sass 2017-05-18 23:50:43 +01:00
n1474335
cbdc24d869 Travis CI now adds a compile message 2017-05-18 23:46:03 +01:00
n1474335
2b3e471f96 Added version number to About/Support pane 2017-05-18 23:40:53 +01:00
n1474335
488d54493a Added modern browser warning for theme support 2017-05-18 23:29:04 +01:00
n1474335
a418f63a44 Added postcss-loader to provide fallbacks for older browsers 2017-05-18 23:24:24 +01:00
toby
0e285151f3 Add codepage numbers to CharEnc IO_FORMAT 2017-05-17 18:22:04 -04:00
n1474335
e4ad7768d5 Finalised the dark theme 2017-05-17 23:02:52 +01:00
toby
f800fab1a3 Add author tags to Encode text & Decode text ops 2017-05-17 17:31:28 -04:00
toby
dc61aeeeb8 Improve format of en/decoding text descriptions 2017-05-17 17:18:08 -04:00
toby
4b1d0fd011 Merge branch 'feature-ebcdic' of github.com:tlwr/CyberChef into feature-ebcdic 2017-05-17 11:30:20 -04:00
toby
2b7ba594fc Split "Text encoding" op into two ops
This commit splits "Text encoding" into two operations:
+ Encode text `string -> byteArray`
+ Decode text `byteArray -> string`

Base64 and Hex support are removed "Encode text" and "Decode text" as
they have their own operations.

Encode and decode operations now have support for the following
encodings:
+ IBM EBCDIC US-Canada
+ IBM EBCDIC International
+ Windows-874 Thai
+ Japanese Shift-JIS
+ Simplified Chinese GBK
+ Korean
+ Traditional Chinese Big5
+ UTF-16, little endian
+ UTF-16, big endian
+ Windows-1250 Central European
+ Windows-1251 Cyrillic
+ Windows-1252 Latin
+ Windows-1253 Greek
+ Windows-1254 Turkish
+ Windows-1255 Hebrew
+ Windows-1256 Arabic
+ Windows-1257 Baltic
+ Windows-1258 Vietnam
+ US-ASCII
+ Russian Cyrillic KOI8-R
+ Simplified Chinese GB2312
+ KOI8-U Ukrainian Cyrillic
+ ISO-8859-1 Latin 1 (Western European)
+ ISO-8859-2 Latin 2 (Central European)
+ ISO-8859-3 Latin 3
+ ISO-8859-4 Baltic
+ ISO-8859-5 Cyrillic
+ ISO-8859-6 Arabic
+ ISO-8859-7 Greek
+ ISO-8859-8 Hebrew
+ ISO-8859-9 Turkish
+ ISO-8859-10 Latin 6
+ ISO-8859-11 Latin (Thai)
+ ISO-8859-13 Latin 7 (Estonian)
+ ISO-8859-14 Latin 8 (Celtic)
+ ISO-8859-15 Latin 9
+ ISO-8859-16 Latin 10
+ ISO-2022 JIS Japanese
+ EUC Japanese
+ EUC Korean
+ Simplified Chinese GB18030
+ UTF-7
+ UTF-8
2017-05-17 11:17:11 -04:00
n1474335
d87b14af13 5.4.1 2017-05-17 14:45:19 +00:00
n1474335
83623d23cf Merge branch 'bug-timestamp' 2017-05-17 14:45:10 +00:00
n1474335
07fba53b73 'To UNIX Timestamp' operation now defaults to UTC instead of your local timezone. 2017-05-17 14:37:36 +00:00
n1474335
823b276ef5 Changed bootstrap-sass back to bootstrap (with less). Theme now loads before the preloader is shown. 2017-05-13 16:45:19 +01:00
n1474335
0e72d78731 5.4.0 2017-05-13 16:10:26 +01:00
n1474335
768609e357 Whitespace 2017-05-13 16:09:32 +01:00
n1474335
526a157421 Merge branch 'tlwr-feature-exif' 2017-05-13 16:08:39 +01:00
n1474335
62154309fb Newlines 2017-05-13 16:08:14 +01:00
n1474335
ad74e6c475 Merge branch 'feature-exif' of https://github.com/tlwr/CyberChef into tlwr-feature-exif 2017-05-13 15:59:48 +01:00
toby
82d28242cc Add JSDoc to the runEXIF function in Image.js 2017-05-09 15:34:18 -04:00
toby
60fddf837d Change let to const in "Extract EXIF" 2017-05-08 12:49:13 -04:00
toby
ee25df0c28 Add desc and fix error message for "Extract EXIF" 2017-05-08 12:48:43 -04:00
toby
478af40359 Fix "Extract EXIF" tests 2017-05-08 12:45:42 -04:00
Toby Lorne
6bf06a9629 Merge branch 'master' into feature-ebcdic 2017-05-07 18:21:30 -04:00
toby
3c15bd9e29 Add "{To,From} EBCDIC" operations
This adds operations
+ "To EBCDIC"
+ "From EBCDIC"

This makes use of the npm codepage package but it is not installed as a
dependency.

Instead I used the `make.sh` script to export pages 37 and 500.

To my knowledge there is no way currently to only import individual code pages
from the npm package (hence the included script).

If we were to import the package directly it increases the build size by
2.7MB.
2017-05-07 18:07:56 -04:00
toby
71796e3dbf Merge remote-tracking branch 'upstream/master' into feature-exif 2017-05-06 23:38:04 -04:00
n1474335
280f1ee2df Dark theme tweaks and improvements 2017-05-07 01:13:47 +01:00
n1474335
0dc72d8301 Merged master 2017-05-06 16:22:25 +01:00
n1474335
c43b67ea90 5.3.5 2017-05-06 16:15:29 +01:00
n1474335
244421b69e Merge branch 'graingert-prefer-const' 2017-05-06 16:14:58 +01:00
n1474335
1adedff61a Filter out source-map warnings in webpack output 2017-05-06 16:14:30 +01:00
n1474335
6abd10f9e2 Tidying codebase 2017-05-06 16:12:09 +01:00
n1474335
a85096ea11 5.3.4 2017-05-06 15:00:46 +01:00
n1474335
f67157f0ad Fixed erroring dependency 2017-05-06 15:00:28 +01:00
n1474335
5efe9bd91d Merge branch 'prefer-const' of https://github.com/graingert/CyberChef into graingert-prefer-const 2017-05-06 14:11:38 +01:00
n1474335
dc7a7267c9 5.3.4 2017-05-06 14:00:41 +01:00
n1474335
17188b1e38 Merge branch 'tlwr-feature-async-ops-small' 2017-05-06 14:00:08 +01:00
n1474335
e9c3bebfff Fixed lint error 2017-05-06 13:59:33 +01:00
n1474335
03fc22d3da Merge conflicts 2017-05-06 13:47:26 +01:00
n1474335
5d52c49c31 5.3.3 2017-05-05 16:04:22 +00:00
n1474335
d53da4cfb5 Merge branch 'bug-x509-sig' 2017-05-05 16:03:40 +00:00
n1474335
76204f5f47 Fixed lint errors 2017-05-05 16:03:25 +00:00
n1474335
b68adbd9a8 Merge branch 'master' into bug-x509-sig 2017-05-05 16:02:12 +00:00
n1474335
951b168f3a 5.3.2 2017-05-05 16:00:40 +00:00
n1474335
53d89af459 Merge branch 'feature-key-derivation-hashers' 2017-05-05 15:58:00 +00:00
n1474335
4f844ea837 Merge branch 'master' into feature-key-derivation-hashers 2017-05-05 15:57:42 +00:00
n1474335
59a36e77bd 5.3.1 2017-05-05 15:55:58 +00:00
n1474335
61d8d4473c Merge branch 'graingert-use-array-fill' 2017-05-05 15:55:46 +00:00
n1474335
508a371175 Fixed offset checker array initialisation 2017-05-05 15:54:59 +00:00
n1474335
b010fd88e8 Fix X.509 signature breakout bug 2017-05-05 15:42:24 +00:00
n1474335
66a93b81c6 Added hasher argument to PBKDF2 and EVPKDF operations. 2017-05-05 15:38:38 +00:00
toby
274e1139fa Remove debounce from Utils 2017-05-03 10:43:30 -04:00
toby
6122e33f4f Removed debounced autobake & stop disabling input 2017-05-03 10:35:15 -04:00
Thomas Grainger
b365ce3195 fix the first 100 prefer-const errors 2017-05-03 00:41:01 +01:00
Thomas Grainger
0a3233d289 move spider images to .json file 2017-05-03 00:41:01 +01:00
Thomas Grainger
15aea9e9ea auto-fix prefer-const 2017-05-03 00:41:01 +01:00
Thomas Grainger
5b03a84be8 use .fill to initialise Arrays 2017-05-02 23:05:04 +01:00
n1474335
80cdf0c014 Merge conflict 2017-05-02 23:03:28 +01:00
n1474335
d41d56e670 5.3.0 2017-05-02 22:54:56 +01:00
n1474335
7e4e1f1a0d Merge branch 'graingert-no-var-rule' 2017-05-02 22:54:41 +01:00
n1474335
463b06f508 Consistency modifications 2017-05-02 22:53:57 +01:00
n1474335
d3377d56b4 Merge branch 'no-var-rule' of https://github.com/graingert/CyberChef into graingert-no-var-rule 2017-05-02 22:28:17 +01:00
n1474335
c7611fbc05 Merge pull request #123 from gchq/feature-comment
Feature: 'Comment' operation
2017-05-02 21:05:58 +01:00
n1474335
67ee218f69 Merge pull request #124 from tlwr/feature-camel-snake-case
Add operations "To {Snake,Camel,Kebab} case"
2017-05-02 21:04:49 +01:00
n1474335
d1d394eec7 Fix search-results layout bug. 2017-05-02 20:56:57 +01:00
toby
98bc68c2bf Update descriptions to explain context awareness 2017-05-02 12:17:43 -04:00
toby
116c0680a2 Make camel,etc smart and add tests 2017-05-02 11:51:33 -04:00
toby
1b8a25ec88 Add "Extract EXIF" operation 2017-04-29 16:06:16 -04:00
toby
d5def01a9d Add operations To {Snake,Camel,Kebab} case 2017-04-29 13:42:07 -04:00
Thomas Grainger
ee07b72415 move eslintrc up a directory 2017-04-28 16:53:38 +01:00
Thomas Grainger
f7547db272 ignore vendor 2017-04-28 16:50:12 +01:00
Thomas Grainger
5d271687ec fix vars in Gruntfile 2017-04-28 16:50:12 +01:00
Thomas Grainger
d05543db30 manual fixes 2017-04-28 16:45:02 +01:00
Thomas Grainger
b33f73ac9a autofix no-var 2017-04-28 16:45:00 +01:00
n1474335
31e5d785fe Added badges for npm version and repo size to the README 2017-04-28 13:28:31 +01:00
n1474335
8096fd20a7 Fixed lint errors 2017-04-27 13:12:45 +00:00
n1474335
addd45ae8e Added 'Comment' operation for annotating the recipe 2017-04-27 13:05:29 +00:00
n1474335
d6895537ac Added more keywords and bug link to package.json 2017-04-27 10:43:11 +00:00
n1474335
4ac40fee5e 5.2.4 2017-04-27 10:24:43 +00:00
n1474335
05b8d0b45c Added Travis deployment for npm. 2017-04-27 10:23:01 +00:00
n1474335
446f539803 5.2.3 2017-04-27 09:14:35 +00:00
n1474335
6ef2e46aa3 Merge branch 'bug-popover' 2017-04-27 09:14:11 +00:00
n1474335
e4c5c4a901 Fixed bug where popovers on operations stopped working after the operation was dragged into the recipe. 2017-04-27 09:10:18 +00:00
n1474335
be231f3a91 5.2.2 2017-04-26 11:05:50 +00:00
n1474335
39f36c9184 Removed excess auto-baking when an operation is added to the recipe. Fixes #120. 2017-04-26 11:05:44 +00:00
n1474335
2e4076bb75 Added option to change the theme. 2017-04-25 00:21:38 +01:00
n1474335
d71ac2e894 Moved from Sass to CSS with custom properties, allowing for dynamic theme changes. 2017-04-24 23:59:35 +01:00
n1474335
7e7da26f29 5.2.1 2017-04-24 11:54:05 +00:00
n1474335
4375a151dd BUGFIX #119: Recipe names are now correctly escaped. 2017-04-24 11:53:55 +00:00
n1474335
0f02fb5d05 5.2.0 2017-04-23 18:53:55 +01:00
n1474335
05edc1f9c4 Merge branch 'tlwr-feature-select-lines-op' 2017-04-23 18:53:21 +01:00
toby
50784f2600 Debounce autobake in the web app.
Added debounce with guidance from the underscore.js implementation:
e944e0275a/underscore.js (L880)
2017-04-23 13:41:28 -04:00
n1474335
2c0f0d9a20 Changed Head and Tail tests to match new 'AllBut' configuration. 2017-04-23 18:29:54 +01:00
toby
21c0fed833 Fix bug: baking error did not reset baking status 2017-04-23 13:14:59 -04:00
n1474335
d081ff745d Added Head and Tail to Utils category and replaced 'AllBut' argument functionality with support for negative values of n. 2017-04-23 18:05:00 +01:00
n1474335
e3f41fea9c Developing a dark theme. 2017-04-23 17:09:12 +01:00
toby
dea214bd2e Add Head and Tail operations 2017-04-21 23:10:34 -04:00
toby
a13e2468db Added UI loading indications to the HTML app 2017-04-21 20:04:12 -04:00
toby
3fb660d816 Add jsdoc-babel plugin
This is to stop jsdoc parsing errors.

More information in this thread:
https://github.com/jsdoc3/jsdoc/issues/555
2017-04-21 18:05:30 -04:00
toby
9f60dc3dd6 Change ecmaVersion to 8 to make eslint happy 2017-04-21 17:56:16 -04:00
toby
02f855ff09 Add more tests for flow control ops 2017-04-21 17:49:10 -04:00
toby
c39622ed1e Add support for async ops using async/await 2017-04-21 17:48:42 -04:00
n1474335
07bb095e73 Merge pull request #115 from tlwr/patch-1
Update Crown Copyright to 2017 in jsdoc.conf.json
2017-04-15 20:49:10 +01:00
n1474335
e409029bb3 Merge pull request #116 from tlwr/patch-2
Add Travis CI badge to README.md
2017-04-15 20:48:42 +01:00
n1474335
a4d93f23d6 Added preloader to hide elements before they are correctly rendered 2017-04-15 20:46:57 +01:00
Toby Lorne
6201176852 Add Travis CI badge to README.md 2017-04-13 15:36:17 -04:00
Toby Lorne
7d958cc20e Update Crown Copyright to 2017 in jsdoc.conf.json 2017-04-13 15:23:54 -04:00
n1474335
e0e5670d0e Styles rewritten in a modular format with themable properties stored in variables. 2017-04-13 17:59:37 +01:00
n1474335
68e855e3d2 Merge branch 'FloatingGhost-master' 2017-04-11 14:42:14 +00:00
n1474335
bf91352fce Modified comments in Code.js 2017-04-11 14:41:30 +00:00
n1474335
a840504b3d Merge branch 'master' of https://github.com/FloatingGhost/CyberChef into FloatingGhost-master 2017-04-11 14:38:29 +00:00
n1474335
e120422b05 Styles now imported through Sass. Less removed. 2017-04-09 14:06:59 +01:00
n1474335
c60e99288f 5.1.3 2017-04-07 23:03:17 +01:00
n1474335
d9006d6e37 Merge pull request #110 from artemisbot/feature/accessibility
Made changes to fix accessibility errors
2017-04-07 23:10:42 +01:00
Matt C
9121b83bd1 Update Gruntfile.js 2017-04-07 23:01:37 +01:00
Matt C
44d2e100bd Made changes to fix accessibility errors
Still some warnings and notices, but they are inconsequential.
2017-04-07 17:00:32 +01:00
Hannah Ward
8d9c114acd fix: Re-add comments in code replacements 2017-04-07 13:59:00 +01:00
Hannah Ward
bce0950498 chg: Removed redundant code = code.replace 2017-04-06 12:43:37 +01:00
Hannah Ward
dcac64fb9a chg: Compress repeated replaces 2017-04-06 12:31:44 +01:00
Dale Myers
fadd7158ed Add string escape/unescape operations
These operations are useful for taking the contents of a string, and making it
suitable for use as a stand alone string. For example, in an IDE you might see
a string which is represented as: "Say \"Hello\"". The escaped double quotes
are shown to make it clear that they do not end the string, despite the fact
that they are not truly part of the string. In order to get the raw string, you
would need to copy this, then manually remove the backslashes. The new
String_.run_unescape operation does this automatically.

The String_.run_escape is the inverse. It allows you to take a string like the
one above, and paste it between two quotes without having to manually escape
it.
2017-01-23 21:39:08 +00:00
122 changed files with 18396 additions and 3976 deletions

View File

@@ -4,9 +4,11 @@
"targets": {
"chrome": 40,
"firefox": 35,
"edge": 14
"edge": 14,
"node": "6.5",
},
"modules": false
"modules": false,
"useBuiltIns": true
}]
]
}

1
.eslintignore Normal file
View File

@@ -0,0 +1 @@
src/core/lib/**

View File

@@ -1,6 +1,6 @@
{
"parserOptions": {
"ecmaVersion": 6,
"ecmaVersion": 8,
"ecmaFeatures": {
"impliedStrict": true
},
@@ -52,6 +52,9 @@
"no-trailing-spaces": "warn",
"eol-last": "error",
"func-call-spacing": "error",
"key-spacing": ["warn", {
"mode": "minimum"
}],
"indent": ["error", 4, {
"ArrayExpression": "first",
"SwitchCase": 1
@@ -84,7 +87,8 @@
}],
"no-whitespace-before-property": "error",
"operator-linebreak": ["error", "after"],
"space-in-parens": "error"
"space-in-parens": "error",
"no-var": "error"
},
"globals": {
"$": false,
@@ -92,6 +96,7 @@
"moment": false,
"COMPILE_TIME": false,
"COMPILE_MSG": false
"COMPILE_MSG": false,
"PKG_VERSION": false
}
}

1
.gitignore vendored
View File

@@ -1,5 +1,6 @@
node_modules
npm-debug.log
travis.log
build
docs/*
!docs/*.conf.json

8
.npmignore Executable file
View File

@@ -0,0 +1,8 @@
node_modules
npm-debug.log
travis.log
build/*
!build/node
docs
.vscode
.github

View File

@@ -9,7 +9,7 @@ script:
- grunt test
- grunt docs
- grunt node
- grunt prod
- grunt prod --msg="$COMPILE_MSG"
before_deploy:
- grunt copy:ghPages
deploy:
@@ -19,6 +19,7 @@ deploy:
local_dir: build/prod/
target_branch: gh-pages
on:
repo: gchq/CyberChef
branch: master
- provider: releases
skip_cleaup: true
@@ -30,3 +31,12 @@ deploy:
on:
repo: gchq/CyberChef
tags: true
- provider: npm
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="
on:
tags: true
branch: master

46
CODE_OF_CONDUCT.md Normal file
View File

@@ -0,0 +1,46 @@
# Contributor Covenant Code of Conduct
## Our Pledge
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation.
## Our Standards
Examples of behavior that contributes to creating a positive environment include:
* Using welcoming and inclusive language
* Being respectful of differing viewpoints and experiences
* Gracefully accepting constructive criticism
* Focusing on what is best for the community
* Showing empathy towards other community members
Examples of unacceptable behavior by participants include:
* The use of sexualized language or imagery and unwelcome sexual attention or advances
* Trolling, insulting/derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or electronic address, without explicit permission
* Other conduct which could reasonably be considered inappropriate in a professional setting
## Our Responsibilities
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior.
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
## Scope
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at oss@gchq.gov.uk. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version]
[homepage]: http://contributor-covenant.org
[version]: http://contributor-covenant.org/version/1/4/

View File

@@ -1,7 +1,8 @@
var webpack = require("webpack"),
ExtractTextPlugin = require("extract-text-webpack-plugin"),
HtmlWebpackPlugin = require("html-webpack-plugin"),
Inliner = require("web-resource-inliner");
const webpack = require("webpack");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const NodeExternals = require("webpack-node-externals");
const Inliner = require("web-resource-inliner");
module.exports = function (grunt) {
grunt.file.defaultEncoding = "utf8";
@@ -54,7 +55,7 @@ module.exports = function (grunt) {
// Project configuration
var compileTime = grunt.template.today("dd/mm/yyyy HH:MM:ss") + " UTC",
const compileTime = grunt.template.today("UTC:dd/mm/yyyy HH:MM:ss") + " UTC",
banner = "/**\n" +
"* CyberChef - The Cyber Swiss Army Knife\n" +
"*\n" +
@@ -74,13 +75,14 @@ module.exports = function (grunt) {
"* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" +
"* See the License for the specific language governing permissions and\n" +
"* limitations under the License.\n" +
"*/\n";
"*/\n",
pkg = grunt.file.readJSON("package.json");
/**
* Compiles a production build of CyberChef into a single, portable web page.
*/
function runInliner() {
var inlinerError = false;
const done = this.async();
Inliner.html({
relativeTo: "build/prod/",
fileContent: grunt.file.read("build/prod/cyberchef.htm"),
@@ -91,14 +93,16 @@ module.exports = function (grunt) {
strict: true
}, function(error, result) {
if (error) {
console.log(error);
inlinerError = true;
return false;
if (error instanceof Error) {
done(error);
} else {
done(new Error(error));
}
} else {
grunt.file.write("build/prod/cyberchef.htm", result);
done(true);
}
grunt.file.write("build/prod/cyberchef.htm", result);
});
return !inlinerError;
}
grunt.initConfig({
@@ -111,7 +115,7 @@ module.exports = function (grunt) {
},
eslint: {
options: {
configFile: "src/.eslintrc.json"
configFile: "./.eslintrc.json"
},
configs: ["Gruntfile.js"],
core: ["src/core/**/*.js", "!src/core/lib/**/*"],
@@ -136,7 +140,11 @@ module.exports = function (grunt) {
},
accessibility: {
options: {
accessibilityLevel: "WCAG2A"
accessibilityLevel: "WCAG2A",
verbose: false,
ignore: [
"WCAG2A.Principle1.Guideline1_3.1_3_1.H42.2"
]
},
test: {
src: ["build/**/*.html"]
@@ -157,7 +165,8 @@ module.exports = function (grunt) {
}),
new webpack.DefinePlugin({
COMPILE_TIME: JSON.stringify(compileTime),
COMPILE_MSG: JSON.stringify(grunt.option("compile-msg") || grunt.option("msg") || "")
COMPILE_MSG: JSON.stringify(grunt.option("compile-msg") || grunt.option("msg") || ""),
PKG_VERSION: JSON.stringify(pkg.version)
}),
new ExtractTextPlugin("styles.css"),
],
@@ -176,7 +185,10 @@ module.exports = function (grunt) {
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
use: "css-loader?minimize"
use: [
{ loader: "css-loader?minimize" },
{ loader: "postcss-loader" },
]
})
},
{
@@ -184,6 +196,7 @@ module.exports = function (grunt) {
use: ExtractTextPlugin.extract({
use: [
{ loader: "css-loader?minimize" },
{ loader: "postcss-loader" },
{ loader: "less-loader" }
]
})
@@ -214,7 +227,11 @@ module.exports = function (grunt) {
]
},
stats: {
children: false
children: false,
warningsFilter: /source-map/
},
node: {
fs: "empty"
}
},
webDev: {
@@ -228,7 +245,8 @@ module.exports = function (grunt) {
new HtmlWebpackPlugin({
filename: "index.html",
template: "./src/web/html/index.html",
compileTime: compileTime
compileTime: compileTime,
version: pkg.version,
})
],
watch: true
@@ -254,6 +272,7 @@ module.exports = function (grunt) {
filename: "index.html",
template: "./src/web/html/index.html",
compileTime: compileTime,
version: pkg.version,
minify: {
removeComments: true,
collapseWhitespace: true,
@@ -265,6 +284,7 @@ module.exports = function (grunt) {
filename: "cyberchef.htm",
template: "./src/web/html/index.html",
compileTime: compileTime,
version: pkg.version,
inline: true,
minify: {
removeComments: true,
@@ -278,6 +298,7 @@ module.exports = function (grunt) {
tests: {
target: "node",
entry: "./test/index.js",
externals: [NodeExternals()],
output: {
filename: "index.js",
path: __dirname + "/build/test"
@@ -286,6 +307,7 @@ module.exports = function (grunt) {
node: {
target: "node",
entry: "./src/node/index.js",
externals: [NodeExternals()],
output: {
filename: "CyberChef.js",
path: __dirname + "/build/node",
@@ -297,7 +319,7 @@ module.exports = function (grunt) {
copy: {
ghPages: {
options: {
process: function (content, srcpath) {
process: function (content) {
// Add Google Analytics code to index.html
content = content.replace("</body></html>",
grunt.file.read("src/web/static/ga.html") + "</body></html>");
@@ -338,5 +360,4 @@ module.exports = function (grunt) {
test: "build/test/index.js"
},
});
};

View File

@@ -1,10 +1,14 @@
# CyberChef
[![Build Status](https://travis-ci.org/gchq/CyberChef.svg?branch=master)](https://travis-ci.org/gchq/CyberChef)
[![npm](https://badge.fury.io/js/cyberchef.svg)](https://www.npmjs.com/package/cyberchef)
![](https://reposs.herokuapp.com/?path=gchq/CyberChef&color=brightgreen)
#### *The Cyber Swiss Army Knife*
CyberChef is a simple, intuitive web app for carrying out all manner of "cyber" operations within a web browser. These operations include creating hexdumps, simple encoding like XOR or Base64, more complex encryption like AES, DES and Blowfish, data compression and decompression, calculating hashes and checksums, IPv6 and X.509 parsing, and much more.
CyberChef is a simple, intuitive web app for carrying out all manner of "cyber" operations within a web browser. These operations include simple encoding like XOR or Base64, more complex encryption like AES, DES and Blowfish, creating binary and hexdumps, compression and decompression of data, calculating hashes and checksums, IPv6 and X.509 parsing, changing character encodings, and much more.
The tool is designed to enable both technical and non-technical analysts to manipulate data in complex ways without having to deal with complex tools or algorithms. It was conceived, designed, built and incrementally improved by an analyst in their 10% innovation time over several years. Every effort has been made to structure the code in a readable and extendable format, however it should be noted that the analyst is not a professional developer and the code has not been peer-reviewed for compliance with a formal specification.
The tool is designed to enable both technical and non-technical analysts to manipulate data in complex ways without having to deal with complex tools or algorithms. It was conceived, designed, built and incrementally improved by an analyst in their 10% innovation time over several years. Every effort has been made to structure the code in a readable and extendable format, however it should be noted that the analyst is not a professional developer.
## Live demo
@@ -20,9 +24,9 @@ Cryptographic operations in CyberChef should not be relied upon to provide secur
There are four main areas in CyberChef:
1. The **input** box in the top right, where you can paste, type or drag the data you want to operate on.
2. The **output** box in the bottom right, where the outcome of the specified processing will be displayed.
2. The **output** box in the bottom right, where the outcome of your processing will be displayed.
3. The **operations** list on the far left, where you can find all the operations that CyberChef is capable of in categorised lists, or by searching.
4. The **recipe** area in the middle, where you drag the operations that you want to use and specify arguments and options.
4. The **recipe** area in the middle, where you can drag the operations that you want to use and specify arguments and options.
You can use as many operations as you like in simple or complex ways. Some examples are as follows:
@@ -62,12 +66,16 @@ You can use as many operations as you like in simple or complex ways. Some examp
## Browser support
CyberChef is built to support Google Chrome 40+, Mozilla Firefox 35+ and Microsoft Edge 14+.
CyberChef is built to support
- Google Chrome 40+
- Mozilla Firefox 35+
- Microsoft Edge 14+
## Contributing
An installation walkthrough, how-to guides for adding new operations, descriptions of the repository structure, available data types and coding conventions can all be found in the project [wiki pages](https://github.com/gchq/CyberChef/wiki).
An installation walkthrough, how-to guides for adding new operations and themes, descriptions of the repository structure, available data types and coding conventions can all be found in the project [wiki pages](https://github.com/gchq/CyberChef/wiki).
- Sign the [GCHQ Contributor Licence Agreement](https://github.com/gchq/Gaffer/wiki/GCHQ-OSS-Contributor-License-Agreement-V1.0)
- Push your changes to your fork.
@@ -80,10 +88,10 @@ CyberChef is released under the [Apache 2.0 Licence](https://www.apache.org/lice
[1]: https://gchq.github.io/CyberChef
[2]: https://gchq.github.io/CyberChef/?recipe=%5B%7B%22op%22%3A%22From%20Base64%22%2C%22args%22%3A%5B%22A-Za-z0-9%2B%2F%3D%22%2Ctrue%5D%7D%5D&input=VTI4Z2JHOXVaeUJoYm1RZ2RHaGhibXR6SUdadmNpQmhiR3dnZEdobElHWnBjMmd1
[3]: https://gchq.github.io/CyberChef/?recipe=%5B%7B%22op%22%3A%22Translate%20DateTime%20Format%22%2C%22args%22%3A%5B%22Standard%20date%20and%20time%22%2C%22DD%2FMM%2FYYYY%20HH%3Amm%3Ass%22%2C%22UTC%22%2C%22dddd%20Do%20MMMM%20YYYY%20HH%3Amm%3Ass%20Z%20z%22%2C%22Australia%2FQueensland%22%5D%7D%5D&input=MTUvMDYvMjAxNSAyMDo0NTowMA
[4]: https://gchq.github.io/CyberChef/?recipe=%5B%7B%22op%22%3A%22Parse%20IPv6%20address%22%2C%22args%22%3A%5B%5D%7D%5D&input=MjAwMTowMDAwOjQxMzY6ZTM3ODo4MDAwOjYzYmY6M2ZmZjpmZGQy
[5]: https://gchq.github.io/CyberChef/?recipe=%5B%7B%22op%22%3A%22From%20Hexdump%22%2C%22args%22%3A%5B%5D%7D%2C%7B%22op%22%3A%22Gunzip%22%2C%22args%22%3A%5B%5D%7D%5D&input=MDAwMDAwMDAgIDFmIDhiIDA4IDAwIDEyIGJjIGYzIDU3IDAwIGZmIDBkIGM3IGMxIDA5IDAwIDIwICB8Li4uLi6881cu%2Fy7HwS4uIHwKMDAwMDAwMTAgIDA4IDA1IGQwIDU1IGZlIDA0IDJkIGQzIDA0IDFmIGNhIDhjIDQ0IDIxIDViIGZmICB8Li7QVf4uLdMuLsouRCFb%2F3wKMDAwMDAwMjAgIDYwIGM3IGQ3IDAzIDE2IGJlIDQwIDFmIDc4IDRhIDNmIDA5IDg5IDBiIDlhIDdkICB8YMfXLi6%2BQC54Sj8uLi4ufXwKMDAwMDAwMzAgIDRlIGM4IDRlIDZkIDA1IDFlIDAxIDhiIDRjIDI0IDAwIDAwIDAwICAgICAgICAgICB8TshObS4uLi5MJC4uLnw
[6]: https://gchq.github.io/CyberChef/?recipe=%5B%7B%22op%22%3A%22Fork%22%2C%22args%22%3A%5B%22%5C%5Cn%22%2C%22%5C%5Cn%22%5D%7D%2C%7B%22op%22%3A%22From%20UNIX%20Timestamp%22%2C%22args%22%3A%5B%22Seconds%20(s)%22%5D%7D%5D&input=OTc4MzQ2ODAwCjEwMTI2NTEyMDAKMTA0NjY5NjQwMAoxMDgxMDg3MjAwCjExMTUzMDUyMDAKMTE0OTYwOTYwMA
[7]: https://gchq.github.io/CyberChef/?recipe=%5B%7B%22op%22%3A%22Fork%22%2C%22args%22%3A%5B%22%5C%5Cn%22%2C%22%5C%5Cn%22%5D%7D%2C%7B%22op%22%3A%22Conditional%20Jump%22%2C%22args%22%3A%5B%221%22%2C%222%22%2C%2210%22%5D%7D%2C%7B%22op%22%3A%22To%20Hex%22%2C%22args%22%3A%5B%22Space%22%5D%7D%2C%7B%22op%22%3A%22Return%22%2C%22args%22%3A%5B%5D%7D%2C%7B%22op%22%3A%22To%20Base64%22%2C%22args%22%3A%5B%22A-Za-z0-9%2B%2F%3D%22%5D%7D%5D&input=U29tZSBkYXRhIHdpdGggYSAxIGluIGl0ClNvbWUgZGF0YSB3aXRoIGEgMiBpbiBpdA
[8]: https://gchq.github.io/CyberChef/?recipe=%5B%7B%22op%22%3A%22XOR%22%2C%22args%22%3A%5B%7B%22option%22%3A%22Hex%22%2C%22string%22%3A%223a%22%7D%2Cfalse%2Cfalse%5D%7D%2C%7B%22op%22%3A%22To%20Hexdump%22%2C%22args%22%3A%5B%2216%22%2Cfalse%2Cfalse%5D%7D%5D&input=VGhlIGFuc3dlciB0byB0aGUgdWx0aW1hdGUgcXVlc3Rpb24gb2YgbGlmZSwgdGhlIFVuaXZlcnNlLCBhbmQgZXZlcnl0aGluZyBpcyA0Mi4
[2]: https://gchq.github.io/CyberChef/#recipe=From_Base64('A-Za-z0-9%2B/%3D',true)&input=VTI4Z2JHOXVaeUJoYm1RZ2RHaGhibXR6SUdadmNpQmhiR3dnZEdobElHWnBjMmd1
[3]: https://gchq.github.io/CyberChef/#recipe=Translate_DateTime_Format('Standard%20date%20and%20time','DD/MM/YYYY%20HH:mm:ss','UTC','dddd%20Do%20MMMM%20YYYY%20HH:mm:ss%20Z%20z','Australia/Queensland')&input=MTUvMDYvMjAxNSAyMDo0NTowMA
[4]: https://gchq.github.io/CyberChef/#recipe=Parse_IPv6_address()&input=MjAwMTowMDAwOjQxMzY6ZTM3ODo4MDAwOjYzYmY6M2ZmZjpmZGQy
[5]: https://gchq.github.io/CyberChef/#recipe=From_Hexdump()Gunzip()&input=MDAwMDAwMDAgIDFmIDhiIDA4IDAwIDEyIGJjIGYzIDU3IDAwIGZmIDBkIGM3IGMxIDA5IDAwIDIwICB8Li4uLi6881cu/y7HwS4uIHwKMDAwMDAwMTAgIDA4IDA1IGQwIDU1IGZlIDA0IDJkIGQzIDA0IDFmIGNhIDhjIDQ0IDIxIDViIGZmICB8Li7QVf4uLdMuLsouRCFb/3wKMDAwMDAwMjAgIDYwIGM3IGQ3IDAzIDE2IGJlIDQwIDFmIDc4IDRhIDNmIDA5IDg5IDBiIDlhIDdkICB8YMfXLi6%2BQC54Sj8uLi4ufXwKMDAwMDAwMzAgIDRlIGM4IDRlIDZkIDA1IDFlIDAxIDhiIDRjIDI0IDAwIDAwIDAwICAgICAgICAgICB8TshObS4uLi5MJC4uLnw
[6]: https://gchq.github.io/CyberChef/#recipe=Fork('%5C%5Cn','%5C%5Cn',false)From_UNIX_Timestamp('Seconds%20(s)')&input=OTc4MzQ2ODAwCjEwMTI2NTEyMDAKMTA0NjY5NjQwMAoxMDgxMDg3MjAwCjExMTUzMDUyMDAKMTE0OTYwOTYwMA
[7]: https://gchq.github.io/CyberChef/#recipe=Fork('%5C%5Cn','%5C%5Cn',false)Conditional_Jump('1',2,10)To_Hex('Space')Return()To_Base64('A-Za-z0-9%2B/%3D')&input=U29tZSBkYXRhIHdpdGggYSAxIGluIGl0ClNvbWUgZGF0YSB3aXRoIGEgMiBpbiBpdA
[8]: https://gchq.github.io/CyberChef/#recipe=XOR(%7B'option':'Hex','string':'3a'%7D,'',false)To_Hexdump(16,false,false)&input=VGhlIGFuc3dlciB0byB0aGUgdWx0aW1hdGUgcXVlc3Rpb24gb2YgbGlmZSwgdGhlIFVuaXZlcnNlLCBhbmQgZXZlcnl0aGluZyBpcyA0Mi4

View File

@@ -2,11 +2,14 @@
"tags": {
"allowUnknownTags": true
},
"plugins": ["plugins/markdown"],
"plugins": [
"plugins/markdown",
"node_modules/jsdoc-babel"
],
"templates": {
"systemName": "CyberChef",
"footer": "",
"copyright": "&copy; Crown Copyright 2016",
"copyright": "&copy; Crown Copyright 2017",
"navType": "inline",
"theme": "cerulean",
"linenums": true,

8010
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,7 @@
{
"name": "cyberchef",
"version": "5.1.2",
"description": "CyberChef is a simple, intuitive web app for analysing and decoding data within a web browser.",
"version": "5.16.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",
"copyright": "Crown copyright 2016",
@@ -19,64 +19,76 @@
"hex",
"encoding",
"format",
"cybersecurity"
"cybersecurity",
"data manipulation",
"data analysis"
],
"repository": {
"type": "git",
"url": "https://github.com/gchq/CyberChef/"
},
"main": "build/node/CyberChef.js",
"bugs": "https://github.com/gchq/CyberChef/issues",
"devDependencies": {
"babel-core": "^6.24.0",
"babel-loader": "^6.4.0",
"babel-polyfill": "^6.23.0",
"babel-preset-env": "^1.2.2",
"css-loader": "^0.27.3",
"babel-loader": "^7.1.1",
"babel-preset-env": "^1.6.0",
"css-loader": "^0.28.4",
"exports-loader": "^0.6.4",
"extract-text-webpack-plugin": "^2.1.0",
"file-loader": "^0.10.1",
"extract-text-webpack-plugin": "^3.0.0",
"file-loader": "^0.11.2",
"grunt": ">=0.4.5",
"grunt-accessibility": "~5.0.0",
"grunt-chmod": "~1.1.1",
"grunt-contrib-clean": "~1.0.0",
"grunt-contrib-clean": "~1.1.0",
"grunt-contrib-copy": "~1.0.0",
"grunt-eslint": "^19.0.0",
"grunt-exec": "~1.0.1",
"grunt-eslint": "^20.0.0",
"grunt-exec": "~3.0.0",
"grunt-execute": "^0.2.2",
"grunt-jsdoc": "^2.1.0",
"grunt-webpack": "^2.0.1",
"html-webpack-plugin": "^2.28.0",
"grunt-webpack": "^3.0.2",
"html-webpack-plugin": "^2.30.1",
"imports-loader": "^0.7.1",
"ink-docstrap": "^1.1.4",
"jsdoc-babel": "^0.3.0",
"less": "^2.7.2",
"less-loader": "^4.0.2",
"style-loader": "^0.15.0",
"less-loader": "^4.0.5",
"postcss-css-variables": "^0.7.0",
"postcss-import": "^10.0.0",
"postcss-loader": "^2.0.5",
"style-loader": "^0.18.2",
"url-loader": "^0.5.8",
"web-resource-inliner": "^4.1.0",
"webpack": "^2.2.1"
"webpack": "^3.4.1",
"webpack-node-externals": "^1.6.0"
},
"dependencies": {
"babel-polyfill": "^6.23.0",
"bootstrap": "^3.3.7",
"bootstrap-colorpicker": "^2.5.1",
"bootstrap-switch": "^3.3.4",
"crypto-api": "^0.6.2",
"crypto-js": "^3.1.9-1",
"diff": "^3.2.0",
"diff": "^3.3.0",
"escodegen": "^1.8.1",
"esmangle": "^1.0.1",
"esprima": "^3.1.3",
"esprima": "^4.0.0",
"exif-parser": "^0.1.12",
"google-code-prettify": "^1.0.5",
"jquery": "^3.1.1",
"jsbn": "^1.1.0",
"jsrsasign": "^7.1.0",
"jsonpath": "^0.2.12",
"jsrsasign": "8.0.3",
"lodash": "^4.17.4",
"moment": "^2.17.1",
"moment-timezone": "^0.5.11",
"sladex-blowfish": "^0.8.1",
"sortablejs": "^1.5.1",
"split.js": "^1.2.0",
"vkbeautify": "^0.99.1",
"vkbeautify": "^0.99.3",
"xmldom": "^0.1.27",
"xpath": "0.0.24",
"zlibjs": "^0.2.0"
"zlibjs": "^0.3.1"
},
"scripts": {
"build": "grunt prod",

15
postcss.config.js Normal file
View File

@@ -0,0 +1,15 @@
module.exports = {
plugins: [
require("postcss-import"),
require("autoprefixer")({
browsers: [
"Chrome >= 40",
"Firefox >= 35",
"Edge >= 14"
]
}),
require("postcss-css-variables")({
preserve: true
}),
]
};

View File

@@ -11,7 +11,7 @@ import Recipe from "./Recipe.js";
*
* @class
*/
var Chef = function() {
const Chef = function() {
this.dish = new Dish();
};
@@ -34,8 +34,8 @@ var Chef = function() {
* @returns {number} response.duration - The number of ms it took to execute the recipe
* @returns {number} response.error - The error object thrown by a failed operation (false if no error)
*/
Chef.prototype.bake = function(inputText, recipeConfig, options, progress, step) {
var startTime = new Date().getTime(),
Chef.prototype.bake = async function(inputText, recipeConfig, options, progress, step) {
let startTime = new Date().getTime(),
recipe = new Recipe(recipeConfig),
containsFc = recipe.containsFlowControl(),
error = false;
@@ -72,7 +72,7 @@ Chef.prototype.bake = function(inputText, recipeConfig, options, progress, step)
}
try {
progress = recipe.execute(this.dish, progress);
progress = await recipe.execute(this.dish, progress);
} catch (err) {
// Return the error in the result so that everything else gets correctly updated
// rather than throwing it here and losing state info.
@@ -111,7 +111,7 @@ Chef.prototype.bake = function(inputText, recipeConfig, options, progress, step)
* @returns {number} The time it took to run the silent bake in milliseconds.
*/
Chef.prototype.silentBake = function(recipeConfig) {
var startTime = new Date().getTime(),
let startTime = new Date().getTime(),
recipe = new Recipe(recipeConfig),
dish = new Dish("", Dish.STRING);

View File

@@ -1,6 +1,5 @@
import Utils from "./Utils.js";
/**
* The data being operated on by each operation.
*
@@ -12,7 +11,7 @@ import Utils from "./Utils.js";
* @param {byteArray|string|number} value - The value of the input data.
* @param {number} type - The data type of value, see Dish enums.
*/
var Dish = function(value, type) {
const Dish = function(value, type) {
this.value = value || typeof value == "string" ? value : null;
this.type = type || Dish.BYTE_ARRAY;
};
@@ -105,7 +104,7 @@ Dish.prototype.set = function(value, type) {
this.type = type;
if (!this.valid()) {
var sample = Utils.truncate(JSON.stringify(this.value), 13);
const sample = Utils.truncate(JSON.stringify(this.value), 13);
throw "Data is not a valid " + Dish.enumLookup(type) + ": " + sample;
}
};
@@ -180,7 +179,7 @@ Dish.prototype.valid = function() {
}
// Check that every value is a number between 0 - 255
for (var i = 0; i < this.value.length; i++) {
for (let i = 0; i < this.value.length; i++) {
if (typeof this.value[i] != "number" ||
this.value[i] < 0 ||
this.value[i] > 255) {

View File

@@ -38,8 +38,8 @@ const FlowControl = {
* @param {Operation[]} state.opList - The list of operations in the recipe.
* @returns {Object} The updated state of the recipe.
*/
runFork: function(state) {
var opList = state.opList,
runFork: async function(state) {
let opList = state.opList,
inputType = opList[state.progress].inputType,
outputType = opList[state.progress].outputType,
input = state.dish.get(inputType),
@@ -48,14 +48,15 @@ const FlowControl = {
mergeDelim = ings[1],
ignoreErrors = ings[2],
subOpList = [],
inputs = [];
inputs = [],
i;
if (input)
inputs = input.split(splitDelim);
// Create subOpList for each tranche to operate on
// (all remaining operations unless we encounter a Merge)
for (var i = state.progress + 1; i < opList.length; i++) {
for (i = state.progress + 1; i < opList.length; i++) {
if (opList[i].name === "Merge" && !opList[i].isDisabled()) {
break;
} else {
@@ -63,7 +64,7 @@ const FlowControl = {
}
}
var recipe = new Recipe(),
let recipe = new Recipe(),
output = "",
progress = 0;
@@ -71,9 +72,9 @@ const FlowControl = {
// Run recipe over each tranche
for (i = 0; i < inputs.length; i++) {
var dish = new Dish(inputs[i], inputType);
const dish = new Dish(inputs[i], inputType);
try {
progress = recipe.execute(dish, 0);
progress = await recipe.execute(dish, 0);
} catch (err) {
if (!ignoreErrors) {
throw err;
@@ -127,7 +128,7 @@ const FlowControl = {
* @returns {Object} The updated state of the recipe.
*/
runJump: function(state) {
var ings = state.opList[state.progress].getIngValues(),
let ings = state.opList[state.progress].getIngValues(),
jumpNum = ings[0],
maxJumps = ings[1];
@@ -156,7 +157,7 @@ const FlowControl = {
* @returns {Object} The updated state of the recipe.
*/
runCondJump: function(state) {
var ings = state.opList[state.progress].getIngValues(),
let ings = state.opList[state.progress].getIngValues(),
dish = state.dish,
regexStr = ings[0],
jumpNum = ings[1],
@@ -193,6 +194,20 @@ const FlowControl = {
return state;
},
/**
* Comment operation.
*
* @param {Object} state - The current state of the recipe.
* @param {number} state.progress - The current position in the recipe.
* @param {Dish} state.dish - The Dish being operated on.
* @param {Operation[]} state.opList - The list of operations in the recipe.
* @returns {Object} The updated state of the recipe.
*/
runComment: function(state) {
return state;
},
};
export default FlowControl;

View File

@@ -11,7 +11,7 @@ import Utils from "./Utils.js";
* @class
* @param {Object} ingredientConfig
*/
var Ingredient = function(ingredientConfig) {
const Ingredient = function(ingredientConfig) {
this.name = "";
this.type = "";
this.value = null;
@@ -63,6 +63,8 @@ Ingredient.prototype.setValue = function(value) {
* @param {string} type - The name of the data type.
*/
Ingredient.prepare = function(data, type) {
let number;
switch (type) {
case "binaryString":
case "binaryShortString":
@@ -71,14 +73,14 @@ Ingredient.prepare = function(data, type) {
case "byteArray":
if (typeof data == "string") {
data = data.replace(/\s+/g, "");
return Utils.hexToByteArray(data);
return Utils.fromHex(data);
} else {
return data;
}
case "number":
var number = parseFloat(data);
number = parseFloat(data);
if (isNaN(number)) {
var sample = Utils.truncate(data.toString(), 10);
const sample = Utils.truncate(data.toString(), 10);
throw "Invalid ingredient value. Not a number: " + sample;
}
return number;

View File

@@ -13,7 +13,7 @@ import Ingredient from "./Ingredient.js";
* @param {string} operationName
* @param {Object} operationConfig
*/
var Operation = function(operationName, operationConfig) {
const Operation = function(operationName, operationConfig) {
this.name = operationName;
this.description = "";
this.inputType = -1;
@@ -46,9 +46,9 @@ Operation.prototype._parseConfig = function(operationConfig) {
this.highlightReverse = operationConfig.highlightReverse;
this.flowControl = operationConfig.flowControl;
for (var a = 0; a < operationConfig.args.length; a++) {
var ingredientConfig = operationConfig.args[a];
var ingredient = new Ingredient(ingredientConfig);
for (let a = 0; a < operationConfig.args.length; a++) {
const ingredientConfig = operationConfig.args[a];
const ingredient = new Ingredient(ingredientConfig);
this.addIngredient(ingredient);
}
};
@@ -60,13 +60,13 @@ Operation.prototype._parseConfig = function(operationConfig) {
* @returns {Object}
*/
Operation.prototype.getConfig = function() {
var ingredientConfig = [];
const ingredientConfig = [];
for (var o = 0; o < this.ingList.length; o++) {
for (let o = 0; o < this.ingList.length; o++) {
ingredientConfig.push(this.ingList[o].getConfig());
}
var operationConfig = {
const operationConfig = {
"op": this.name,
"args": ingredientConfig
};
@@ -91,7 +91,7 @@ Operation.prototype.addIngredient = function(ingredient) {
* @param {Object[]} ingValues
*/
Operation.prototype.setIngValues = function(ingValues) {
for (var i = 0; i < ingValues.length; i++) {
for (let i = 0; i < ingValues.length; i++) {
this.ingList[i].setValue(ingValues[i]);
}
};
@@ -103,8 +103,8 @@ Operation.prototype.setIngValues = function(ingValues) {
* @returns {Object[]}
*/
Operation.prototype.getIngValues = function() {
var ingValues = [];
for (var i = 0; i < this.ingList.length; i++) {
const ingValues = [];
for (let i = 0; i < this.ingList.length; i++) {
ingValues.push(this.ingList[i].value);
}
return ingValues;

View File

@@ -12,7 +12,7 @@ import OperationConfig from "./config/OperationConfig.js";
* @class
* @param {Object} recipeConfig
*/
var Recipe = function(recipeConfig) {
const Recipe = function(recipeConfig) {
this.opList = [];
if (recipeConfig) {
@@ -28,10 +28,10 @@ var Recipe = function(recipeConfig) {
* @param {Object} recipeConfig
*/
Recipe.prototype._parseConfig = function(recipeConfig) {
for (var c = 0; c < recipeConfig.length; c++) {
var operationName = recipeConfig[c].op;
var operationConfig = OperationConfig[operationName];
var operation = new Operation(operationName, operationConfig);
for (let c = 0; c < recipeConfig.length; c++) {
const operationName = recipeConfig[c].op;
const operationConfig = OperationConfig[operationName];
const operation = new Operation(operationName, operationConfig);
operation.setIngValues(recipeConfig[c].args);
operation.setBreakpoint(recipeConfig[c].breakpoint);
operation.setDisabled(recipeConfig[c].disabled);
@@ -46,9 +46,9 @@ Recipe.prototype._parseConfig = function(recipeConfig) {
* @returns {*}
*/
Recipe.prototype.getConfig = function() {
var recipeConfig = [];
const recipeConfig = [];
for (var o = 0; o < this.opList.length; o++) {
for (let o = 0; o < this.opList.length; o++) {
recipeConfig.push(this.opList[o].getConfig());
}
@@ -98,7 +98,7 @@ Recipe.prototype.setBreakpoint = function(position, value) {
* @param {number} pos
*/
Recipe.prototype.removeBreaksUpTo = function(pos) {
for (var i = 0; i < pos; i++) {
for (let i = 0; i < pos; i++) {
this.opList[i].setBreakpoint(false);
}
};
@@ -110,7 +110,7 @@ Recipe.prototype.removeBreaksUpTo = function(pos) {
* @returns {boolean}
*/
Recipe.prototype.containsFlowControl = function() {
for (var i = 0; i < this.opList.length; i++) {
for (let i = 0; i < this.opList.length; i++) {
if (this.opList[i].isFlowControl()) return true;
}
return false;
@@ -125,7 +125,7 @@ Recipe.prototype.containsFlowControl = function() {
* @returns (number}
*/
Recipe.prototype.lastOpIndex = function(startIndex) {
var i = startIndex + 1 || 0,
let i = startIndex + 1 || 0,
op;
for (; i < this.opList.length; i++) {
@@ -145,11 +145,11 @@ Recipe.prototype.lastOpIndex = function(startIndex) {
* @param {number} [startFrom=0] - The index of the Operation to start executing from
* @returns {number} - The final progress through the recipe
*/
Recipe.prototype.execute = function(dish, startFrom) {
Recipe.prototype.execute = async function(dish, startFrom) {
startFrom = startFrom || 0;
var op, input, output, numJumps = 0;
let op, input, output, numJumps = 0;
for (var i = startFrom; i < this.opList.length; i++) {
for (let i = startFrom; i < this.opList.length; i++) {
op = this.opList[i];
if (op.isDisabled()) {
continue;
@@ -163,22 +163,22 @@ Recipe.prototype.execute = function(dish, startFrom) {
if (op.isFlowControl()) {
// Package up the current state
var state = {
"progress" : i,
"dish" : dish,
"opList" : this.opList,
"numJumps" : numJumps
let state = {
"progress": i,
"dish": dish,
"opList": this.opList,
"numJumps": numJumps
};
state = op.run(state);
state = await op.run(state);
i = state.progress;
numJumps = state.numJumps;
} else {
output = op.run(input, op.getIngValues());
output = await op.run(input, op.getIngValues());
dish.set(output, op.outputType);
}
} catch (err) {
var e = typeof err == "string" ? { message: err } : err;
const e = typeof err == "string" ? { message: err } : err;
e.progress = i;
if (e.fileName) {
@@ -213,7 +213,7 @@ Recipe.prototype.toString = function() {
* @param {string} recipeStr
*/
Recipe.prototype.fromString = function(recipeStr) {
var recipeConfig = JSON.parse(recipeStr);
const recipeConfig = JSON.parse(recipeStr);
this._parseConfig(recipeConfig);
};

View File

@@ -23,6 +23,16 @@ const Utils = {
* Utils.chr(97);
*/
chr: function(o) {
// Detect astral symbols
// Thanks to @mathiasbynens for this solution
// https://mathiasbynens.be/notes/javascript-unicode
if (o > 0xffff) {
o -= 0x10000;
const high = String.fromCharCode(o >>> 10 & 0x3ff | 0xd800);
o = 0xdc00 | o & 0x3ff;
return high + String.fromCharCode(o);
}
return String.fromCharCode(o);
},
@@ -38,6 +48,18 @@ const Utils = {
* Utils.ord('a');
*/
ord: function(c) {
// Detect astral symbols
// Thanks to @mathiasbynens for this solution
// https://mathiasbynens.be/notes/javascript-unicode
if (c.length === 2) {
const high = c.charCodeAt(0);
const low = c.charCodeAt(1);
if (high >= 0xd800 && high < 0xdc00 &&
low >= 0xdc00 && low < 0xe000) {
return (high - 0xd800) * 0x400 + low - 0xdc00 + 0x10000;
}
}
return c.charCodeAt(0);
},
@@ -65,7 +87,7 @@ const Utils = {
*/
padLeft: function(str, max, chr) {
chr = chr || "0";
var startIndex = chr.length - (max - str.length);
let startIndex = chr.length - (max - str.length);
startIndex = startIndex < 0 ? 0 : startIndex;
return str.length < max ?
Utils.padLeft(chr.slice(startIndex, chr.length) + str, max, chr) : str;
@@ -119,7 +141,7 @@ const Utils = {
*/
padBytesRight: function(arr, numBytes, padByte) {
padByte = padByte || 0;
var paddedBytes = new Array(numBytes);
const paddedBytes = new Array(numBytes);
paddedBytes.fill(padByte);
Array.prototype.map.call(arr, function(b, i) {
@@ -216,8 +238,8 @@ const Utils = {
str = Utils.byteArrayToChars(Utils.strToByteArray(str));
}
var re = /[\0-\x08\x0B-\x0C\x0E-\x1F\x7F-\x9F\xAD\u0378\u0379\u037F-\u0383\u038B\u038D\u03A2\u0528-\u0530\u0557\u0558\u0560\u0588\u058B-\u058E\u0590\u05C8-\u05CF\u05EB-\u05EF\u05F5-\u0605\u061C\u061D\u06DD\u070E\u070F\u074B\u074C\u07B2-\u07BF\u07FB-\u07FF\u082E\u082F\u083F\u085C\u085D\u085F-\u089F\u08A1\u08AD-\u08E3\u08FF\u0978\u0980\u0984\u098D\u098E\u0991\u0992\u09A9\u09B1\u09B3-\u09B5\u09BA\u09BB\u09C5\u09C6\u09C9\u09CA\u09CF-\u09D6\u09D8-\u09DB\u09DE\u09E4\u09E5\u09FC-\u0A00\u0A04\u0A0B-\u0A0E\u0A11\u0A12\u0A29\u0A31\u0A34\u0A37\u0A3A\u0A3B\u0A3D\u0A43-\u0A46\u0A49\u0A4A\u0A4E-\u0A50\u0A52-\u0A58\u0A5D\u0A5F-\u0A65\u0A76-\u0A80\u0A84\u0A8E\u0A92\u0AA9\u0AB1\u0AB4\u0ABA\u0ABB\u0AC6\u0ACA\u0ACE\u0ACF\u0AD1-\u0ADF\u0AE4\u0AE5\u0AF2-\u0B00\u0B04\u0B0D\u0B0E\u0B11\u0B12\u0B29\u0B31\u0B34\u0B3A\u0B3B\u0B45\u0B46\u0B49\u0B4A\u0B4E-\u0B55\u0B58-\u0B5B\u0B5E\u0B64\u0B65\u0B78-\u0B81\u0B84\u0B8B-\u0B8D\u0B91\u0B96-\u0B98\u0B9B\u0B9D\u0BA0-\u0BA2\u0BA5-\u0BA7\u0BAB-\u0BAD\u0BBA-\u0BBD\u0BC3-\u0BC5\u0BC9\u0BCE\u0BCF\u0BD1-\u0BD6\u0BD8-\u0BE5\u0BFB-\u0C00\u0C04\u0C0D\u0C11\u0C29\u0C34\u0C3A-\u0C3C\u0C45\u0C49\u0C4E-\u0C54\u0C57\u0C5A-\u0C5F\u0C64\u0C65\u0C70-\u0C77\u0C80\u0C81\u0C84\u0C8D\u0C91\u0CA9\u0CB4\u0CBA\u0CBB\u0CC5\u0CC9\u0CCE-\u0CD4\u0CD7-\u0CDD\u0CDF\u0CE4\u0CE5\u0CF0\u0CF3-\u0D01\u0D04\u0D0D\u0D11\u0D3B\u0D3C\u0D45\u0D49\u0D4F-\u0D56\u0D58-\u0D5F\u0D64\u0D65\u0D76-\u0D78\u0D80\u0D81\u0D84\u0D97-\u0D99\u0DB2\u0DBC\u0DBE\u0DBF\u0DC7-\u0DC9\u0DCB-\u0DCE\u0DD5\u0DD7\u0DE0-\u0DF1\u0DF5-\u0E00\u0E3B-\u0E3E\u0E5C-\u0E80\u0E83\u0E85\u0E86\u0E89\u0E8B\u0E8C\u0E8E-\u0E93\u0E98\u0EA0\u0EA4\u0EA6\u0EA8\u0EA9\u0EAC\u0EBA\u0EBE\u0EBF\u0EC5\u0EC7\u0ECE\u0ECF\u0EDA\u0EDB\u0EE0-\u0EFF\u0F48\u0F6D-\u0F70\u0F98\u0FBD\u0FCD\u0FDB-\u0FFF\u10C6\u10C8-\u10CC\u10CE\u10CF\u1249\u124E\u124F\u1257\u1259\u125E\u125F\u1289\u128E\u128F\u12B1\u12B6\u12B7\u12BF\u12C1\u12C6\u12C7\u12D7\u1311\u1316\u1317\u135B\u135C\u137D-\u137F\u139A-\u139F\u13F5-\u13FF\u169D-\u169F\u16F1-\u16FF\u170D\u1715-\u171F\u1737-\u173F\u1754-\u175F\u176D\u1771\u1774-\u177F\u17DE\u17DF\u17EA-\u17EF\u17FA-\u17FF\u180F\u181A-\u181F\u1878-\u187F\u18AB-\u18AF\u18F6-\u18FF\u191D-\u191F\u192C-\u192F\u193C-\u193F\u1941-\u1943\u196E\u196F\u1975-\u197F\u19AC-\u19AF\u19CA-\u19CF\u19DB-\u19DD\u1A1C\u1A1D\u1A5F\u1A7D\u1A7E\u1A8A-\u1A8F\u1A9A-\u1A9F\u1AAE-\u1AFF\u1B4C-\u1B4F\u1B7D-\u1B7F\u1BF4-\u1BFB\u1C38-\u1C3A\u1C4A-\u1C4C\u1C80-\u1CBF\u1CC8-\u1CCF\u1CF7-\u1CFF\u1DE7-\u1DFB\u1F16\u1F17\u1F1E\u1F1F\u1F46\u1F47\u1F4E\u1F4F\u1F58\u1F5A\u1F5C\u1F5E\u1F7E\u1F7F\u1FB5\u1FC5\u1FD4\u1FD5\u1FDC\u1FF0\u1FF1\u1FF5\u1FFF\u200B-\u200F\u202A-\u202E\u2060-\u206F\u2072\u2073\u208F\u209D-\u209F\u20BB-\u20CF\u20F1-\u20FF\u218A-\u218F\u23F4-\u23FF\u2427-\u243F\u244B-\u245F\u2700\u2B4D-\u2B4F\u2B5A-\u2BFF\u2C2F\u2C5F\u2CF4-\u2CF8\u2D26\u2D28-\u2D2C\u2D2E\u2D2F\u2D68-\u2D6E\u2D71-\u2D7E\u2D97-\u2D9F\u2DA7\u2DAF\u2DB7\u2DBF\u2DC7\u2DCF\u2DD7\u2DDF\u2E3C-\u2E7F\u2E9A\u2EF4-\u2EFF\u2FD6-\u2FEF\u2FFC-\u2FFF\u3040\u3097\u3098\u3100-\u3104\u312E-\u3130\u318F\u31BB-\u31BF\u31E4-\u31EF\u321F\u32FF\u4DB6-\u4DBF\u9FCD-\u9FFF\uA48D-\uA48F\uA4C7-\uA4CF\uA62C-\uA63F\uA698-\uA69E\uA6F8-\uA6FF\uA78F\uA794-\uA79F\uA7AB-\uA7F7\uA82C-\uA82F\uA83A-\uA83F\uA878-\uA87F\uA8C5-\uA8CD\uA8DA-\uA8DF\uA8FC-\uA8FF\uA954-\uA95E\uA97D-\uA97F\uA9CE\uA9DA-\uA9DD\uA9E0-\uA9FF\uAA37-\uAA3F\uAA4E\uAA4F\uAA5A\uAA5B\uAA7C-\uAA7F\uAAC3-\uAADA\uAAF7-\uAB00\uAB07\uAB08\uAB0F\uAB10\uAB17-\uAB1F\uAB27\uAB2F-\uABBF\uABEE\uABEF\uABFA-\uABFF\uD7A4-\uD7AF\uD7C7-\uD7CA\uD7FC-\uF8FF\uFA6E\uFA6F\uFADA-\uFAFF\uFB07-\uFB12\uFB18-\uFB1C\uFB37\uFB3D\uFB3F\uFB42\uFB45\uFBC2-\uFBD2\uFD40-\uFD4F\uFD90\uFD91\uFDC8-\uFDEF\uFDFE\uFDFF\uFE1A-\uFE1F\uFE27-\uFE2F\uFE53\uFE67\uFE6C-\uFE6F\uFE75\uFEFD-\uFF00\uFFBF-\uFFC1\uFFC8\uFFC9\uFFD0\uFFD1\uFFD8\uFFD9\uFFDD-\uFFDF\uFFE7\uFFEF-\uFFFB\uFFFE\uFFFF]/g;
var wsRe = /[\x09-\x10\x0D\u2028\u2029]/g;
const re = /[\0-\x08\x0B-\x0C\x0E-\x1F\x7F-\x9F\xAD\u0378\u0379\u037F-\u0383\u038B\u038D\u03A2\u0528-\u0530\u0557\u0558\u0560\u0588\u058B-\u058E\u0590\u05C8-\u05CF\u05EB-\u05EF\u05F5-\u0605\u061C\u061D\u06DD\u070E\u070F\u074B\u074C\u07B2-\u07BF\u07FB-\u07FF\u082E\u082F\u083F\u085C\u085D\u085F-\u089F\u08A1\u08AD-\u08E3\u08FF\u0978\u0980\u0984\u098D\u098E\u0991\u0992\u09A9\u09B1\u09B3-\u09B5\u09BA\u09BB\u09C5\u09C6\u09C9\u09CA\u09CF-\u09D6\u09D8-\u09DB\u09DE\u09E4\u09E5\u09FC-\u0A00\u0A04\u0A0B-\u0A0E\u0A11\u0A12\u0A29\u0A31\u0A34\u0A37\u0A3A\u0A3B\u0A3D\u0A43-\u0A46\u0A49\u0A4A\u0A4E-\u0A50\u0A52-\u0A58\u0A5D\u0A5F-\u0A65\u0A76-\u0A80\u0A84\u0A8E\u0A92\u0AA9\u0AB1\u0AB4\u0ABA\u0ABB\u0AC6\u0ACA\u0ACE\u0ACF\u0AD1-\u0ADF\u0AE4\u0AE5\u0AF2-\u0B00\u0B04\u0B0D\u0B0E\u0B11\u0B12\u0B29\u0B31\u0B34\u0B3A\u0B3B\u0B45\u0B46\u0B49\u0B4A\u0B4E-\u0B55\u0B58-\u0B5B\u0B5E\u0B64\u0B65\u0B78-\u0B81\u0B84\u0B8B-\u0B8D\u0B91\u0B96-\u0B98\u0B9B\u0B9D\u0BA0-\u0BA2\u0BA5-\u0BA7\u0BAB-\u0BAD\u0BBA-\u0BBD\u0BC3-\u0BC5\u0BC9\u0BCE\u0BCF\u0BD1-\u0BD6\u0BD8-\u0BE5\u0BFB-\u0C00\u0C04\u0C0D\u0C11\u0C29\u0C34\u0C3A-\u0C3C\u0C45\u0C49\u0C4E-\u0C54\u0C57\u0C5A-\u0C5F\u0C64\u0C65\u0C70-\u0C77\u0C80\u0C81\u0C84\u0C8D\u0C91\u0CA9\u0CB4\u0CBA\u0CBB\u0CC5\u0CC9\u0CCE-\u0CD4\u0CD7-\u0CDD\u0CDF\u0CE4\u0CE5\u0CF0\u0CF3-\u0D01\u0D04\u0D0D\u0D11\u0D3B\u0D3C\u0D45\u0D49\u0D4F-\u0D56\u0D58-\u0D5F\u0D64\u0D65\u0D76-\u0D78\u0D80\u0D81\u0D84\u0D97-\u0D99\u0DB2\u0DBC\u0DBE\u0DBF\u0DC7-\u0DC9\u0DCB-\u0DCE\u0DD5\u0DD7\u0DE0-\u0DF1\u0DF5-\u0E00\u0E3B-\u0E3E\u0E5C-\u0E80\u0E83\u0E85\u0E86\u0E89\u0E8B\u0E8C\u0E8E-\u0E93\u0E98\u0EA0\u0EA4\u0EA6\u0EA8\u0EA9\u0EAC\u0EBA\u0EBE\u0EBF\u0EC5\u0EC7\u0ECE\u0ECF\u0EDA\u0EDB\u0EE0-\u0EFF\u0F48\u0F6D-\u0F70\u0F98\u0FBD\u0FCD\u0FDB-\u0FFF\u10C6\u10C8-\u10CC\u10CE\u10CF\u1249\u124E\u124F\u1257\u1259\u125E\u125F\u1289\u128E\u128F\u12B1\u12B6\u12B7\u12BF\u12C1\u12C6\u12C7\u12D7\u1311\u1316\u1317\u135B\u135C\u137D-\u137F\u139A-\u139F\u13F5-\u13FF\u169D-\u169F\u16F1-\u16FF\u170D\u1715-\u171F\u1737-\u173F\u1754-\u175F\u176D\u1771\u1774-\u177F\u17DE\u17DF\u17EA-\u17EF\u17FA-\u17FF\u180F\u181A-\u181F\u1878-\u187F\u18AB-\u18AF\u18F6-\u18FF\u191D-\u191F\u192C-\u192F\u193C-\u193F\u1941-\u1943\u196E\u196F\u1975-\u197F\u19AC-\u19AF\u19CA-\u19CF\u19DB-\u19DD\u1A1C\u1A1D\u1A5F\u1A7D\u1A7E\u1A8A-\u1A8F\u1A9A-\u1A9F\u1AAE-\u1AFF\u1B4C-\u1B4F\u1B7D-\u1B7F\u1BF4-\u1BFB\u1C38-\u1C3A\u1C4A-\u1C4C\u1C80-\u1CBF\u1CC8-\u1CCF\u1CF7-\u1CFF\u1DE7-\u1DFB\u1F16\u1F17\u1F1E\u1F1F\u1F46\u1F47\u1F4E\u1F4F\u1F58\u1F5A\u1F5C\u1F5E\u1F7E\u1F7F\u1FB5\u1FC5\u1FD4\u1FD5\u1FDC\u1FF0\u1FF1\u1FF5\u1FFF\u200B-\u200F\u202A-\u202E\u2060-\u206F\u2072\u2073\u208F\u209D-\u209F\u20BB-\u20CF\u20F1-\u20FF\u218A-\u218F\u23F4-\u23FF\u2427-\u243F\u244B-\u245F\u2700\u2B4D-\u2B4F\u2B5A-\u2BFF\u2C2F\u2C5F\u2CF4-\u2CF8\u2D26\u2D28-\u2D2C\u2D2E\u2D2F\u2D68-\u2D6E\u2D71-\u2D7E\u2D97-\u2D9F\u2DA7\u2DAF\u2DB7\u2DBF\u2DC7\u2DCF\u2DD7\u2DDF\u2E3C-\u2E7F\u2E9A\u2EF4-\u2EFF\u2FD6-\u2FEF\u2FFC-\u2FFF\u3040\u3097\u3098\u3100-\u3104\u312E-\u3130\u318F\u31BB-\u31BF\u31E4-\u31EF\u321F\u32FF\u4DB6-\u4DBF\u9FCD-\u9FFF\uA48D-\uA48F\uA4C7-\uA4CF\uA62C-\uA63F\uA698-\uA69E\uA6F8-\uA6FF\uA78F\uA794-\uA79F\uA7AB-\uA7F7\uA82C-\uA82F\uA83A-\uA83F\uA878-\uA87F\uA8C5-\uA8CD\uA8DA-\uA8DF\uA8FC-\uA8FF\uA954-\uA95E\uA97D-\uA97F\uA9CE\uA9DA-\uA9DD\uA9E0-\uA9FF\uAA37-\uAA3F\uAA4E\uAA4F\uAA5A\uAA5B\uAA7C-\uAA7F\uAAC3-\uAADA\uAAF7-\uAB00\uAB07\uAB08\uAB0F\uAB10\uAB17-\uAB1F\uAB27\uAB2F-\uABBF\uABEE\uABEF\uABFA-\uABFF\uD7A4-\uD7AF\uD7C7-\uD7CA\uD7FC-\uD7FF\uE000-\uF8FF\uFA6E\uFA6F\uFADA-\uFAFF\uFB07-\uFB12\uFB18-\uFB1C\uFB37\uFB3D\uFB3F\uFB42\uFB45\uFBC2-\uFBD2\uFD40-\uFD4F\uFD90\uFD91\uFDC8-\uFDEF\uFDFE\uFDFF\uFE1A-\uFE1F\uFE27-\uFE2F\uFE53\uFE67\uFE6C-\uFE6F\uFE75\uFEFD-\uFF00\uFFBF-\uFFC1\uFFC8\uFFC9\uFFD0\uFFD1\uFFD8\uFFD9\uFFDD-\uFFDF\uFFE7\uFFEF-\uFFFB\uFFFE\uFFFF]/g;
const wsRe = /[\x09-\x10\x0D\u2028\u2029]/g;
str = str.replace(re, ".");
if (!preserveWs) str = str.replace(wsRe, ".");
@@ -259,6 +281,22 @@ const Utils = {
},
/**
* Escape a string containing regex control characters so that it can be safely
* used in a regex without causing unintended behaviours.
*
* @param {string} str
* @returns {string}
*
* @example
* // returns "\[example\]"
* Utils.escapeRegex("[example]");
*/
escapeRegex: function(str) {
return str.replace(/([.*+?^=!:${}()|[\]/\\])/g, "\\$1");
},
/**
* Expand an alphabet range string into a list of the characters in that range.
*
@@ -276,16 +314,16 @@ const Utils = {
* Utils.expandAlphRange("a-d0\\-3")
*/
expandAlphRange: function(alphStr) {
var alphArr = [];
const alphArr = [];
for (var i = 0; i < alphStr.length; i++) {
for (let i = 0; i < alphStr.length; i++) {
if (i < alphStr.length - 2 &&
alphStr[i+1] === "-" &&
alphStr[i] !== "\\") {
var start = Utils.ord(alphStr[i]),
let start = Utils.ord(alphStr[i]),
end = Utils.ord(alphStr[i+2]);
for (var j = start; j <= end; j++) {
for (let j = start; j <= end; j++) {
alphArr.push(Utils.chr(j));
}
i += 2;
@@ -302,48 +340,6 @@ const Utils = {
},
/**
* Translates a hex string into an array of bytes.
*
* @param {string} hexStr
* @returns {byteArray}
*
* @example
* // returns [0xfe, 0x09, 0xa7]
* Utils.hexToByteArray("fe09a7");
*/
hexToByteArray: function(hexStr) {
// TODO: Handle errors i.e. input string is not hex
if (!hexStr) return [];
hexStr = hexStr.replace(/\s+/g, "");
var byteArray = [];
for (var i = 0; i < hexStr.length; i += 2) {
byteArray.push(parseInt(hexStr.substr(i, 2), 16));
}
return byteArray;
},
/**
* Translates an array of bytes to a hex string.
*
* @param {byteArray} byteArray
* @returns {string}
*
* @example
* // returns "fe09a7"
* Utils.byteArrayToHex([0xfe, 0x09, 0xa7]);
*/
byteArrayToHex: function(byteArray) {
if (!byteArray) return "";
var hexStr = "";
for (var i = 0; i < byteArray.length; i++) {
hexStr += Utils.hex(byteArray[i]) + " ";
}
return hexStr.slice(0, hexStr.length-1);
},
/**
* Converts a string to a byte array.
* Treats the string as UTF-8 if any values are over 255.
@@ -359,8 +355,8 @@ const Utils = {
* Utils.strToByteArray("你好");
*/
strToByteArray: function(str) {
var byteArray = new Array(str.length);
var i = str.length, b;
const byteArray = new Array(str.length);
let i = str.length, b;
while (i--) {
b = str.charCodeAt(i);
byteArray[i] = b;
@@ -385,7 +381,7 @@ const Utils = {
* Utils.strToUtf8ByteArray("你好");
*/
strToUtf8ByteArray: function(str) {
var wordArray = CryptoJS.enc.Utf8.parse(str),
let wordArray = CryptoJS.enc.Utf8.parse(str),
byteArray = Utils.wordArrayToByteArray(wordArray);
if (typeof window !== "undefined" && str.length !== wordArray.sigBytes) {
@@ -396,7 +392,7 @@ const Utils = {
/**
* Converts a string to a charcode array
* Converts a string to a unicode charcode array
*
* @param {string} str
* @returns {byteArray}
@@ -409,12 +405,23 @@ const Utils = {
* Utils.strToCharcode("你好");
*/
strToCharcode: function(str) {
var byteArray = new Array(str.length);
var i = str.length;
while (i--) {
byteArray[i] = str.charCodeAt(i);
const charcode = new Array();
for (let i = 0; i < str.length; i++) {
let ord = str.charCodeAt(i);
// Detect and merge astral symbols
if (i < str.length - 1 && ord >= 0xd800 && ord < 0xdc00) {
const low = str[i + 1].charCodeAt(0);
if (low >= 0xdc00 && low < 0xe000) {
ord = Utils.ord(str[i] + str[++i]);
}
}
charcode.push(ord);
}
return byteArray;
return charcode;
},
@@ -434,11 +441,11 @@ const Utils = {
byteArrayToUtf8: function(byteArray) {
try {
// Try to output data as UTF-8 string
var words = [];
for (var i = 0; i < byteArray.length; i++) {
const words = [];
for (let i = 0; i < byteArray.length; i++) {
words[i >>> 2] |= byteArray[i] << (24 - (i % 4) * 8);
}
var wordArray = new CryptoJS.lib.WordArray.init(words, byteArray.length),
let wordArray = new CryptoJS.lib.WordArray.init(words, byteArray.length),
str = CryptoJS.enc.Utf8.stringify(wordArray);
if (typeof window !== "undefined" && str.length !== wordArray.sigBytes)
@@ -466,8 +473,8 @@ const Utils = {
*/
byteArrayToChars: function(byteArray) {
if (!byteArray) return "";
var str = "";
for (var i = 0; i < byteArray.length;) {
let str = "";
for (let i = 0; i < byteArray.length;) {
str += String.fromCharCode(byteArray[i++]);
}
return str;
@@ -487,10 +494,10 @@ const Utils = {
wordArrayToByteArray: function(wordArray) {
if (wordArray.sigBytes <= 0) return [];
var words = wordArray.words,
let words = wordArray.words,
byteArray = [];
for (var i = 0; i < wordArray.sigBytes; i++) {
for (let i = 0; i < wordArray.sigBytes; i++) {
byteArray.push((words[i >>> 2] >>> (24 - (i % 4) * 8)) & 0xff);
}
@@ -498,127 +505,6 @@ const Utils = {
},
/**
* Mapping of Unicode code points to Windows-1251
* @private
* @constant
*/
UNIC_WIN1251_MAP: {
0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10, 11: 11, 12: 12, 13: 13,
14: 14, 15: 15, 16: 16, 17: 17, 18: 18, 19: 19, 20: 20, 21: 21, 22: 22, 23: 23, 24: 24,
25: 25, 26: 26, 27: 27, 28: 28, 29: 29, 30: 30, 31: 31, 32: 32, 33: 33, 34: 34, 35: 35,
36: 36, 37: 37, 38: 38, 39: 39, 40: 40, 41: 41, 42: 42, 43: 43, 44: 44, 45: 45, 46: 46,
47: 47, 48: 48, 49: 49, 50: 50, 51: 51, 52: 52, 53: 53, 54: 54, 55: 55, 56: 56, 57: 57,
58: 58, 59: 59, 60: 60, 61: 61, 62: 62, 63: 63, 64: 64, 65: 65, 66: 66, 67: 67, 68: 68,
69: 69, 70: 70, 71: 71, 72: 72, 73: 73, 74: 74, 75: 75, 76: 76, 77: 77, 78: 78, 79: 79,
80: 80, 81: 81, 82: 82, 83: 83, 84: 84, 85: 85, 86: 86, 87: 87, 88: 88, 89: 89, 90: 90,
91: 91, 92: 92, 93: 93, 94: 94, 95: 95, 96: 96, 97: 97, 98: 98, 99: 99, 100: 100, 101: 101,
102: 102, 103: 103, 104: 104, 105: 105, 106: 106, 107: 107, 108: 108, 109: 109, 110: 110,
111: 111, 112: 112, 113: 113, 114: 114, 115: 115, 116: 116, 117: 117, 118: 118, 119: 119,
120: 120, 121: 121, 122: 122, 123: 123, 124: 124, 125: 125, 126: 126, 127: 127, 1027: 129,
8225: 135, 1046: 198, 8222: 132, 1047: 199, 1168: 165, 1048: 200, 1113: 154, 1049: 201,
1045: 197, 1050: 202, 1028: 170, 160: 160, 1040: 192, 1051: 203, 164: 164, 166: 166,
167: 167, 169: 169, 171: 171, 172: 172, 173: 173, 174: 174, 1053: 205, 176: 176, 177: 177,
1114: 156, 181: 181, 182: 182, 183: 183, 8221: 148, 187: 187, 1029: 189, 1056: 208,
1057: 209, 1058: 210, 8364: 136, 1112: 188, 1115: 158, 1059: 211, 1060: 212, 1030: 178,
1061: 213, 1062: 214, 1063: 215, 1116: 157, 1064: 216, 1065: 217, 1031: 175, 1066: 218,
1067: 219, 1068: 220, 1069: 221, 1070: 222, 1032: 163, 8226: 149, 1071: 223, 1072: 224,
8482: 153, 1073: 225, 8240: 137, 1118: 162, 1074: 226, 1110: 179, 8230: 133, 1075: 227,
1033: 138, 1076: 228, 1077: 229, 8211: 150, 1078: 230, 1119: 159, 1079: 231, 1042: 194,
1080: 232, 1034: 140, 1025: 168, 1081: 233, 1082: 234, 8212: 151, 1083: 235, 1169: 180,
1084: 236, 1052: 204, 1085: 237, 1035: 142, 1086: 238, 1087: 239, 1088: 240, 1089: 241,
1090: 242, 1036: 141, 1041: 193, 1091: 243, 1092: 244, 8224: 134, 1093: 245, 8470: 185,
1094: 246, 1054: 206, 1095: 247, 1096: 248, 8249: 139, 1097: 249, 1098: 250, 1044: 196,
1099: 251, 1111: 191, 1055: 207, 1100: 252, 1038: 161, 8220: 147, 1101: 253, 8250: 155,
1102: 254, 8216: 145, 1103: 255, 1043: 195, 1105: 184, 1039: 143, 1026: 128, 1106: 144,
8218: 130, 1107: 131, 8217: 146, 1108: 186, 1109: 190
},
/**
* Mapping of Windows-1251 code points to Unicode
* @private
* @constant
*/
WIN1251_UNIC_MAP: {
0: 0, 1: 1, 2: 2, 3: 3, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 9, 10: 10, 11: 11, 12: 12, 13: 13,
14: 14, 15: 15, 16: 16, 17: 17, 18: 18, 19: 19, 20: 20, 21: 21, 22: 22, 23: 23, 24: 24,
25: 25, 26: 26, 27: 27, 28: 28, 29: 29, 30: 30, 31: 31, 32: 32, 33: 33, 34: 34, 35: 35,
36: 36, 37: 37, 38: 38, 39: 39, 40: 40, 41: 41, 42: 42, 43: 43, 44: 44, 45: 45, 46: 46,
47: 47, 48: 48, 49: 49, 50: 50, 51: 51, 52: 52, 53: 53, 54: 54, 55: 55, 56: 56, 57: 57,
58: 58, 59: 59, 60: 60, 61: 61, 62: 62, 63: 63, 64: 64, 65: 65, 66: 66, 67: 67, 68: 68,
69: 69, 70: 70, 71: 71, 72: 72, 73: 73, 74: 74, 75: 75, 76: 76, 77: 77, 78: 78, 79: 79,
80: 80, 81: 81, 82: 82, 83: 83, 84: 84, 85: 85, 86: 86, 87: 87, 88: 88, 89: 89, 90: 90,
91: 91, 92: 92, 93: 93, 94: 94, 95: 95, 96: 96, 97: 97, 98: 98, 99: 99, 100: 100, 101: 101,
102: 102, 103: 103, 104: 104, 105: 105, 106: 106, 107: 107, 108: 108, 109: 109, 110: 110,
111: 111, 112: 112, 113: 113, 114: 114, 115: 115, 116: 116, 117: 117, 118: 118, 119: 119,
120: 120, 121: 121, 122: 122, 123: 123, 124: 124, 125: 125, 126: 126, 127: 127, 160: 160,
164: 164, 166: 166, 167: 167, 169: 169, 171: 171, 172: 172, 173: 173, 174: 174, 176: 176,
177: 177, 181: 181, 182: 182, 183: 183, 187: 187, 168: 1025, 128: 1026, 129: 1027,
170: 1028, 189: 1029, 178: 1030, 175: 1031, 163: 1032, 138: 1033, 140: 1034, 142: 1035,
141: 1036, 161: 1038, 143: 1039, 192: 1040, 193: 1041, 194: 1042, 195: 1043, 196: 1044,
197: 1045, 198: 1046, 199: 1047, 200: 1048, 201: 1049, 202: 1050, 203: 1051, 204: 1052,
205: 1053, 206: 1054, 207: 1055, 208: 1056, 209: 1057, 210: 1058, 211: 1059, 212: 1060,
213: 1061, 214: 1062, 215: 1063, 216: 1064, 217: 1065, 218: 1066, 219: 1067, 220: 1068,
221: 1069, 222: 1070, 223: 1071, 224: 1072, 225: 1073, 226: 1074, 227: 1075, 228: 1076,
229: 1077, 230: 1078, 231: 1079, 232: 1080, 233: 1081, 234: 1082, 235: 1083, 236: 1084,
237: 1085, 238: 1086, 239: 1087, 240: 1088, 241: 1089, 242: 1090, 243: 1091, 244: 1092,
245: 1093, 246: 1094, 247: 1095, 248: 1096, 249: 1097, 250: 1098, 251: 1099, 252: 1100,
253: 1101, 254: 1102, 255: 1103, 184: 1105, 144: 1106, 131: 1107, 186: 1108, 190: 1109,
179: 1110, 191: 1111, 188: 1112, 154: 1113, 156: 1114, 158: 1115, 157: 1116, 162: 1118,
159: 1119, 165: 1168, 180: 1169, 150: 8211, 151: 8212, 145: 8216, 146: 8217, 130: 8218,
147: 8220, 148: 8221, 132: 8222, 134: 8224, 135: 8225, 149: 8226, 133: 8230, 137: 8240,
139: 8249, 155: 8250, 136: 8364, 185: 8470, 153: 8482
},
/**
* Converts a Unicode string to Windows-1251 encoding
*
* @param {string} unicStr
* @returns {string} String encoded in Windows-1251
*
* @example
* // returns "îáíîâëåííàÿ òåõíè÷êà ïî Áîèíãó. îðèãèíàë ó ìåíÿ. çàáåðåòå êîãäà áóäåòå â ÊÈ"
* Utils.unicodeToWin1251("обновленная техничка по Боингу. оригинал у меня. заберете когда будете в КИ");
*/
unicodeToWin1251: function(unicStr) {
var res = [];
for (var i = 0; i < unicStr.length; i++) {
var ord = unicStr.charCodeAt(i);
if (!(ord in Utils.UNIC_WIN1251_MAP))
throw "Character '" + unicStr.charAt(i) + "' isn't supported by Windows-1251";
res.push(String.fromCharCode(Utils.UNIC_WIN1251_MAP[ord]));
}
return res.join("");
},
/**
* Converts a Windows-1251 string to Unicode encoding
*
* @param {string} win1251Str
* @returns {string} String encoded in Unicode
*
* @example
* // returns "обновленная техничка по Боингу. оригинал у меня. заберете когда будете в КИ"
* Utils.unicodeToWin1251("îáíîâëåííàÿ òåõíè÷êà ïî Áîèíãó. îðèãèíàë ó ìåíÿ. çàáåðåòå êîãäà áóäåòå â ÊÈ");
*/
win1251ToUnicode: function(win1251Str) {
var res = [];
for (var i = 0; i < win1251Str.length; i++) {
var ord = win1251Str.charCodeAt(i);
if (!(ord in Utils.WIN1251_UNIC_MAP))
throw "Character '" + win1251Str.charAt(i) + "' isn't supported by Windows-1251";
res.push(String.fromCharCode(Utils.WIN1251_UNIC_MAP[ord]));
}
return res.join("");
},
/**
* Base64's the input byte array using the given alphabet, returning a string.
*
@@ -642,7 +528,7 @@ const Utils = {
alphabet = alphabet ?
Utils.expandAlphRange(alphabet).join("") :
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
var output = "",
let output = "",
chr1, chr2, chr3,
enc1, enc2, enc3, enc4,
i = 0;
@@ -700,13 +586,13 @@ const Utils = {
if (removeNonAlphChars === undefined)
removeNonAlphChars = true;
var output = [],
let output = [],
chr1, chr2, chr3,
enc1, enc2, enc3, enc4,
i = 0;
if (removeNonAlphChars) {
var re = new RegExp("[^" + alphabet.replace(/[\[\]\\\-^$]/g, "\\$&") + "]", "g");
const re = new RegExp("[^" + alphabet.replace(/[[\]\\\-^$]/g, "\\$&") + "]", "g");
data = data.replace(re, "");
}
@@ -758,9 +644,9 @@ const Utils = {
delim = typeof delim == "string" ? delim : " ";
padding = padding || 2;
var output = "";
let output = "";
for (var i = 0; i < data.length; i++) {
for (let i = 0; i < data.length; i++) {
output += Utils.pad(data[i].toString(16), padding) + delim;
}
@@ -788,9 +674,9 @@ const Utils = {
toHexFast: function(data) {
if (!data) return "";
var output = [];
const output = [];
for (var i = 0; i < data.length; i++) {
for (let i = 0; i < data.length; i++) {
output.push((data[i] >>> 4).toString(16));
output.push((data[i] & 0x0f).toString(16));
}
@@ -818,12 +704,12 @@ const Utils = {
delim = delim || (data.indexOf(" ") >= 0 ? "Space" : "None");
byteLen = byteLen || 2;
if (delim !== "None") {
var delimRegex = Utils.regexRep[delim];
const delimRegex = Utils.regexRep[delim];
data = data.replace(delimRegex, "");
}
var output = [];
for (var i = 0; i < data.length; i += byteLen) {
const output = [];
for (let i = 0; i < data.length; i += byteLen) {
output.push(parseInt(data.substr(i, byteLen), 16));
}
return output;
@@ -842,14 +728,14 @@ const Utils = {
*/
parseCSV: function(data) {
var b,
let b,
ignoreNext = false,
inString = false,
cell = "",
line = [],
lines = [];
for (var i = 0; i < data.length; i++) {
for (let i = 0; i < data.length; i++) {
b = data[i];
if (ignoreNext) {
cell += b;
@@ -898,7 +784,7 @@ const Utils = {
if (removeScriptAndStyle) {
htmlStr = htmlStr.replace(/<(script|style)[^>]*>.*<\/(script|style)>/gmi, "");
}
return htmlStr.replace(/<[^>\n]+>/g, "");
return htmlStr.replace(/<[^>]+>/g, "");
},
@@ -914,7 +800,7 @@ const Utils = {
* Utils.escapeHtml("A <script> tag");
*/
escapeHtml: function(str) {
var HTML_CHARS = {
const HTML_CHARS = {
"&": "&amp;",
"<": "&lt;",
">": "&gt;",
@@ -924,7 +810,7 @@ const Utils = {
"`": "&#x60;"
};
return str.replace(/[&<>"'\/`]/g, function (match) {
return str.replace(/[&<>"'/`]/g, function (match) {
return HTML_CHARS[match];
});
},
@@ -941,7 +827,7 @@ const Utils = {
* Utils.unescapeHtml("A &lt;script&gt; tag");
*/
unescapeHtml: function(str) {
var HTML_CHARS = {
const HTML_CHARS = {
"&amp;": "&",
"&lt;": "<",
"&gt;": ">",
@@ -957,6 +843,139 @@ const Utils = {
},
/**
* Encodes a URI fragment (#) or query (?) using a minimal amount of percent-encoding.
*
* RFC 3986 defines legal characters for the fragment and query parts of a URL to be as follows:
*
* fragment = *( pchar / "/" / "?" )
* query = *( pchar / "/" / "?" )
* pchar = unreserved / pct-encoded / sub-delims / ":" / "@"
* unreserved = ALPHA / DIGIT / "-" / "." / "_" / "~"
* pct-encoded = "%" HEXDIG HEXDIG
* sub-delims = "!" / "$" / "&" / "'" / "(" / ")"
* / "*" / "+" / "," / ";" / "="
*
* Meaning that the list of characters that need not be percent-encoded are alphanumeric plus:
* -._~!$&'()*+,;=:@/?
*
* & and = are still escaped as they are used to serialise the key-value pairs in CyberChef
* fragments. + is also escaped so as to prevent it being decoded to a space.
*
* @param {string} str
* @returns {string}
*/
encodeURIFragment: function(str) {
const LEGAL_CHARS = {
"%2D": "-",
"%2E": ".",
"%5F": "_",
"%7E": "~",
"%21": "!",
"%24": "$",
//"%26": "&",
"%27": "'",
"%28": "(",
"%29": ")",
"%2A": "*",
//"%2B": "+",
"%2C": ",",
"%3B": ";",
//"%3D": "=",
"%3A": ":",
"%40": "@",
"%2F": "/",
"%3F": "?"
};
str = encodeURIComponent(str);
return str.replace(/%[0-9A-F]{2}/g, function (match) {
return LEGAL_CHARS[match] || match;
});
},
/**
* Generates a "pretty" recipe format from a recipeConfig object.
*
* "Pretty" CyberChef recipe formats are designed to be included in the fragment (#) or query (?)
* parts of the URL. They can also be loaded into CyberChef through the 'Load' interface. In order
* to make this format as readable as possible, various special characters are used unescaped. This
* reduces the amount of percent-encoding included in the URL which is typically difficult to read,
* as well as substantially increasing the overall length. These characteristics can be quite
* offputting for users.
*
* @param {Object[]} recipeConfig
* @param {boolean} newline - whether to add a newline after each operation
* @returns {string}
*/
generatePrettyRecipe: function(recipeConfig, newline) {
let prettyConfig = "",
name = "",
args = "",
disabled = "",
bp = "";
recipeConfig.forEach(op => {
name = op.op.replace(/ /g, "_");
args = JSON.stringify(op.args)
.slice(1, -1) // Remove [ and ] as they are implied
// We now need to switch double-quoted (") strings to single-quotes (') as these do not
// need to be percent-encoded.
.replace(/'/g, "\\'") // Escape single quotes
.replace(/\\"/g, '"') // Unescape double quotes
.replace(/(^|,|{|:)"/g, "$1'") // Replace opening " with '
.replace(/"(,|:|}|$)/g, "'$1"); // Replace closing " with '
disabled = op.disabled ? "/disabled": "";
bp = op.breakpoint ? "/breakpoint" : "";
prettyConfig += `${name}(${args}${disabled}${bp})`;
if (newline) prettyConfig += "\n";
});
return prettyConfig;
},
/**
* Converts a recipe string to the JSON representation of the recipe.
* Accepts either stringified JSON or bespoke "pretty" recipe format.
*
* @param {string} recipe
* @returns {Object[]}
*/
parseRecipeConfig: function(recipe) {
recipe = recipe.trim();
if (recipe.length === 0) return [];
if (recipe[0] === "[") return JSON.parse(recipe);
// Parse bespoke recipe format
recipe = recipe.replace(/\n/g, "");
let m,
recipeRegex = /([^(]+)\(((?:'[^'\\]*(?:\\.[^'\\]*)*'|[^)/])*)(\/[^)]+)?\)/g,
recipeConfig = [],
args;
while ((m = recipeRegex.exec(recipe))) {
// Translate strings in args back to double-quotes
args = m[2]
.replace(/"/g, '\\"') // Escape double quotes
.replace(/(^|,|{|:)'/g, '$1"') // Replace opening ' with "
.replace(/([^\\])'(,|:|}|$)/g, '$1"$2') // Replace closing ' with "
.replace(/\\'/g, "'"); // Unescape single quotes
args = "[" + args + "]";
let op = {
op: m[1].replace(/_/g, " "),
args: JSON.parse(args)
};
if (m[3] && m[3].indexOf("disabled") > 0) op.disabled = true;
if (m[3] && m[3].indexOf("breakpoint") > 0) op.breakpoint = true;
recipeConfig.push(op);
}
return recipeConfig;
},
/**
* Expresses a number of milliseconds in a human readable format.
*
@@ -997,7 +1016,7 @@ const Utils = {
* @returns {Object}
*/
extend: function(a, b){
for (var key in b)
for (const key in b)
if (b.hasOwnProperty(key))
a[key] = b[key];
return a;
@@ -1015,66 +1034,76 @@ const Utils = {
* @param {Object[]} files
* @returns {html}
*/
displayFilesAsHTML: function(files){
var formatDirectory = function(file) {
var html = "<div class='panel panel-default'>" +
"<div class='panel-heading' role='tab'>" +
"<h4 class='panel-title'>" +
file.fileName +
// The following line is for formatting when HTML is stripped
"<span style='display: none'>\n0 bytes\n</span>" +
"</h4>" +
"</div>" +
"</div>";
displayFilesAsHTML: function(files) {
/* <NL> and <SP> used to denote newlines and spaces in HTML markup.
* If a non-html operation is used, all markup will be removed but these
* whitespace chars will remain for formatting purposes.
*/
const formatDirectory = function(file) {
const html = `<div class='panel panel-default' style='white-space: normal;'>
<div class='panel-heading' role='tab'>
<h4 class='panel-title'>
<NL>${Utils.escapeHtml(file.fileName)}
</h4>
</div>
</div>`;
return html;
};
var formatFile = function(file, i) {
var blob = new Blob(
const formatFile = function(file, i) {
const blob = new Blob(
[new Uint8Array(file.bytes)],
{type: "octet/stream"}
);
var blobUrl = URL.createObjectURL(blob);
const blobUrl = URL.createObjectURL(blob);
var downloadAnchorElem = "<a href='" + blobUrl + "' " +
"title='Download " + Utils.escapeHtml(file.fileName) + "' " +
"download='" + Utils.escapeHtml(file.fileName) + "'>\u21B4</a>";
const viewFileElem = `<a href='#collapse${i}'
class='collapsed'
data-toggle='collapse'
aria-expanded='true'
aria-controls='collapse${i}'
title="Show/hide contents of '${Utils.escapeHtml(file.fileName)}'">&#x1f441;&#xfe0f;</a>`;
var expandFileContentsElem = "<a href='#collapse" + i + "' " +
"class='collapsed' " +
"data-toggle='collapse' " +
"aria-expanded='true' " +
"aria-controls='collapse" + i + "' " +
"title=\"Show/hide contents of '" + Utils.escapeHtml(file.fileName) + "'\">&#x1F50D</a>";
const downloadFileElem = `<a href='${blobUrl}'
title='Download ${Utils.escapeHtml(file.fileName)}'
download='${Utils.escapeHtml(file.fileName)}'>&#x1f4be;</a>`;
var html = "<div class='panel panel-default'>" +
"<div class='panel-heading' role='tab' id='heading" + i + "'>" +
"<h4 class='panel-title'>" +
"<div>" +
Utils.escapeHtml(file.fileName) +
" " + expandFileContentsElem +
" " + downloadAnchorElem +
"<span class='pull-right'>" +
// These are for formatting when stripping HTML
"<span style='display: none'>\n</span>" +
file.size.toLocaleString() + " bytes" +
"<span style='display: none'>\n</span>" +
"</span>" +
"</div>" +
"</h4>" +
"</div>" +
"<div id='collapse" + i + "' class='panel-collapse collapse' " +
"role='tabpanel' aria-labelledby='heading" + i + "'>" +
"<div class='panel-body'>" +
"<pre><code>" + Utils.escapeHtml(file.contents) + "</pre></code></div>" +
"</div>" +
"</div>";
const hexFileData = Utils.toHexFast(new Uint8Array(file.bytes));
const switchToInputElem = `<a href='#switchFileToInput${i}'
class='file-switch'
title='Move file to input as hex'
fileValue='${hexFileData}'>&#x21e7;</a>`;
const html = `<div class='panel panel-default' style='white-space: normal;'>
<div class='panel-heading' role='tab' id='heading${i}'>
<h4 class='panel-title'>
<div>
${Utils.escapeHtml(file.fileName)}<NL>
${viewFileElem}<SP>
${downloadFileElem}<SP>
${switchToInputElem}<SP>
<span class='pull-right'>
<NL>${file.size.toLocaleString()} bytes
</span>
</div>
</h4>
</div>
<div id='collapse${i}' class='panel-collapse collapse'
role='tabpanel' aria-labelledby='heading${i}'>
<div class='panel-body'>
<NL><NL><pre><code>${Utils.escapeHtml(file.contents)}</code></pre>
</div>
</div>
</div>`;
return html;
};
var html = "<div style='padding: 5px;'>" +
files.length +
" file(s) found</div>\n";
let html = `<div style='padding: 5px; white-space: normal;'>
${files.length} file(s) found<NL>
</div>`;
files.forEach(function(file, i) {
if (typeof file.contents !== "undefined") {
html += formatFile(file, i);
@@ -1082,14 +1111,53 @@ const Utils = {
html += formatDirectory(file);
}
});
return html;
return html.replace(/(?:(<pre>(?:\n|.)*<\/pre>)|\s{2,})/g, "$1") // Remove whitespace from markup
.replace(/<NL>/g, "\n") // Replace <NP> with newlines
.replace(/<SP>/g, " "); // Replace <SP> with spaces
},
/**
* Parses URI parameters into a JSON object.
*
* @param {string} paramStr - The serialised query or hash section of a URI
* @returns {object}
*
* @example
* // returns {a: 'abc', b: '123'}
* Utils.parseURIParams("?a=abc&b=123")
* Utils.parseURIParams("#a=abc&b=123")
*/
parseURIParams: function(paramStr) {
if (paramStr === "") return {};
// Cut off ? or # and split on &
if (paramStr[0] === "?" ||
paramStr[0] === "#") {
paramStr = paramStr.substr(1);
}
const params = paramStr.split("&");
const result = {};
for (let i = 0; i < params.length; i++) {
const param = params[i].split("=");
if (param.length !== 2) {
result[params[i]] = true;
} else {
result[param[0]] = decodeURIComponent(param[1].replace(/\+/g, " "));
}
}
return result;
},
/**
* Actual modulo function, since % is actually the remainder function in JS.
*
* @author Matt C [matt@artemisbot.pw]
* @author Matt C [matt@artemisbot.uk]
* @param {number} x
* @param {number} y
* @returns {number}
@@ -1102,7 +1170,7 @@ const Utils = {
/**
* Finds the greatest common divisor of two numbers.
*
* @author Matt C [matt@artemisbot.pw]
* @author Matt C [matt@artemisbot.uk]
* @param {number} x
* @param {number} y
* @returns {number}
@@ -1118,14 +1186,14 @@ const Utils = {
/**
* Finds the modular inverse of two values.
*
* @author Matt C [matt@artemisbot.pw]
* @author Matt C [matt@artemisbot.uk]
* @param {number} x
* @param {number} y
* @returns {number}
*/
modInv: function(x, y) {
x %= y;
for (var i = 1; i < y; i++) {
for (let i = 1; i < y; i++) {
if ((x * i) % 26 === 1) {
return i;
}
@@ -1203,8 +1271,8 @@ export default Utils;
* ["One", "Two", "Three", "One"].unique();
*/
Array.prototype.unique = function() {
var u = {}, a = [];
for (var i = 0, l = this.length; i < l; i++) {
let u = {}, a = [];
for (let i = 0, l = this.length; i < l; i++) {
if (u.hasOwnProperty(this[i])) {
continue;
}
@@ -1274,7 +1342,7 @@ Array.prototype.sum = function() {
*/
Array.prototype.equals = function(other) {
if (!other) return false;
var i = this.length;
let i = this.length;
if (i !== other.length) return false;
while (i--) {
if (this[i] !== other[i]) return false;
@@ -1314,11 +1382,11 @@ CryptoJS.enc.Hex.parse = function (hexStr) {
hexStr = hexStr.replace(/\s/g, "");
// Shortcut
var hexStrLength = hexStr.length;
const hexStrLength = hexStr.length;
// Convert
var words = [];
for (var i = 0; i < hexStrLength; i += 2) {
const words = [];
for (let i = 0; i < hexStrLength; i += 2) {
words[i >>> 3] |= parseInt(hexStr.substr(i, 2), 16) << (24 - (i % 8) * 4);
}

View File

@@ -46,6 +46,8 @@ const Categories = [
"From Base58",
"To Base",
"From Base",
"To BCD",
"From BCD",
"To HTML Entity",
"From HTML Entity",
"URL Encode",
@@ -61,7 +63,8 @@ const Categories = [
"Hex to PEM",
"Parse ASN.1 hex string",
"Change IP format",
"Text encoding",
"Encode text",
"Decode text",
"Swap endianness",
]
},
@@ -88,6 +91,8 @@ const Categories = [
"Vigenère Decode",
"To Morse Code",
"From Morse Code",
"Bifid Cipher Encode",
"Bifid Cipher Decode",
"Affine Cipher Encode",
"Affine Cipher Decode",
"Atbash Cipher",
@@ -125,6 +130,7 @@ const Categories = [
{
name: "Networking",
ops: [
"HTTP request",
"Strip HTTP headers",
"Parse User Agent",
"Parse IP range",
@@ -143,7 +149,8 @@ const Categories = [
{
name: "Language",
ops: [
"Text encoding",
"Encode text",
"Decode text",
"Unescape Unicode Characters",
]
},
@@ -162,9 +169,10 @@ const Categories = [
"Unique",
"Split",
"Filter",
"Head",
"Tail",
"Count occurrences",
"Expand alphabet range",
"Parse escaped string",
"Drop bytes",
"Take bytes",
"Pad lines",
@@ -179,6 +187,8 @@ const Categories = [
"Parse UNIX file permissions",
"Swap endianness",
"Parse colour code",
"Escape string",
"Unescape string",
]
},
{
@@ -188,6 +198,8 @@ const Categories = [
"Translate DateTime Format",
"From UNIX Timestamp",
"To UNIX Timestamp",
"Windows Filetime to UNIX Timestamp",
"UNIX Timestamp to Windows Filetime",
"Extract dates",
]
},
@@ -204,7 +216,9 @@ const Categories = [
"Extract dates",
"Regular expression",
"XPath expression",
"JPath expression",
"CSS selector",
"Extract EXIF",
]
},
{
@@ -266,9 +280,13 @@ const Categories = [
"CSS Beautify",
"CSS Minify",
"XPath expression",
"JPath expression",
"CSS selector",
"Strip HTML tags",
"Diff",
"To Snake case",
"To Camel case",
"To Kebab case",
]
},
{
@@ -279,6 +297,9 @@ const Categories = [
"Detect File Type",
"Scan for Embedded Files",
"Generate UUID",
"Render Image",
"Remove EXIF",
"Extract EXIF",
"Numberwang",
]
},
@@ -290,6 +311,7 @@ const Categories = [
"Jump",
"Conditional Jump",
"Return",
"Comment"
]
},
];

View File

@@ -2,6 +2,7 @@ import FlowControl from "../FlowControl.js";
import Base from "../operations/Base.js";
import Base58 from "../operations/Base58.js";
import Base64 from "../operations/Base64.js";
import BCD from "../operations/BCD.js";
import BitwiseOp from "../operations/BitwiseOp.js";
import ByteRepr from "../operations/ByteRepr.js";
import CharEnc from "../operations/CharEnc.js";
@@ -15,6 +16,7 @@ import Endian from "../operations/Endian.js";
import Entropy from "../operations/Entropy.js";
import Extract from "../operations/Extract.js";
import FileType from "../operations/FileType.js";
import Image from "../operations/Image.js";
import Hash from "../operations/Hash.js";
import Hexdump from "../operations/Hexdump.js";
import HTML from "../operations/HTML.js";
@@ -162,6 +164,20 @@ const OperationConfig = {
flowControl: true,
args: []
},
"Comment": {
description: "Provides a place to write comments within the flow of the recipe. This operation has no computational effect.",
run: FlowControl.runComment,
inputType: "string",
outputType: "string",
flowControl: true,
args: [
{
name: "",
type: "text",
value: ""
}
]
},
"From Base64": {
description: "Base64 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.<br><br>This operation decodes data from an ASCII Base64 string back into its raw format.<br><br>e.g. <code>aGVsbG8=</code> becomes <code>hello</code>",
run: Base64.runFrom,
@@ -315,30 +331,25 @@ const OperationConfig = {
value: BitwiseOp.XOR_BRUTE_KEY_LENGTH
},
{
name: "Length of sample",
name: "Sample length",
type: "number",
value: BitwiseOp.XOR_BRUTE_SAMPLE_LENGTH
},
{
name: "Offset of sample",
name: "Sample offset",
type: "number",
value: BitwiseOp.XOR_BRUTE_SAMPLE_OFFSET
},
{
name: "Scheme",
type: "option",
value: BitwiseOp.XOR_SCHEME
},
{
name: "Null preserving",
type: "boolean",
value: BitwiseOp.XOR_PRESERVE_NULLS
},
{
name: "Differential",
type: "boolean",
value: BitwiseOp.XOR_DIFFERENTIAL
},
{
name: "Crib (known plaintext string)",
type: "binaryString",
value: ""
},
{
name: "Print key",
type: "boolean",
@@ -348,6 +359,11 @@ const OperationConfig = {
name: "Output as hex",
type: "boolean",
value: BitwiseOp.XOR_BRUTE_OUTPUT_HEX
},
{
name: "Crib (known plaintext string)",
type: "binaryString",
value: ""
}
]
},
@@ -590,7 +606,7 @@ const OperationConfig = {
args: []
},
"To Hexdump": {
description: "Creates a hexdump of the input data, displaying both the hexademinal values of each byte and an ASCII representation alongside.",
description: "Creates a hexdump of the input data, displaying both the hexadecimal values of each byte and an ASCII representation alongside.",
run: Hexdump.runTo,
highlight: Hexdump.highlightTo,
highlightReverse: Hexdump.highlightFrom,
@@ -872,21 +888,43 @@ const OperationConfig = {
}
]
},
"Text encoding": {
description: "Translates the data between different character encodings.<br><br>Supported charsets are:<ul><li>UTF8</li><li>UTF16</li><li>UTF16LE (little-endian)</li><li>UTF16BE (big-endian)</li><li>Hex</li><li>Base64</li><li>Latin1 (ISO-8859-1)</li><li>Windows-1251</li></ul>",
run: CharEnc.run,
"Encode text": {
description: [
"Encodes text into the chosen character encoding.",
"<br><br>",
"Supported charsets are:",
"<ul>",
Object.keys(CharEnc.IO_FORMAT).map(e => `<li>${e}</li>`).join("\n"),
"</ul>",
].join("\n"),
run: CharEnc.runEncode,
inputType: "string",
outputType: "byteArray",
args: [
{
name: "Encoding",
type: "option",
value: Object.keys(CharEnc.IO_FORMAT),
},
]
},
"Decode text": {
description: [
"Decodes text from the chosen character encoding.",
"<br><br>",
"Supported charsets are:",
"<ul>",
Object.keys(CharEnc.IO_FORMAT).map(e => `<li>${e}</li>`).join("\n"),
"</ul>",
].join("\n"),
run: CharEnc.runDecode,
inputType: "byteArray",
outputType: "string",
args: [
{
name: "Input type",
name: "Encoding",
type: "option",
value: CharEnc.IO_FORMAT
},
{
name: "Output type",
type: "option",
value: CharEnc.IO_FORMAT
value: Object.keys(CharEnc.IO_FORMAT),
},
]
},
@@ -907,7 +945,6 @@ const OperationConfig = {
type: "toggleString",
value: "",
toggleValues: Cipher.IO_FORMAT1
},
{
name: "Salt",
@@ -954,7 +991,6 @@ const OperationConfig = {
type: "toggleString",
value: "",
toggleValues: Cipher.IO_FORMAT1
},
{
name: "Salt",
@@ -1387,6 +1423,11 @@ const OperationConfig = {
type: "number",
value: Cipher.KDF_ITERATIONS
},
{
name: "Hashing function",
type: "option",
value: Cipher.HASHERS
},
{
name: "Salt (hex)",
type: "string",
@@ -1420,6 +1461,11 @@ const OperationConfig = {
type: "number",
value: Cipher.KDF_ITERATIONS
},
{
name: "Hashing function",
type: "option",
value: Cipher.HASHERS
},
{
name: "Salt (hex)",
type: "string",
@@ -1467,6 +1513,36 @@ const OperationConfig = {
}
]
},
"Bifid Cipher Encode": {
description: "The Bifid cipher is a cipher which uses a Polybius square in conjunction with transposition, which can be fairly difficult to decipher without knowing the alphabet keyword.",
run: Cipher.runBifidEnc,
highlight: true,
highlightReverse: true,
inputType: "string",
outputType: "string",
args: [
{
name: "Keyword",
type: "string",
value: ""
}
]
},
"Bifid Cipher Decode": {
description: "The Bifid cipher is a cipher which uses a Polybius square in conjunction with transposition, which can be fairly difficult to decipher without knowing the alphabet keyword.",
run: Cipher.runBifidDec,
highlight: true,
highlightReverse: true,
inputType: "string",
outputType: "string",
args: [
{
name: "Keyword",
type: "string",
value: ""
}
]
},
"Affine Cipher Encode": {
description: "The Affine cipher is a type of monoalphabetic substitution cipher, wherein each letter in an alphabet is mapped to its numeric equivalent, encrypted using simple mathematical function, <code>(ax + b) % 26</code>, and converted back to a letter.",
run: Cipher.runAffineEnc,
@@ -1874,7 +1950,7 @@ const OperationConfig = {
args: []
},
"Find / Replace": {
description: "Replaces all occurrences of the first string with the second.<br><br>The three match options are only relevant to regex search strings.",
description: "Replaces all occurrences of the first string with the second.<br><br> Includes support for regular expressions (regex), simple strings and extended strings (which support \\n, \\r, \\t, \\b, \\f and escaped hex bytes using \\x notation, e.g. \\x00 for a null byte).",
run: StrUtils.runFindReplace,
manualBake: true,
inputType: "string",
@@ -2167,6 +2243,24 @@ const OperationConfig = {
}
]
},
"JPath expression": {
description: "Extract information from a JSON object with a JPath query.",
run: Code.runJpath,
inputType: "string",
outputType: "string",
args: [
{
name: "Query",
type: "string",
value: Code.JPATH_INITIAL
},
{
name: "Result delimiter",
type: "binaryShortString",
value: Code.JPATH_DELIMITER
}
]
},
"CSS selector": {
description: "Extract information from an HTML document with a CSS selector",
run: Code.runCSSQuery,
@@ -2186,7 +2280,7 @@ const OperationConfig = {
]
},
"From UNIX Timestamp": {
description: "Converts a UNIX timestamp to a datetime string.<br><br>e.g. <code>978346800</code> becomes <code>Mon 1 January 2001 11:00:00 UTC</code>",
description: "Converts a UNIX timestamp to a datetime string.<br><br>e.g. <code>978346800</code> becomes <code>Mon 1 January 2001 11:00:00 UTC</code><br><br>A UNIX timestamp is a 32-bit value representing the number of seconds since January 1, 1970 UTC (the UNIX epoch).",
run: DateTime.runFromUnixTimestamp,
inputType: "number",
outputType: "string",
@@ -2199,7 +2293,7 @@ const OperationConfig = {
]
},
"To UNIX Timestamp": {
description: "Parses a datetime string and returns the corresponding UNIX timestamp.<br><br>e.g. <code>Mon 1 January 2001 11:00:00 UTC</code> becomes <code>978346800</code>",
description: "Parses a datetime string in UTC and returns the corresponding UNIX timestamp.<br><br>e.g. <code>Mon 1 January 2001 11:00:00</code> becomes <code>978346800</code><br><br>A UNIX timestamp is a 32-bit value representing the number of seconds since January 1, 1970 UTC (the UNIX epoch).",
run: DateTime.runToUnixTimestamp,
inputType: "string",
outputType: "number",
@@ -2208,6 +2302,47 @@ const OperationConfig = {
name: "Units",
type: "option",
value: DateTime.UNITS
},
{
name: "Treat as UTC",
type: "boolean",
value: DateTime.TREAT_AS_UTC
}
]
},
"Windows Filetime to UNIX Timestamp": {
description: "Converts a Windows Filetime value to a UNIX timestamp.<br><br>A Windows Filetime is a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 UTC.<br><br>A UNIX timestamp is a 32-bit value representing the number of seconds since January 1, 1970 UTC (the UNIX epoch).<br><br>This operation also supports UNIX timestamps in milliseconds, microseconds and nanoseconds.",
run: DateTime.runFromFiletimeToUnix,
inputType: "string",
outputType: "string",
args: [
{
name: "Output units",
type: "option",
value: DateTime.UNITS
},
{
name: "Input format",
type: "option",
value: DateTime.FILETIME_FORMATS
}
]
},
"UNIX Timestamp to Windows Filetime": {
description: "Converts a UNIX timestamp to a Windows Filetime value.<br><br>A Windows Filetime is a 64-bit value representing the number of 100-nanosecond intervals since January 1, 1601 UTC.<br><br>A UNIX timestamp is a 32-bit value representing the number of seconds since January 1, 1970 UTC (the UNIX epoch).<br><br>This operation also supports UNIX timestamps in milliseconds, microseconds and nanoseconds.",
run: DateTime.runToFiletimeFromUnix,
inputType: "string",
outputType: "string",
args: [
{
name: "Input units",
type: "option",
value: DateTime.UNITS
},
{
name: "Output format",
type: "option",
value: DateTime.FILETIME_FORMATS
}
]
},
@@ -3089,13 +3224,6 @@ const OperationConfig = {
}
]
},
"Parse escaped string": {
description: "Replaces escaped characters with the bytes they represent.<br><br>e.g.<code>Hello\\nWorld</code> becomes <code>Hello<br>World</code>",
run: StrUtils.runParseEscapedString,
inputType: "string",
outputType: "string",
args: []
},
"TCP/IP Checksum": {
description: "Calculates the checksum for a TCP (Transport Control Protocol) or IP (Internet Protocol) header from an input of raw bytes.",
run: Checksum.runTCPIP,
@@ -3120,8 +3248,8 @@ const OperationConfig = {
"Substitute": {
description: "A substitution cipher allowing you to specify bytes to replace with other byte values. This can be used to create Caesar ciphers but is more powerful as any byte value can be substituted, not just letters, and the substitution values need not be in order.<br><br>Enter the bytes you want to replace in the Plaintext field and the bytes to replace them with in the Ciphertext field.<br><br>Non-printable bytes can be specified using string escape notation. For example, a line feed character can be written as either <code>\\n</code> or <code>\\x0a</code>.<br><br>Byte ranges can be specified using a hyphen. For example, the sequence <code>0123456789</code> can be written as <code>0-9</code>.",
run: Cipher.runSubstitute,
inputType: "byteArray",
outputType: "byteArray",
inputType: "string",
outputType: "string",
args: [
{
name: "Plaintext",
@@ -3135,6 +3263,20 @@ const OperationConfig = {
}
]
},
"Escape string": {
description: "Escapes special characters in a string so that they do not cause conflicts. For example, <code>Don't stop me now</code> becomes <code>Don\\'t stop me now</code>.",
run: StrUtils.runEscape,
inputType: "string",
outputType: "string",
args: []
},
"Unescape string": {
description: "Unescapes characters in a string that have been escaped. For example, <code>Don\\'t stop me now</code> becomes <code>Don't stop me now</code>.",
run: StrUtils.runUnescape,
inputType: "string",
outputType: "string",
args: []
},
"To Morse Code": {
description: "Translates alphanumeric characters into International Morse Code.<br><br>Ignores non-Morse characters.<br><br>e.g. <code>SOS</code> becomes <code>... --- ...</code>",
run: MorseCode.runTo,
@@ -3196,7 +3338,259 @@ const OperationConfig = {
outputType: "html",
args: [
]
}
},
"Head": {
description: [
"Like the UNIX head utility.",
"<br>",
"Gets the first n lines.",
"<br>",
"You can select all but the last n lines by entering a negative value for n.",
"<br>",
"The delimiter can be changed so that instead of lines, fields (i.e. commas) are selected instead.",
].join("\n"),
run: StrUtils.runHead,
inputType: "string",
outputType: "string",
args: [
{
name: "Delimiter",
type: "option",
value: StrUtils.DELIMITER_OPTIONS
},
{
name: "Number",
type: "number",
value: 10,
},
]
},
"Tail": {
description: [
"Like the UNIX tail utility.",
"<br>",
"Gets the last n lines.",
"<br>",
"Optionally you can select all lines after line n by entering a negative value for n.",
"<br>",
"The delimiter can be changed so that instead of lines, fields (i.e. commas) are selected instead.",
].join("\n"),
run: StrUtils.runTail,
inputType: "string",
outputType: "string",
args: [
{
name: "Delimiter",
type: "option",
value: StrUtils.DELIMITER_OPTIONS
},
{
name: "Number",
type: "number",
value: 10,
},
]
},
"To Snake case": {
description: [
"Converts the input string to snake case.",
"<br><br>",
"Snake case is all lower case with underscores as word boundaries.",
"<br><br>",
"e.g. this_is_snake_case",
"<br><br>",
"'Attempt to be context aware' will make the operation attempt to nicely transform variable and function names.",
].join("\n"),
run: Code.runToSnakeCase,
inputType: "string",
outputType: "string",
args: [
{
name: "Attempt to be context aware",
type: "boolean",
value: false,
},
]
},
"To Camel case": {
description: [
"Converts the input string to camel case.",
"<br><br>",
"Camel case is all lower case except letters after word boundaries which are uppercase.",
"<br><br>",
"e.g. thisIsCamelCase",
"<br><br>",
"'Attempt to be context aware' will make the operation attempt to nicely transform variable and function names.",
].join("\n"),
run: Code.runToCamelCase,
inputType: "string",
outputType: "string",
args: [
{
name: "Attempt to be context aware",
type: "boolean",
value: false,
},
]
},
"To Kebab case": {
description: [
"Converts the input string to kebab case.",
"<br><br>",
"Kebab case is all lower case with dashes as word boundaries.",
"<br><br>",
"e.g. this-is-kebab-case",
"<br><br>",
"'Attempt to be context aware' will make the operation attempt to nicely transform variable and function names.",
].join("\n"),
run: Code.runToKebabCase,
inputType: "string",
outputType: "string",
args: [
{
name: "Attempt to be context aware",
type: "boolean",
value: false,
},
]
},
"Extract EXIF": {
description: [
"Extracts EXIF data from an image.",
"<br><br>",
"EXIF data is metadata embedded in images (JPEG, JPG, TIFF) and audio files.",
"<br><br>",
"EXIF data from photos usually contains information about the image file itself as well as the device used to create it.",
].join("\n"),
run: Image.runExtractEXIF,
inputType: "byteArray",
outputType: "string",
args: [],
},
"Render Image": {
description: "Displays the input as an image. Supports the following formats:<br><br><ul><li>jpg/jpeg</li><li>png</li><li>gif</li><li>webp</li><li>bmp</li><li>ico</li></ul>",
run: Image.runRenderImage,
inputType: "string",
outputType: "html",
args: [
{
name: "Input format",
type: "option",
value: Image.INPUT_FORMAT
}
]
},
"Remove EXIF": {
description: [
"Removes EXIF data from a JPEG image.",
"<br><br>",
"EXIF data embedded in photos usually contains information about the image file itself as well as the device used to create it.",
].join("\n"),
run: Image.runRemoveEXIF,
inputType: "byteArray",
outputType: "byteArray",
args: []
},
"HTTP request": {
description: [
"Makes an HTTP request and returns the response.",
"<br><br>",
"This operation supports different HTTP verbs like GET, POST, PUT, etc.",
"<br><br>",
"You can add headers line by line in the format <code>Key: Value</code>",
"<br><br>",
"The status code of the response, along with a limited selection of exposed headers, can be viewed by checking the 'Show response metadata' option. Only a limited set of response headers are exposed by the browser for security reasons.",
].join("\n"),
run: HTTP.runHTTPRequest,
inputType: "string",
outputType: "string",
manualBake: true,
args: [
{
name: "Method",
type: "option",
value: HTTP.METHODS,
},
{
name: "URL",
type: "string",
value: "",
},
{
name: "Headers",
type: "text",
value: "",
},
{
name: "Mode",
type: "option",
value: HTTP.MODE,
},
{
name: "Show response metadata",
type: "boolean",
value: false,
}
]
},
"From BCD": {
description: "Binary-Coded Decimal (BCD) is a class of binary encodings of decimal numbers where each decimal digit is represented by a fixed number of bits, usually four or eight. Special bit patterns are sometimes used for a sign.",
run: BCD.runFromBCD,
inputType: "string",
outputType: "number",
args: [
{
name: "Scheme",
type: "option",
value: BCD.ENCODING_SCHEME
},
{
name: "Packed",
type: "boolean",
value: true
},
{
name: "Signed",
type: "boolean",
value: false
},
{
name: "Input format",
type: "option",
value: BCD.FORMAT
}
]
},
"To BCD": {
description: "Binary-Coded Decimal (BCD) is a class of binary encodings of decimal numbers where each decimal digit is represented by a fixed number of bits, usually four or eight. Special bit patterns are sometimes used for a sign",
run: BCD.runToBCD,
inputType: "number",
outputType: "string",
args: [
{
name: "Scheme",
type: "option",
value: BCD.ENCODING_SCHEME
},
{
name: "Packed",
type: "boolean",
value: true
},
{
name: "Signed",
type: "boolean",
value: false
},
{
name: "Output format",
type: "option",
value: BCD.FORMAT
}
]
},
};
export default OperationConfig;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,515 @@
/* cputils.js (C) 2013-present SheetJS -- http://sheetjs.com */
/* vim: set ft=javascript: */
/*jshint newcap: false */
(function(root, factory) {
"use strict";
if(typeof cptable === "undefined") {
if(typeof require !== "undefined"){
var cpt = require('./cptable');
if (typeof module !== 'undefined' && module.exports) module.exports = factory(cpt);
else root.cptable = factory(cpt);
} else throw new Error("cptable not found");
} else cptable = factory(cptable);
}(this, function(cpt){
"use strict";
var magic = {
"1200":"utf16le",
"1201":"utf16be",
"12000":"utf32le",
"12001":"utf32be",
"16969":"utf64le",
"20127":"ascii",
"65000":"utf7",
"65001":"utf8"
};
var sbcs_cache = [874,1250,1251,1252,1253,1254,1255,1256,10000];
var dbcs_cache = [932,936,949,950];
var magic_cache = [65001];
var magic_decode = {};
var magic_encode = {};
var cpdcache = {};
var cpecache = {};
var sfcc = function sfcc(x) { return String.fromCharCode(x); };
var cca = function cca(x) { return x.charCodeAt(0); };
var has_buf = (typeof Buffer !== 'undefined');
if(has_buf) {
var mdl = 1024, mdb = new Buffer(mdl);
var make_EE = function make_EE(E){
var EE = new Buffer(65536);
for(var i = 0; i < 65536;++i) EE[i] = 0;
var keys = Object.keys(E), len = keys.length;
for(var ee = 0, e = keys[ee]; ee < len; ++ee) {
if(!(e = keys[ee])) continue;
EE[e.charCodeAt(0)] = E[e];
}
return EE;
};
var sbcs_encode = function make_sbcs_encode(cp) {
var EE = make_EE(cpt[cp].enc);
return function sbcs_e(data, ofmt) {
var len = data.length;
var out, i=0, j=0, D=0, w=0;
if(typeof data === 'string') {
out = new Buffer(len);
for(i = 0; i < len; ++i) out[i] = EE[data.charCodeAt(i)];
} else if(Buffer.isBuffer(data)) {
out = new Buffer(2*len);
j = 0;
for(i = 0; i < len; ++i) {
D = data[i];
if(D < 128) out[j++] = EE[D];
else if(D < 224) { out[j++] = EE[((D&31)<<6)+(data[i+1]&63)]; ++i; }
else if(D < 240) { out[j++] = EE[((D&15)<<12)+((data[i+1]&63)<<6)+(data[i+2]&63)]; i+=2; }
else {
w = ((D&7)<<18)+((data[i+1]&63)<<12)+((data[i+2]&63)<<6)+(data[i+3]&63); i+=3;
if(w < 65536) out[j++] = EE[w];
else { w -= 65536; out[j++] = EE[0xD800 + ((w>>10)&1023)]; out[j++] = EE[0xDC00 + (w&1023)]; }
}
}
out = out.slice(0,j);
} else {
out = new Buffer(len);
for(i = 0; i < len; ++i) out[i] = EE[data[i].charCodeAt(0)];
}
if(!ofmt || ofmt === 'buf') return out;
if(ofmt !== 'arr') return out.toString('binary');
return [].slice.call(out);
};
};
var sbcs_decode = function make_sbcs_decode(cp) {
var D = cpt[cp].dec;
var DD = new Buffer(131072), d=0, c="";
for(d=0;d<D.length;++d) {
if(!(c=D[d])) continue;
var w = c.charCodeAt(0);
DD[2*d] = w&255; DD[2*d+1] = w>>8;
}
return function sbcs_d(data) {
var len = data.length, i=0, j=0;
if(2 * len > mdl) { mdl = 2 * len; mdb = new Buffer(mdl); }
if(Buffer.isBuffer(data)) {
for(i = 0; i < len; i++) {
j = 2*data[i];
mdb[2*i] = DD[j]; mdb[2*i+1] = DD[j+1];
}
} else if(typeof data === "string") {
for(i = 0; i < len; i++) {
j = 2*data.charCodeAt(i);
mdb[2*i] = DD[j]; mdb[2*i+1] = DD[j+1];
}
} else {
for(i = 0; i < len; i++) {
j = 2*data[i];
mdb[2*i] = DD[j]; mdb[2*i+1] = DD[j+1];
}
}
return mdb.slice(0, 2 * len).toString('ucs2');
};
};
var dbcs_encode = function make_dbcs_encode(cp) {
var E = cpt[cp].enc;
var EE = new Buffer(131072);
for(var i = 0; i < 131072; ++i) EE[i] = 0;
var keys = Object.keys(E);
for(var ee = 0, e = keys[ee]; ee < keys.length; ++ee) {
if(!(e = keys[ee])) continue;
var f = e.charCodeAt(0);
EE[2*f] = E[e] & 255; EE[2*f+1] = E[e]>>8;
}
return function dbcs_e(data, ofmt) {
var len = data.length, out = new Buffer(2*len), i=0, j=0, jj=0, k=0, D=0;
if(typeof data === 'string') {
for(i = k = 0; i < len; ++i) {
j = data.charCodeAt(i)*2;
out[k++] = EE[j+1] || EE[j]; if(EE[j+1] > 0) out[k++] = EE[j];
}
out = out.slice(0,k);
} else if(Buffer.isBuffer(data)) {
for(i = k = 0; i < len; ++i) {
D = data[i];
if(D < 128) j = D;
else if(D < 224) { j = ((D&31)<<6)+(data[i+1]&63); ++i; }
else if(D < 240) { j = ((D&15)<<12)+((data[i+1]&63)<<6)+(data[i+2]&63); i+=2; }
else { j = ((D&7)<<18)+((data[i+1]&63)<<12)+((data[i+2]&63)<<6)+(data[i+3]&63); i+=3; }
if(j<65536) { j*=2; out[k++] = EE[j+1] || EE[j]; if(EE[j+1] > 0) out[k++] = EE[j]; }
else { jj = j-65536;
j=2*(0xD800 + ((jj>>10)&1023)); out[k++] = EE[j+1] || EE[j]; if(EE[j+1] > 0) out[k++] = EE[j];
j=2*(0xDC00 + (jj&1023)); out[k++] = EE[j+1] || EE[j]; if(EE[j+1] > 0) out[k++] = EE[j];
}
}
out = out.slice(0,k);
} else {
for(i = k = 0; i < len; i++) {
j = data[i].charCodeAt(0)*2;
out[k++] = EE[j+1] || EE[j]; if(EE[j+1] > 0) out[k++] = EE[j];
}
}
if(!ofmt || ofmt === 'buf') return out;
if(ofmt !== 'arr') return out.toString('binary');
return [].slice.call(out);
};
};
var dbcs_decode = function make_dbcs_decode(cp) {
var D = cpt[cp].dec;
var DD = new Buffer(131072), d=0, c, w=0, j=0, i=0;
for(i = 0; i < 65536; ++i) { DD[2*i] = 0xFF; DD[2*i+1] = 0xFD;}
for(d = 0; d < D.length; ++d) {
if(!(c=D[d])) continue;
w = c.charCodeAt(0);
j = 2*d;
DD[j] = w&255; DD[j+1] = w>>8;
}
return function dbcs_d(data) {
var len = data.length, out = new Buffer(2*len), i=0, j=0, k=0;
if(Buffer.isBuffer(data)) {
for(i = 0; i < len; i++) {
j = 2*data[i];
if(DD[j]===0xFF && DD[j+1]===0xFD) { j=2*((data[i]<<8)+data[i+1]); ++i; }
out[k++] = DD[j]; out[k++] = DD[j+1];
}
} else if(typeof data === "string") {
for(i = 0; i < len; i++) {
j = 2*data.charCodeAt(i);
if(DD[j]===0xFF && DD[j+1]===0xFD) { j=2*((data.charCodeAt(i)<<8)+data.charCodeAt(i+1)); ++i; }
out[k++] = DD[j]; out[k++] = DD[j+1];
}
} else {
for(i = 0; i < len; i++) {
j = 2*data[i];
if(DD[j]===0xFF && DD[j+1]===0xFD) { j=2*((data[i]<<8)+data[i+1]); ++i; }
out[k++] = DD[j]; out[k++] = DD[j+1];
}
}
return out.slice(0,k).toString('ucs2');
};
};
magic_decode[65001] = function utf8_d(data) {
if(typeof data === "string") return utf8_d(data.split("").map(cca));
var len = data.length, w = 0, ww = 0;
if(4 * len > mdl) { mdl = 4 * len; mdb = new Buffer(mdl); }
var i = 0;
if(len >= 3 && data[0] == 0xEF) if(data[1] == 0xBB && data[2] == 0xBF) i = 3;
for(var j = 1, k = 0, D = 0; i < len; i+=j) {
j = 1; D = data[i];
if(D < 128) w = D;
else if(D < 224) { w=(D&31)*64+(data[i+1]&63); j=2; }
else if(D < 240) { w=((D&15)<<12)+(data[i+1]&63)*64+(data[i+2]&63); j=3; }
else { w=(D&7)*262144+((data[i+1]&63)<<12)+(data[i+2]&63)*64+(data[i+3]&63); j=4; }
if(w < 65536) { mdb[k++] = w&255; mdb[k++] = w>>8; }
else {
w -= 65536; ww = 0xD800 + ((w>>10)&1023); w = 0xDC00 + (w&1023);
mdb[k++] = ww&255; mdb[k++] = ww>>>8; mdb[k++] = w&255; mdb[k++] = (w>>>8)&255;
}
}
return mdb.slice(0,k).toString('ucs2');
};
magic_encode[65001] = function utf8_e(data, ofmt) {
if(has_buf && Buffer.isBuffer(data)) {
if(!ofmt || ofmt === 'buf') return data;
if(ofmt !== 'arr') return data.toString('binary');
return [].slice.call(data);
}
var len = data.length, w = 0, ww = 0, j = 0;
var direct = typeof data === "string";
if(4 * len > mdl) { mdl = 4 * len; mdb = new Buffer(mdl); }
for(var i = 0; i < len; ++i) {
w = direct ? data.charCodeAt(i) : data[i].charCodeAt(0);
if(w <= 0x007F) mdb[j++] = w;
else if(w <= 0x07FF) {
mdb[j++] = 192 + (w >> 6);
mdb[j++] = 128 + (w&63);
} else if(w >= 0xD800 && w <= 0xDFFF) {
w -= 0xD800; ++i;
ww = (direct ? data.charCodeAt(i) : data[i].charCodeAt(0)) - 0xDC00 + (w << 10);
mdb[j++] = 240 + ((ww>>>18) & 0x07);
mdb[j++] = 144 + ((ww>>>12) & 0x3F);
mdb[j++] = 128 + ((ww>>>6) & 0x3F);
mdb[j++] = 128 + (ww & 0x3F);
} else {
mdb[j++] = 224 + (w >> 12);
mdb[j++] = 128 + ((w >> 6)&63);
mdb[j++] = 128 + (w&63);
}
}
if(!ofmt || ofmt === 'buf') return mdb.slice(0,j);
if(ofmt !== 'arr') return mdb.slice(0,j).toString('binary');
return [].slice.call(mdb, 0, j);
};
}
var encache = function encache() {
if(has_buf) {
if(cpdcache[sbcs_cache[0]]) return;
var i=0, s=0;
for(i = 0; i < sbcs_cache.length; ++i) {
s = sbcs_cache[i];
if(cpt[s]) {
cpdcache[s] = sbcs_decode(s);
cpecache[s] = sbcs_encode(s);
}
}
for(i = 0; i < dbcs_cache.length; ++i) {
s = dbcs_cache[i];
if(cpt[s]) {
cpdcache[s] = dbcs_decode(s);
cpecache[s] = dbcs_encode(s);
}
}
for(i = 0; i < magic_cache.length; ++i) {
s = magic_cache[i];
if(magic_decode[s]) cpdcache[s] = magic_decode[s];
if(magic_encode[s]) cpecache[s] = magic_encode[s];
}
}
};
var null_enc = function(data, ofmt) { return ""; };
var cp_decache = function cp_decache(cp) { delete cpdcache[cp]; delete cpecache[cp]; };
var decache = function decache() {
if(has_buf) {
if(!cpdcache[sbcs_cache[0]]) return;
sbcs_cache.forEach(cp_decache);
dbcs_cache.forEach(cp_decache);
magic_cache.forEach(cp_decache);
}
last_enc = null_enc; last_cp = 0;
};
var cache = {
encache: encache,
decache: decache,
sbcs: sbcs_cache,
dbcs: dbcs_cache
};
encache();
var BM = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
var SetD = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'(),-./:?";
var last_enc = null_enc, last_cp = 0;
var encode = function encode(cp, data, ofmt) {
if(cp === last_cp && last_enc) { return last_enc(data, ofmt); }
if(cpecache[cp]) { last_enc = cpecache[last_cp=cp]; return last_enc(data, ofmt); }
if(has_buf && Buffer.isBuffer(data)) data = data.toString('utf8');
var len = data.length;
var out = has_buf ? new Buffer(4*len) : [], w=0, i=0, j = 0, ww=0;
var C = cpt[cp], E, M = "";
var isstr = typeof data === 'string';
if(C && (E=C.enc)) for(i = 0; i < len; ++i, ++j) {
w = E[isstr? data.charAt(i) : data[i]];
if(w > 255) {
out[j] = w>>8;
out[++j] = w&255;
} else out[j] = w&255;
}
else if((M=magic[cp])) switch(M) {
case "utf8":
if(has_buf && isstr) { out = new Buffer(data, M); j = out.length; break; }
for(i = 0; i < len; ++i, ++j) {
w = isstr ? data.charCodeAt(i) : data[i].charCodeAt(0);
if(w <= 0x007F) out[j] = w;
else if(w <= 0x07FF) {
out[j] = 192 + (w >> 6);
out[++j] = 128 + (w&63);
} else if(w >= 0xD800 && w <= 0xDFFF) {
w -= 0xD800;
ww = (isstr ? data.charCodeAt(++i) : data[++i].charCodeAt(0)) - 0xDC00 + (w << 10);
out[j] = 240 + ((ww>>>18) & 0x07);
out[++j] = 144 + ((ww>>>12) & 0x3F);
out[++j] = 128 + ((ww>>>6) & 0x3F);
out[++j] = 128 + (ww & 0x3F);
} else {
out[j] = 224 + (w >> 12);
out[++j] = 128 + ((w >> 6)&63);
out[++j] = 128 + (w&63);
}
}
break;
case "ascii":
if(has_buf && typeof data === "string") { out = new Buffer(data, M); j = out.length; break; }
for(i = 0; i < len; ++i, ++j) {
w = isstr ? data.charCodeAt(i) : data[i].charCodeAt(0);
if(w <= 0x007F) out[j] = w;
else throw new Error("bad ascii " + w);
}
break;
case "utf16le":
if(has_buf && typeof data === "string") { out = new Buffer(data, M); j = out.length; break; }
for(i = 0; i < len; ++i) {
w = isstr ? data.charCodeAt(i) : data[i].charCodeAt(0);
out[j++] = w&255;
out[j++] = w>>8;
}
break;
case "utf16be":
for(i = 0; i < len; ++i) {
w = isstr ? data.charCodeAt(i) : data[i].charCodeAt(0);
out[j++] = w>>8;
out[j++] = w&255;
}
break;
case "utf32le":
for(i = 0; i < len; ++i) {
w = isstr ? data.charCodeAt(i) : data[i].charCodeAt(0);
if(w >= 0xD800 && w <= 0xDFFF) w = 0x10000 + ((w - 0xD800) << 10) + (data[++i].charCodeAt(0) - 0xDC00);
out[j++] = w&255; w >>= 8;
out[j++] = w&255; w >>= 8;
out[j++] = w&255; w >>= 8;
out[j++] = w&255;
}
break;
case "utf32be":
for(i = 0; i < len; ++i) {
w = isstr ? data.charCodeAt(i) : data[i].charCodeAt(0);
if(w >= 0xD800 && w <= 0xDFFF) w = 0x10000 + ((w - 0xD800) << 10) + (data[++i].charCodeAt(0) - 0xDC00);
out[j+3] = w&255; w >>= 8;
out[j+2] = w&255; w >>= 8;
out[j+1] = w&255; w >>= 8;
out[j] = w&255;
j+=4;
}
break;
case "utf7":
for(i = 0; i < len; i++) {
var c = isstr ? data.charAt(i) : data[i].charAt(0);
if(c === "+") { out[j++] = 0x2b; out[j++] = 0x2d; continue; }
if(SetD.indexOf(c) > -1) { out[j++] = c.charCodeAt(0); continue; }
var tt = encode(1201, c);
out[j++] = 0x2b;
out[j++] = BM.charCodeAt(tt[0]>>2);
out[j++] = BM.charCodeAt(((tt[0]&0x03)<<4) + ((tt[1]||0)>>4));
out[j++] = BM.charCodeAt(((tt[1]&0x0F)<<2) + ((tt[2]||0)>>6));
out[j++] = 0x2d;
}
break;
default: throw new Error("Unsupported magic: " + cp + " " + magic[cp]);
}
else throw new Error("Unrecognized CP: " + cp);
out = out.slice(0,j);
if(!has_buf) return (ofmt == 'str') ? (out).map(sfcc).join("") : out;
if(!ofmt || ofmt === 'buf') return out;
if(ofmt !== 'arr') return out.toString('binary');
return [].slice.call(out);
};
var decode = function decode(cp, data) {
var F; if((F=cpdcache[cp])) return F(data);
if(typeof data === "string") return decode(cp, data.split("").map(cca));
var len = data.length, out = new Array(len), s="", w=0, i=0, j=1, k=0, ww=0;
var C = cpt[cp], D, M="";
if(C && (D=C.dec)) {
for(i = 0; i < len; i+=j) {
j = 2;
s = D[(data[i]<<8)+ data[i+1]];
if(!s) {
j = 1;
s = D[data[i]];
}
if(!s) throw new Error('Unrecognized code: ' + data[i] + ' ' + data[i+j-1] + ' ' + i + ' ' + j + ' ' + D[data[i]]);
out[k++] = s;
}
}
else if((M=magic[cp])) switch(M) {
case "utf8":
if(len >= 3 && data[0] == 0xEF) if(data[1] == 0xBB && data[2] == 0xBF) i = 3;
for(; i < len; i+=j) {
j = 1;
if(data[i] < 128) w = data[i];
else if(data[i] < 224) { w=(data[i]&31)*64+(data[i+1]&63); j=2; }
else if(data[i] < 240) { w=((data[i]&15)<<12)+(data[i+1]&63)*64+(data[i+2]&63); j=3; }
else { w=(data[i]&7)*262144+((data[i+1]&63)<<12)+(data[i+2]&63)*64+(data[i+3]&63); j=4; }
if(w < 65536) { out[k++] = String.fromCharCode(w); }
else {
w -= 65536; ww = 0xD800 + ((w>>10)&1023); w = 0xDC00 + (w&1023);
out[k++] = String.fromCharCode(ww); out[k++] = String.fromCharCode(w);
}
}
break;
case "ascii":
if(has_buf && Buffer.isBuffer(data)) return data.toString(M);
for(i = 0; i < len; i++) out[i] = String.fromCharCode(data[i]);
k = len; break;
case "utf16le":
if(len >= 2 && data[0] == 0xFF) if(data[1] == 0xFE) i = 2;
if(has_buf && Buffer.isBuffer(data)) return data.toString(M);
j = 2;
for(; i+1 < len; i+=j) {
out[k++] = String.fromCharCode((data[i+1]<<8) + data[i]);
}
break;
case "utf16be":
if(len >= 2 && data[0] == 0xFE) if(data[1] == 0xFF) i = 2;
j = 2;
for(; i+1 < len; i+=j) {
out[k++] = String.fromCharCode((data[i]<<8) + data[i+1]);
}
break;
case "utf32le":
if(len >= 4 && data[0] == 0xFF) if(data[1] == 0xFE && data[2] === 0 && data[3] === 0) i = 4;
j = 4;
for(; i < len; i+=j) {
w = (data[i+3]<<24) + (data[i+2]<<16) + (data[i+1]<<8) + (data[i]);
if(w > 0xFFFF) {
w -= 0x10000;
out[k++] = String.fromCharCode(0xD800 + ((w >> 10) & 0x3FF));
out[k++] = String.fromCharCode(0xDC00 + (w & 0x3FF));
}
else out[k++] = String.fromCharCode(w);
}
break;
case "utf32be":
if(len >= 4 && data[3] == 0xFF) if(data[2] == 0xFE && data[1] === 0 && data[0] === 0) i = 4;
j = 4;
for(; i < len; i+=j) {
w = (data[i]<<24) + (data[i+1]<<16) + (data[i+2]<<8) + (data[i+3]);
if(w > 0xFFFF) {
w -= 0x10000;
out[k++] = String.fromCharCode(0xD800 + ((w >> 10) & 0x3FF));
out[k++] = String.fromCharCode(0xDC00 + (w & 0x3FF));
}
else out[k++] = String.fromCharCode(w);
}
break;
case "utf7":
if(len >= 4 && data[0] == 0x2B && data[1] == 0x2F && data[2] == 0x76) {
if(len >= 5 && data[3] == 0x38 && data[4] == 0x2D) i = 5;
else if(data[3] == 0x38 || data[3] == 0x39 || data[3] == 0x2B || data[3] == 0x2F) i = 4;
}
for(; i < len; i+=j) {
if(data[i] !== 0x2b) { j=1; out[k++] = String.fromCharCode(data[i]); continue; }
j=1;
if(data[i+1] === 0x2d) { j = 2; out[k++] = "+"; continue; }
while(String.fromCharCode(data[i+j]).match(/[A-Za-z0-9+\/]/)) j++;
var dash = 0;
if(data[i+j] === 0x2d) { ++j; dash=1; }
var tt = [];
var o64 = "";
var c1=0, c2=0, c3=0;
var e1=0, e2=0, e3=0, e4=0;
for(var l = 1; l < j - dash;) {
e1 = BM.indexOf(String.fromCharCode(data[i+l++]));
e2 = BM.indexOf(String.fromCharCode(data[i+l++]));
c1 = e1 << 2 | e2 >> 4;
tt.push(c1);
e3 = BM.indexOf(String.fromCharCode(data[i+l++]));
if(e3 === -1) break;
c2 = (e2 & 15) << 4 | e3 >> 2;
tt.push(c2);
e4 = BM.indexOf(String.fromCharCode(data[i+l++]));
if(e4 === -1) break;
c3 = (e3 & 3) << 6 | e4;
if(e4 < 64) tt.push(c3);
}
o64 = decode(1201, tt);
for(l = 0; l < o64.length; ++l) out[k++] = o64.charAt(l);
}
break;
default: throw new Error("Unsupported magic: " + cp + " " + magic[cp]);
}
else throw new Error("Unrecognized CP: " + cp);
return out.slice(0,k).join("");
};
var hascp = function hascp(cp) { return !!(cpt[cp] || magic[cp]); };
cpt.utils = { decode: decode, encode: encode, hascp: hascp, magic: magic, cache:cache };
return cpt;
}));

153
src/core/lib/remove-exif.js Normal file
View File

@@ -0,0 +1,153 @@
/* piexifjs
The MIT License (MIT)
Copyright (c) 2014, 2015 hMatoba(https://github.com/hMatoba)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
import Utils from "../Utils.js";
// Param jpeg should be a binaryArray
function removeEXIF(jpeg) {
// Convert binaryArray to char string
jpeg = Utils.byteArrayToChars(jpeg);
if (jpeg.slice(0, 2) != "\xff\xd8") {
throw ("Given data is not jpeg.");
}
var segments = splitIntoSegments(jpeg);
if (segments[1].slice(0, 2) == "\xff\xe1" &&
segments[1].slice(4, 10) == "Exif\x00\x00") {
segments = [segments[0]].concat(segments.slice(2));
} else if (segments[2].slice(0, 2) == "\xff\xe1" &&
segments[2].slice(4, 10) == "Exif\x00\x00") {
segments = segments.slice(0, 2).concat(segments.slice(3));
} else {
throw ("Exif not found.");
}
var new_data = segments.join("");
// Convert back to binaryArray
new_data = Utils.strToCharcode(new_data);
return new_data;
};
function splitIntoSegments(data) {
if (data.slice(0, 2) != "\xff\xd8") {
throw ("Given data isn't JPEG.");
}
var head = 2;
var segments = ["\xff\xd8"];
while (true) {
if (data.slice(head, head + 2) == "\xff\xda") {
segments.push(data.slice(head));
break;
} else {
var length = unpack(">H", data.slice(head + 2, head + 4))[0];
var endPoint = head + length + 2;
segments.push(data.slice(head, endPoint));
head = endPoint;
}
if (head >= data.length) {
throw ("Wrong JPEG data.");
}
}
return segments;
}
function unpack(mark, str) {
if (typeof(str) != "string") {
throw ("'unpack' error. Got invalid type argument.");
}
var l = 0;
for (var markPointer = 1; markPointer < mark.length; markPointer++) {
if (mark[markPointer].toLowerCase() == "b") {
l += 1;
} else if (mark[markPointer].toLowerCase() == "h") {
l += 2;
} else if (mark[markPointer].toLowerCase() == "l") {
l += 4;
} else {
throw ("'unpack' error. Got invalid mark.");
}
}
if (l != str.length) {
throw ("'unpack' error. Mismatch between symbol and string length. " + l + ":" + str.length);
}
var littleEndian;
if (mark[0] == "<") {
littleEndian = true;
} else if (mark[0] == ">") {
littleEndian = false;
} else {
throw ("'unpack' error.");
}
var unpacked = [];
var strPointer = 0;
var p = 1;
var val = null;
var c = null;
var length = null;
var sliced = "";
while (c = mark[p]) {
if (c.toLowerCase() == "b") {
length = 1;
sliced = str.slice(strPointer, strPointer + length);
val = sliced.charCodeAt(0);
if ((c == "b") && (val >= 0x80)) {
val -= 0x100;
}
} else if (c == "H") {
length = 2;
sliced = str.slice(strPointer, strPointer + length);
if (littleEndian) {
sliced = sliced.split("").reverse().join("");
}
val = sliced.charCodeAt(0) * 0x100 +
sliced.charCodeAt(1);
} else if (c.toLowerCase() == "l") {
length = 4;
sliced = str.slice(strPointer, strPointer + length);
if (littleEndian) {
sliced = sliced.split("").reverse().join("");
}
val = sliced.charCodeAt(0) * 0x1000000 +
sliced.charCodeAt(1) * 0x10000 +
sliced.charCodeAt(2) * 0x100 +
sliced.charCodeAt(3);
if ((c == "l") && (val >= 0x80000000)) {
val -= 0x100000000;
}
} else {
throw ("'unpack' error. " + c);
}
unpacked.push(val);
strPointer += length;
p += 1;
}
return unpacked;
}
export default removeEXIF;

214
src/core/operations/BCD.js Executable file
View File

@@ -0,0 +1,214 @@
import Utils from "../Utils.js";
/**
* Binary-Coded Decimal operations.
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2017
* @license Apache-2.0
*
* @namespace
*/
const BCD = {
/**
* @constant
* @default
*/
ENCODING_SCHEME: [
"8 4 2 1",
"7 4 2 1",
"4 2 2 1",
"2 4 2 1",
"8 4 -2 -1",
"Excess-3",
"IBM 8 4 2 1",
],
/**
* Lookup table for the binary value of each digit representation.
*
* I wrote a very nice algorithm to generate 8 4 2 1 encoding programatically,
* but unfortunately it's much easier (if less elegant) to use lookup tables
* when supporting multiple encoding schemes.
*
* "Practicality beats purity" - PEP 20
*
* In some schemes it is possible to represent the same value in multiple ways.
* For instance, in 4 2 2 1 encoding, 0100 and 0010 both represent 2. Support
* has not yet been added for this.
*
* @constant
*/
ENCODING_LOOKUP: {
"8 4 2 1": [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
"7 4 2 1": [0, 1, 2, 3, 4, 5, 6, 8, 9, 10],
"4 2 2 1": [0, 1, 4, 5, 8, 9, 12, 13, 14, 15],
"2 4 2 1": [0, 1, 2, 3, 4, 11, 12, 13, 14, 15],
"8 4 -2 -1": [0, 7, 6, 5, 4, 11, 10, 9, 8, 15],
"Excess-3": [3, 4, 5, 6, 7, 8, 9, 10, 11, 12],
"IBM 8 4 2 1": [10, 1, 2, 3, 4, 5, 6, 7, 8, 9],
},
/**
* @default
* @constant
*/
FORMAT: ["Nibbles", "Bytes", "Raw"],
/**
* To BCD operation.
*
* @param {number} input
* @param {Object[]} args
* @returns {string}
*/
runToBCD: function(input, args) {
if (isNaN(input))
return "Invalid input";
if (Math.floor(input) !== input)
return "Fractional values are not supported by BCD";
const encoding = BCD.ENCODING_LOOKUP[args[0]],
packed = args[1],
signed = args[2],
outputFormat = args[3];
// Split input number up into separate digits
const digits = input.toString().split("");
if (digits[0] === "-" || digits[0] === "+") {
digits.shift();
}
let nibbles = [];
digits.forEach(d => {
const n = parseInt(d, 10);
nibbles.push(encoding[n]);
});
if (signed) {
if (packed && digits.length % 2 === 0) {
// If there are an even number of digits, we add a leading 0 so
// that the sign nibble doesn't sit in its own byte, leading to
// ambiguity around whether the number ends with a 0 or not.
nibbles.unshift(encoding[0]);
}
nibbles.push(input > 0 ? 12 : 13);
// 12 ("C") for + (credit)
// 13 ("D") for - (debit)
}
let bytes = [];
if (packed) {
let encoded = 0,
little = false;
nibbles.forEach(n => {
encoded ^= little ? n : (n << 4);
if (little) {
bytes.push(encoded);
encoded = 0;
}
little = !little;
});
if (little) bytes.push(encoded);
} else {
bytes = nibbles;
// Add null high nibbles
nibbles = nibbles.map(n => {
return [0, n];
}).reduce((a, b) => {
return a.concat(b);
});
}
// Output
switch (outputFormat) {
case "Nibbles":
return nibbles.map(n => {
return Utils.padLeft(n.toString(2), 4);
}).join(" ");
case "Bytes":
return bytes.map(b => {
return Utils.padLeft(b.toString(2), 8);
}).join(" ");
case "Raw":
default:
return Utils.byteArrayToChars(bytes);
}
},
/**
* From BCD operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {number}
*/
runFromBCD: function(input, args) {
const encoding = BCD.ENCODING_LOOKUP[args[0]],
packed = args[1],
signed = args[2],
inputFormat = args[3];
let nibbles = [],
output = "",
byteArray;
// Normalise the input
switch (inputFormat) {
case "Nibbles":
case "Bytes":
input = input.replace(/\s/g, "");
for (let i = 0; i < input.length; i += 4) {
nibbles.push(parseInt(input.substr(i, 4), 2));
}
break;
case "Raw":
default:
byteArray = Utils.strToByteArray(input);
byteArray.forEach(b => {
nibbles.push(b >>> 4);
nibbles.push(b & 15);
});
break;
}
if (!packed) {
// Discard each high nibble
for (let i = 0; i < nibbles.length; i++) {
nibbles.splice(i, 1);
}
}
if (signed) {
const sign = nibbles.pop();
if (sign === 13 ||
sign === 11) {
// Negative
output += "-";
}
}
nibbles.forEach(n => {
if (isNaN(n)) throw "Invalid input";
let val = encoding.indexOf(n);
if (val < 0) throw `Value ${Utils.bin(n, 4)} not in encoding scheme`;
output += val.toString();
});
return parseInt(output, 10);
},
};
export default BCD;

View File

@@ -26,7 +26,7 @@ const Base = {
if (!input) {
throw ("Error: Input must be a number");
}
var radix = args[0] || Base.DEFAULT_RADIX;
const radix = args[0] || Base.DEFAULT_RADIX;
if (radix < 2 || radix > 36) {
throw "Error: Radix argument must be between 2 and 36";
}
@@ -42,19 +42,19 @@ const Base = {
* @returns {number}
*/
runFrom: function(input, args) {
var radix = args[0] || Base.DEFAULT_RADIX;
const radix = args[0] || Base.DEFAULT_RADIX;
if (radix < 2 || radix > 36) {
throw "Error: Radix argument must be between 2 and 36";
}
var number = input.replace(/\s/g, "").split("."),
let number = input.replace(/\s/g, "").split("."),
result = parseInt(number[0], radix) || 0;
if (number.length === 1) return result;
// Fractional part
for (var i = 0; i < number[1].length; i++) {
var digit = parseInt(number[1][i], radix);
for (let i = 0; i < number[1].length; i++) {
const digit = parseInt(number[1][i], radix);
result += digit / Math.pow(radix, i+1);
}

View File

@@ -40,7 +40,7 @@ const Base58 = {
* @returns {string}
*/
runTo: function(input, args) {
var alphabet = args[0] || Base58.ALPHABET_OPTIONS[0].value,
let alphabet = args[0] || Base58.ALPHABET_OPTIONS[0].value,
result = [0];
alphabet = Utils.expandAlphRange(alphabet).join("");
@@ -53,11 +53,11 @@ const Base58 = {
if (input.length === 0) return "";
input.forEach(function(b) {
var carry = (result[0] << 8) + b;
let carry = (result[0] << 8) + b;
result[0] = carry % 58;
carry = (carry / 58) | 0;
for (var i = 1; i < result.length; i++) {
for (let i = 1; i < result.length; i++) {
carry += result[i] << 8;
result[i] = carry % 58;
carry = (carry / 58) | 0;
@@ -89,7 +89,7 @@ const Base58 = {
* @returns {byteArray}
*/
runFrom: function(input, args) {
var alphabet = args[0] || Base58.ALPHABET_OPTIONS[0].value,
let alphabet = args[0] || Base58.ALPHABET_OPTIONS[0].value,
removeNonAlphaChars = args[1] === undefined ? true : args[1],
result = [0];
@@ -103,7 +103,7 @@ const Base58 = {
if (input.length === 0) return [];
[].forEach.call(input, function(c, charIndex) {
var index = alphabet.indexOf(c);
const index = alphabet.indexOf(c);
if (index === -1) {
if (removeNonAlphaChars) {
@@ -113,11 +113,11 @@ const Base58 = {
}
}
var carry = result[0] * 58 + index;
let carry = result[0] * 58 + index;
result[0] = carry & 0xFF;
carry = carry >> 8;
for (var i = 1; i < result.length; i++) {
for (let i = 1; i < result.length; i++) {
carry += result[i] * 58;
result[i] = carry & 0xFF;
carry = carry >> 8;

View File

@@ -45,7 +45,7 @@ const Base64 = {
* @returns {string}
*/
runTo: function(input, args) {
var alphabet = args[0] || Base64.ALPHABET;
const alphabet = args[0] || Base64.ALPHABET;
return Utils.toBase64(input, alphabet);
},
@@ -64,7 +64,7 @@ const Base64 = {
* @returns {byteArray}
*/
runFrom: function(input, args) {
var alphabet = args[0] || Base64.ALPHABET,
let alphabet = args[0] || Base64.ALPHABET,
removeNonAlphChars = args[1];
return Utils.fromBase64(input, alphabet, "byteArray", removeNonAlphChars);
@@ -87,7 +87,7 @@ const Base64 = {
runTo32: function(input, args) {
if (!input) return "";
var alphabet = args[0] ?
let alphabet = args[0] ?
Utils.expandAlphRange(args[0]).join("") : "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=",
output = "",
chr1, chr2, chr3, chr4, chr5,
@@ -139,17 +139,17 @@ const Base64 = {
runFrom32: function(input, args) {
if (!input) return [];
var alphabet = args[0] ?
let alphabet = args[0] ?
Utils.expandAlphRange(args[0]).join("") : "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567=",
removeNonAlphChars = args[0];
var output = [],
let output = [],
chr1, chr2, chr3, chr4, chr5,
enc1, enc2, enc3, enc4, enc5, enc6, enc7, enc8,
i = 0;
if (removeNonAlphChars) {
var re = new RegExp("[^" + alphabet.replace(/[\]\\\-^]/g, "\\$&") + "]", "g");
const re = new RegExp("[^" + alphabet.replace(/[\]\\\-^]/g, "\\$&") + "]", "g");
input = input.replace(re, "");
}
@@ -199,7 +199,7 @@ const Base64 = {
* @returns {html}
*/
runOffsets: function(input, args) {
var alphabet = args[0] || Base64.ALPHABET,
let alphabet = args[0] || Base64.ALPHABET,
showVariable = args[1],
offset0 = Utils.toBase64(input, alphabet),
offset1 = Utils.toBase64([0].concat(input), alphabet),
@@ -221,15 +221,15 @@ const Base64 = {
offset0 = "<span data-toggle='tooltip' data-placement='top' title='" +
Utils.escapeHtml(Utils.fromBase64(staticSection, alphabet).slice(0, -2)) + "'>" +
staticSection + "</span>" +
"<span class='hlgreen'>" + offset0.substr(offset0.length - 3, 1) + "</span>" +
"<span class='hlred'>" + offset0.substr(offset0.length - 2) + "</span>";
"<span class='hl5'>" + offset0.substr(offset0.length - 3, 1) + "</span>" +
"<span class='hl3'>" + offset0.substr(offset0.length - 2) + "</span>";
} else if (len0 % 4 === 3) {
staticSection = offset0.slice(0, -2);
offset0 = "<span data-toggle='tooltip' data-placement='top' title='" +
Utils.escapeHtml(Utils.fromBase64(staticSection, alphabet).slice(0, -1)) + "'>" +
staticSection + "</span>" +
"<span class='hlgreen'>" + offset0.substr(offset0.length - 2, 1) + "</span>" +
"<span class='hlred'>" + offset0.substr(offset0.length - 1) + "</span>";
"<span class='hl5'>" + offset0.substr(offset0.length - 2, 1) + "</span>" +
"<span class='hl3'>" + offset0.substr(offset0.length - 1) + "</span>";
} else {
staticSection = offset0;
offset0 = "<span data-toggle='tooltip' data-placement='top' title='" +
@@ -243,23 +243,23 @@ const Base64 = {
// Highlight offset 1
padding = "<span class='hlred'>" + offset1.substr(0, 1) + "</span>" +
"<span class='hlgreen'>" + offset1.substr(1, 1) + "</span>";
padding = "<span class='hl3'>" + offset1.substr(0, 1) + "</span>" +
"<span class='hl5'>" + offset1.substr(1, 1) + "</span>";
offset1 = offset1.substr(2);
if (len1 % 4 === 2) {
staticSection = offset1.slice(0, -3);
offset1 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
Utils.escapeHtml(Utils.fromBase64("AA" + staticSection, alphabet).slice(1, -2)) + "'>" +
staticSection + "</span>" +
"<span class='hlgreen'>" + offset1.substr(offset1.length - 3, 1) + "</span>" +
"<span class='hlred'>" + offset1.substr(offset1.length - 2) + "</span>";
"<span class='hl5'>" + offset1.substr(offset1.length - 3, 1) + "</span>" +
"<span class='hl3'>" + offset1.substr(offset1.length - 2) + "</span>";
} else if (len1 % 4 === 3) {
staticSection = offset1.slice(0, -2);
offset1 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
Utils.escapeHtml(Utils.fromBase64("AA" + staticSection, alphabet).slice(1, -1)) + "'>" +
staticSection + "</span>" +
"<span class='hlgreen'>" + offset1.substr(offset1.length - 2, 1) + "</span>" +
"<span class='hlred'>" + offset1.substr(offset1.length - 1) + "</span>";
"<span class='hl5'>" + offset1.substr(offset1.length - 2, 1) + "</span>" +
"<span class='hl3'>" + offset1.substr(offset1.length - 1) + "</span>";
} else {
staticSection = offset1;
offset1 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
@@ -272,23 +272,23 @@ const Base64 = {
}
// Highlight offset 2
padding = "<span class='hlred'>" + offset2.substr(0, 2) + "</span>" +
"<span class='hlgreen'>" + offset2.substr(2, 1) + "</span>";
padding = "<span class='hl3'>" + offset2.substr(0, 2) + "</span>" +
"<span class='hl5'>" + offset2.substr(2, 1) + "</span>";
offset2 = offset2.substr(3);
if (len2 % 4 === 2) {
staticSection = offset2.slice(0, -3);
offset2 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
Utils.escapeHtml(Utils.fromBase64("AAA" + staticSection, alphabet).slice(2, -2)) + "'>" +
staticSection + "</span>" +
"<span class='hlgreen'>" + offset2.substr(offset2.length - 3, 1) + "</span>" +
"<span class='hlred'>" + offset2.substr(offset2.length - 2) + "</span>";
"<span class='hl5'>" + offset2.substr(offset2.length - 3, 1) + "</span>" +
"<span class='hl3'>" + offset2.substr(offset2.length - 2) + "</span>";
} else if (len2 % 4 === 3) {
staticSection = offset2.slice(0, -2);
offset2 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
Utils.escapeHtml(Utils.fromBase64("AAA" + staticSection, alphabet).slice(2, -2)) + "'>" +
staticSection + "</span>" +
"<span class='hlgreen'>" + offset2.substr(offset2.length - 2, 1) + "</span>" +
"<span class='hlred'>" + offset2.substr(offset2.length - 1) + "</span>";
"<span class='hl5'>" + offset2.substr(offset2.length - 2, 1) + "</span>" +
"<span class='hl3'>" + offset2.substr(offset2.length - 1) + "</span>";
} else {
staticSection = offset2;
offset2 = padding + "<span data-toggle='tooltip' data-placement='top' title='" +
@@ -300,8 +300,8 @@ const Base64 = {
offset2 = staticSection;
}
return (showVariable ? "Characters highlighted in <span class='hlgreen'>green</span> could change if the input is surrounded by more data." +
"\nCharacters highlighted in <span class='hlred'>red</span> are for padding purposes only." +
return (showVariable ? "Characters highlighted in <span class='hl5'>green</span> could change if the input is surrounded by more data." +
"\nCharacters highlighted in <span class='hl3'>red</span> are for padding purposes only." +
"\nUnhighlighted characters are <span data-toggle='tooltip' data-placement='top' title='Tooltip on left'>static</span>." +
"\nHover over the static sections to see what they decode to on their own.\n" +
"\nOffset 0: " + offset0 +

View File

@@ -26,17 +26,19 @@ const BitwiseOp = {
*/
_bitOp: function (input, key, func, nullPreserving, scheme) {
if (!key || !key.length) key = [0];
var result = [],
let result = [],
x = null,
k = null,
o = null;
for (var i = 0; i < input.length; i++) {
for (let i = 0; i < input.length; i++) {
k = key[i % key.length];
o = input[i];
x = nullPreserving && (o === 0 || o === k) ? o : func(o, k);
result.push(x);
if (scheme !== "Standard" && !(nullPreserving && (o === 0 || o === k))) {
if (scheme &&
scheme !== "Standard" &&
!(nullPreserving && (o === 0 || o === k))) {
switch (scheme) {
case "Input differential":
key[i % key.length] = x;
@@ -76,7 +78,7 @@ const BitwiseOp = {
* @returns {byteArray}
*/
runXor: function (input, args) {
var key = Utils.format[args[0].option].parse(args[0].string || ""),
let key = Utils.format[args[0].option].parse(args[0].string || ""),
scheme = args[1],
nullPreserving = args[2];
@@ -120,19 +122,19 @@ const BitwiseOp = {
* @returns {string}
*/
runXorBrute: function (input, args) {
var keyLength = parseInt(args[0], 10),
const keyLength = parseInt(args[0], 10),
sampleLength = args[1],
sampleOffset = args[2],
nullPreserving = args[3],
differential = args[4],
crib = args[5],
printKey = args[6],
outputHex = args[7],
regex;
scheme = args[3],
nullPreserving = args[4],
printKey = args[5],
outputHex = args[6],
crib = args[7];
var output = "",
let output = "",
result,
resultUtf8;
resultUtf8,
regex;
input = input.slice(sampleOffset, sampleOffset + sampleLength);
@@ -141,15 +143,13 @@ const BitwiseOp = {
}
for (var key = 1, l = Math.pow(256, keyLength); key < l; key++) {
result = BitwiseOp._bitOp(input, Utils.hexToByteArray(key.toString(16)), BitwiseOp._xor, nullPreserving, differential);
for (let key = 1, l = Math.pow(256, keyLength); key < l; key++) {
result = BitwiseOp._bitOp(input, Utils.fromHex(key.toString(16)), BitwiseOp._xor, nullPreserving, scheme);
resultUtf8 = Utils.byteArrayToUtf8(result);
if (crib !== "" && resultUtf8.search(regex) === -1) continue;
if (printKey) output += "Key = " + Utils.hex(key, (2*keyLength)) + ": ";
if (outputHex)
output += Utils.byteArrayToHex(result) + "\n";
else
output += Utils.printable(resultUtf8, false) + "\n";
if (outputHex) output += Utils.toHex(result) + "\n";
else output += Utils.printable(resultUtf8, false) + "\n";
if (printKey) output += "\n";
}
return output;
@@ -176,7 +176,7 @@ const BitwiseOp = {
* @returns {byteArray}
*/
runAnd: function (input, args) {
var key = Utils.format[args[0].option].parse(args[0].string || "");
let key = Utils.format[args[0].option].parse(args[0].string || "");
key = Utils.wordArrayToByteArray(key);
return BitwiseOp._bitOp(input, key, BitwiseOp._and);
@@ -191,7 +191,7 @@ const BitwiseOp = {
* @returns {byteArray}
*/
runOr: function (input, args) {
var key = Utils.format[args[0].option].parse(args[0].string || "");
let key = Utils.format[args[0].option].parse(args[0].string || "");
key = Utils.wordArrayToByteArray(key);
return BitwiseOp._bitOp(input, key, BitwiseOp._or);
@@ -206,7 +206,7 @@ const BitwiseOp = {
* @returns {byteArray}
*/
runAdd: function (input, args) {
var key = Utils.format[args[0].option].parse(args[0].string || "");
let key = Utils.format[args[0].option].parse(args[0].string || "");
key = Utils.wordArrayToByteArray(key);
return BitwiseOp._bitOp(input, key, BitwiseOp._add);
@@ -221,7 +221,7 @@ const BitwiseOp = {
* @returns {byteArray}
*/
runSub: function (input, args) {
var key = Utils.format[args[0].option].parse(args[0].string || "");
let key = Utils.format[args[0].option].parse(args[0].string || "");
key = Utils.wordArrayToByteArray(key);
return BitwiseOp._bitOp(input, key, BitwiseOp._sub);
@@ -301,7 +301,7 @@ const BitwiseOp = {
* @returns {number}
*/
_sub: function (operand, key) {
var result = operand - key;
const result = operand - key;
return (result < 0) ? 256 + result : result;
},

View File

@@ -37,7 +37,7 @@ const ByteRepr = {
* @returns {string}
*/
runToHex: function(input, args) {
var delim = Utils.charRep[args[0] || "Space"];
const delim = Utils.charRep[args[0] || "Space"];
return Utils.toHex(input, delim, 2);
},
@@ -50,7 +50,7 @@ const ByteRepr = {
* @returns {byteArray}
*/
runFromHex: function(input, args) {
var delim = args[0] || "Space";
const delim = args[0] || "Space";
return Utils.fromHex(input, delim, 2);
},
@@ -58,13 +58,13 @@ const ByteRepr = {
/**
* To Octal operation.
*
* @author Matt C [matt@artemisbot.pw]
* @author Matt C [matt@artemisbot.uk]
* @param {byteArray} input
* @param {Object[]} args
* @returns {string}
*/
runToOct: function(input, args) {
var delim = Utils.charRep[args[0] || "Space"];
const delim = Utils.charRep[args[0] || "Space"];
return input.map(val => val.toString(8)).join(delim);
},
@@ -72,13 +72,13 @@ const ByteRepr = {
/**
* From Octal operation.
*
* @author Matt C [matt@artemisbot.pw]
* @author Matt C [matt@artemisbot.uk]
* @param {string} input
* @param {Object[]} args
* @returns {byteArray}
*/
runFromOct: function(input, args) {
var delim = Utils.charRep[args[0] || "Space"];
const delim = Utils.charRep[args[0] || "Space"];
if (input.length === 0) return [];
return input.split(delim).map(val => parseInt(val, 8));
},
@@ -98,7 +98,7 @@ const ByteRepr = {
* @returns {string}
*/
runToCharcode: function(input, args) {
var delim = Utils.charRep[args[0] || "Space"],
let delim = Utils.charRep[args[0] || "Space"],
base = args[1],
output = "",
padding = 2,
@@ -108,8 +108,9 @@ const ByteRepr = {
throw "Error: Base argument must be between 2 and 36";
}
for (var i = 0; i < input.length; i++) {
ordinal = Utils.ord(input[i]);
const charcode = Utils.strToCharcode(input);
for (let i = 0; i < charcode.length; i++) {
ordinal = charcode[i];
if (base === 16) {
if (ordinal < 256) padding = 2;
@@ -139,7 +140,7 @@ const ByteRepr = {
* @returns {byteArray}
*/
runFromCharcode: function(input, args) {
var delim = Utils.charRep[args[0] || "Space"],
let delim = Utils.charRep[args[0] || "Space"],
base = args[1],
bites = input.split(delim),
i = 0;
@@ -161,7 +162,7 @@ const ByteRepr = {
}
}
var latin1 = "";
let latin1 = "";
for (i = 0; i < bites.length; i++) {
latin1 += Utils.chr(parseInt(bites[i], base));
}
@@ -179,7 +180,7 @@ const ByteRepr = {
* @returns {Object[]} pos
*/
highlightTo: function(pos, args) {
var delim = Utils.charRep[args[0] || "Space"],
let delim = Utils.charRep[args[0] || "Space"],
len = delim === "\r\n" ? 1 : delim.length;
pos[0].start = pos[0].start * (2 + len);
@@ -204,7 +205,7 @@ const ByteRepr = {
* @returns {Object[]} pos
*/
highlightFrom: function(pos, args) {
var delim = Utils.charRep[args[0] || "Space"],
let delim = Utils.charRep[args[0] || "Space"],
len = delim === "\r\n" ? 1 : delim.length,
width = len + 2;
@@ -230,7 +231,7 @@ const ByteRepr = {
* @returns {string}
*/
runToDecimal: function(input, args) {
var delim = Utils.charRep[args[0]];
const delim = Utils.charRep[args[0]];
return input.join(delim);
},
@@ -243,12 +244,12 @@ const ByteRepr = {
* @returns {byteArray}
*/
runFromDecimal: function(input, args) {
var delim = Utils.charRep[args[0]];
var byteStr = input.split(delim), output = [];
const delim = Utils.charRep[args[0]];
let byteStr = input.split(delim), output = [];
if (byteStr[byteStr.length-1] === "")
byteStr = byteStr.slice(0, byteStr.length-1);
for (var i = 0; i < byteStr.length; i++) {
for (let i = 0; i < byteStr.length; i++) {
output[i] = parseInt(byteStr[i], 10);
}
return output;
@@ -263,11 +264,11 @@ const ByteRepr = {
* @returns {string}
*/
runToBinary: function(input, args) {
var delim = Utils.charRep[args[0] || "Space"],
let delim = Utils.charRep[args[0] || "Space"],
output = "",
padding = 8;
for (var i = 0; i < input.length; i++) {
for (let i = 0; i < input.length; i++) {
output += Utils.pad(input[i].toString(2), padding) + delim;
}
@@ -288,13 +289,13 @@ const ByteRepr = {
*/
runFromBinary: function(input, args) {
if (args[0] !== "None") {
var delimRegex = Utils.regexRep[args[0] || "Space"];
const delimRegex = Utils.regexRep[args[0] || "Space"];
input = input.replace(delimRegex, "");
}
var output = [];
var byteLen = 8;
for (var i = 0; i < input.length; i += byteLen) {
const output = [];
const byteLen = 8;
for (let i = 0; i < input.length; i += byteLen) {
output.push(parseInt(input.substr(i, byteLen), 2));
}
return output;
@@ -311,7 +312,7 @@ const ByteRepr = {
* @returns {Object[]} pos
*/
highlightToBinary: function(pos, args) {
var delim = Utils.charRep[args[0] || "Space"];
const delim = Utils.charRep[args[0] || "Space"];
pos[0].start = pos[0].start * (8 + delim.length);
pos[0].end = pos[0].end * (8 + delim.length) - delim.length;
return pos;
@@ -328,7 +329,7 @@ const ByteRepr = {
* @returns {Object[]} pos
*/
highlightFromBinary: function(pos, args) {
var delim = Utils.charRep[args[0] || "Space"];
const delim = Utils.charRep[args[0] || "Space"];
pos[0].start = pos[0].start === 0 ? 0 : Math.floor(pos[0].start / (8 + delim.length));
pos[0].end = pos[0].end === 0 ? 0 : Math.ceil(pos[0].end / (8 + delim.length));
return pos;
@@ -354,19 +355,19 @@ const ByteRepr = {
* @returns {string}
*/
runToHexContent: function(input, args) {
var convert = args[0];
var spaces = args[1];
const convert = args[0];
const spaces = args[1];
if (convert === "All chars") {
var result = "|" + Utils.toHex(input) + "|";
let result = "|" + Utils.toHex(input) + "|";
if (!spaces) result = result.replace(/ /g, "");
return result;
}
var output = "",
let output = "",
inHex = false,
convertSpaces = convert === "Only special chars including spaces",
b;
for (var i = 0; i < input.length; i++) {
for (let i = 0; i < input.length; i++) {
b = input[i];
if ((b === 32 && convertSpaces) || (b < 48 && b !== 32) || (b > 57 && b < 65) || (b > 90 && b < 97) || b > 122) {
if (!inHex) {
@@ -395,17 +396,17 @@ const ByteRepr = {
* @returns {byteArray}
*/
runFromHexContent: function(input, args) {
var regex = /\|([a-f\d ]{2,})\|/gi;
var output = [], m, i = 0;
const regex = /\|([a-f\d ]{2,})\|/gi;
let output = [], m, i = 0;
while ((m = regex.exec(input))) {
// Add up to match
for (; i < m.index;)
output.push(Utils.ord(input[i++]));
// Add match
var bytes = Utils.fromHex(m[1]);
const bytes = Utils.fromHex(m[1]);
if (bytes) {
for (var a = 0; a < bytes.length;)
for (let a = 0; a < bytes.length;)
output.push(bytes[a++]);
} else {
// Not valid hex, print as normal

View File

@@ -1,3 +1,4 @@
import cptable from "../lib/js-codepage/cptable.js";
import Utils from "../Utils.js";
import CryptoJS from "crypto-js";
@@ -17,34 +18,82 @@ const CharEnc = {
* @constant
* @default
*/
IO_FORMAT: ["UTF8", "UTF16", "UTF16LE", "UTF16BE", "Latin1", "Windows-1251", "Hex", "Base64"],
IO_FORMAT: {
"UTF-8 (65001)": 65001,
"UTF-7 (65000)": 65000,
"UTF16LE (1200)": 1200,
"UTF16BE (1201)": 1201,
"UTF16 (1201)": 1201,
"IBM EBCDIC International (500)": 500,
"IBM EBCDIC US-Canada (37)": 37,
"Windows-874 Thai (874)": 874,
"Japanese Shift-JIS (932)": 932,
"Simplified Chinese GBK (936)": 936,
"Korean (949)": 949,
"Traditional Chinese Big5 (950)": 950,
"Windows-1250 Central European (1250)": 1250,
"Windows-1251 Cyrillic (1251)": 1251,
"Windows-1252 Latin (1252)": 1252,
"Windows-1253 Greek (1253)": 1253,
"Windows-1254 Turkish (1254)": 1254,
"Windows-1255 Hebrew (1255)": 1255,
"Windows-1256 Arabic (1256)": 1256,
"Windows-1257 Baltic (1257)": 1257,
"Windows-1258 Vietnam (1258)": 1258,
"US-ASCII (20127)": 20127,
"Simplified Chinese GB2312 (20936)": 20936,
"KOI8-R Russian Cyrillic (20866)": 20866,
"KOI8-U Ukrainian Cyrillic (21866)": 21866,
"ISO-8859-1 Latin 1 Western European (28591)": 28591,
"ISO-8859-2 Latin 2 Central European (28592)": 28592,
"ISO-8859-3 Latin 3 South European (28593)": 28593,
"ISO-8859-4 Latin 4 North European (28594)": 28594,
"ISO-8859-5 Latin/Cyrillic (28595)": 28595,
"ISO-8859-6 Latin/Arabic (28596)": 28596,
"ISO-8859-7 Latin/Greek (28597)": 28597,
"ISO-8859-8 Latin/Hebrew (28598)": 28598,
"ISO-8859-9 Latin 5 Turkish (28599)": 28599,
"ISO-8859-10 Latin 6 Nordic (28600)": 28600,
"ISO-8859-11 Latin/Thai (28601)": 28601,
"ISO-8859-13 Latin 7 Baltic Rim (28603)": 28603,
"ISO-8859-14 Latin 8 Celtic (28604)": 28604,
"ISO-8859-15 Latin 9 (28605)": 28605,
"ISO-8859-16 Latin 10 (28606)": 28606,
"ISO-2022 JIS Japanese (50222)": 50222,
"EUC Japanese (51932)": 51932,
"EUC Korean (51949)": 51949,
"Simplified Chinese GB18030 (54936)": 54936,
},
/**
* Text encoding operation.
* Encode text operation.
* @author tlwr [toby@toby.codes]
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
* @returns {byteArray}
*/
run: function(input, args) {
var inputFormat = args[0],
outputFormat = args[1];
if (inputFormat === "Windows-1251") {
input = Utils.win1251ToUnicode(input);
input = CryptoJS.enc.Utf8.parse(input);
} else {
input = Utils.format[inputFormat].parse(input);
}
if (outputFormat === "Windows-1251") {
input = CryptoJS.enc.Utf8.stringify(input);
return Utils.unicodeToWin1251(input);
} else {
return Utils.format[outputFormat].stringify(input);
}
runEncode: function(input, args) {
const format = CharEnc.IO_FORMAT[args[0]];
let encoded = cptable.utils.encode(format, input);
encoded = Array.from(encoded);
return encoded;
},
/**
* Decode text operation.
* @author tlwr [toby@toby.codes]
*
* @param {byteArray} input
* @param {Object[]} args
* @returns {string}
*/
runDecode: function(input, args) {
const format = CharEnc.IO_FORMAT[args[0]];
let decoded = cptable.utils.decode(format, input);
return decoded;
},
};
export default CharEnc;

View File

@@ -20,10 +20,10 @@ const Checksum = {
* @returns {string}
*/
runFletcher8: function(input, args) {
var a = 0,
let a = 0,
b = 0;
for (var i = 0; i < input.length; i++) {
for (let i = 0; i < input.length; i++) {
a = (a + input[i]) % 0xf;
b = (b + a) % 0xf;
}
@@ -40,10 +40,10 @@ const Checksum = {
* @returns {string}
*/
runFletcher16: function(input, args) {
var a = 0,
let a = 0,
b = 0;
for (var i = 0; i < input.length; i++) {
for (let i = 0; i < input.length; i++) {
a = (a + input[i]) % 0xff;
b = (b + a) % 0xff;
}
@@ -60,10 +60,10 @@ const Checksum = {
* @returns {string}
*/
runFletcher32: function(input, args) {
var a = 0,
let a = 0,
b = 0;
for (var i = 0; i < input.length; i++) {
for (let i = 0; i < input.length; i++) {
a = (a + input[i]) % 0xffff;
b = (b + a) % 0xffff;
}
@@ -80,10 +80,10 @@ const Checksum = {
* @returns {string}
*/
runFletcher64: function(input, args) {
var a = 0,
let a = 0,
b = 0;
for (var i = 0; i < input.length; i++) {
for (let i = 0; i < input.length; i++) {
a = (a + input[i]) % 0xffffffff;
b = (b + a) % 0xffffffff;
}
@@ -100,11 +100,11 @@ const Checksum = {
* @returns {string}
*/
runAdler32: function(input, args) {
var MOD_ADLER = 65521,
let MOD_ADLER = 65521,
a = 1,
b = 0;
for (var i = 0; i < input.length; i++) {
for (let i = 0; i < input.length; i++) {
a += input[i];
b += a;
}
@@ -124,10 +124,10 @@ const Checksum = {
* @returns {string}
*/
runCRC32: function(input, args) {
var crcTable = global.crcTable || (global.crcTable = Checksum._genCRCTable()),
let crcTable = global.crcTable || (global.crcTable = Checksum._genCRCTable()),
crc = 0 ^ (-1);
for (var i = 0; i < input.length; i++) {
for (let i = 0; i < input.length; i++) {
crc = (crc >>> 8) ^ crcTable[(crc ^ input[i]) & 0xff];
}
@@ -153,9 +153,9 @@ const Checksum = {
* 0x00,0x00,0xac,0x11,0x00,0x03,0xac,0x11,0x00,0x04])
*/
runTCPIP: function(input, args) {
var csum = 0;
let csum = 0;
for (var i = 0; i < input.length; i++) {
for (let i = 0; i < input.length; i++) {
if (i % 2 === 0) {
csum += (input[i] << 8);
} else {
@@ -176,12 +176,12 @@ const Checksum = {
* @returns {array}
*/
_genCRCTable: function() {
var c,
let c,
crcTable = [];
for (var n = 0; n < 256; n++) {
for (let n = 0; n < 256; n++) {
c = n;
for (var k = 0; k < 8; k++) {
for (let k = 0; k < 8; k++) {
c = ((c & 1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));
}
crcTable[n] = c;

View File

@@ -61,7 +61,7 @@ const Cipher = {
* @returns {string}
*/
_enc: function (algo, input, args) {
var key = Utils.format[args[0].option].parse(args[0].string || ""),
let key = Utils.format[args[0].option].parse(args[0].string || ""),
iv = Utils.format[args[1].option].parse(args[1].string || ""),
salt = Utils.format[args[2].option].parse(args[2].string || ""),
mode = CryptoJS.mode[args[3]],
@@ -74,14 +74,14 @@ const Cipher = {
key = key.toString(CryptoJS.enc.Latin1);
}
var encrypted = algo.encrypt(input, key, {
const encrypted = algo.encrypt(input, key, {
salt: salt.sigBytes > 0 ? salt : false,
iv: iv.sigBytes > 0 ? iv : null,
mode: mode,
padding: padding
});
var result = "";
let result = "";
if (resultOption === "show all") {
result += "Key: " + encrypted.key.toString(Utils.format[outputFormat]);
result += "\nIV: " + encrypted.iv.toString(Utils.format[outputFormat]);
@@ -105,7 +105,7 @@ const Cipher = {
* @returns {string}
*/
_dec: function (algo, input, args) {
var key = Utils.format[args[0].option].parse(args[0].string || ""),
let key = Utils.format[args[0].option].parse(args[0].string || ""),
iv = Utils.format[args[1].option].parse(args[1].string || ""),
salt = Utils.format[args[2].option].parse(args[2].string || ""),
mode = CryptoJS.mode[args[3]],
@@ -118,14 +118,14 @@ const Cipher = {
return "No input";
}
var ciphertext = Utils.format[inputFormat].parse(input);
const ciphertext = Utils.format[inputFormat].parse(input);
if (iv.sigBytes === 0) {
// Use passphrase rather than key. Need to convert it to a string.
key = key.toString(CryptoJS.enc.Latin1);
}
var decrypted = algo.decrypt({
const decrypted = algo.decrypt({
ciphertext: ciphertext,
salt: salt.sigBytes > 0 ? salt : false
}, key, {
@@ -134,7 +134,7 @@ const Cipher = {
padding: padding
});
var result;
let result;
try {
result = decrypted.toString(Utils.format[outputFormat]);
} catch (err) {
@@ -260,13 +260,13 @@ const Cipher = {
* @returns {string}
*/
runBlowfishEnc: function (input, args) {
var key = Utils.format[args[0].option].parse(args[0].string).toString(Utils.format.Latin1),
let key = Utils.format[args[0].option].parse(args[0].string).toString(Utils.format.Latin1),
mode = args[1],
outputFormat = args[2];
if (key.length === 0) return "Enter a key";
var encHex = Blowfish.encrypt(input, key, {
let encHex = Blowfish.encrypt(input, key, {
outputType: 1,
cipherMode: Cipher.BLOWFISH_MODES.indexOf(mode)
}),
@@ -284,7 +284,7 @@ const Cipher = {
* @returns {string}
*/
runBlowfishDec: function (input, args) {
var key = Utils.format[args[0].option].parse(args[0].string).toString(Utils.format.Latin1),
let key = Utils.format[args[0].option].parse(args[0].string).toString(Utils.format.Latin1),
mode = args[1],
inputFormat = args[2];
@@ -309,6 +309,11 @@ const Cipher = {
* @default
*/
KDF_ITERATIONS: 1,
/**
* @constant
* @default
*/
HASHERS: ["MD5", "SHA1", "SHA224", "SHA256", "SHA384", "SHA512", "SHA3", "RIPEMD160"],
/**
* Derive PBKDF2 key operation.
@@ -318,13 +323,18 @@ const Cipher = {
* @returns {string}
*/
runPbkdf2: function (input, args) {
var keySize = args[0] / 32,
let keySize = args[0] / 32,
iterations = args[1],
salt = CryptoJS.enc.Hex.parse(args[2] || ""),
inputFormat = args[3],
outputFormat = args[4],
hasher = args[2],
salt = CryptoJS.enc.Hex.parse(args[3] || ""),
inputFormat = args[4],
outputFormat = args[5],
passphrase = Utils.format[inputFormat].parse(input),
key = CryptoJS.PBKDF2(passphrase, salt, { keySize: keySize, iterations: iterations });
key = CryptoJS.PBKDF2(passphrase, salt, {
keySize: keySize,
hasher: CryptoJS.algo[hasher],
iterations: iterations,
});
return key.toString(Utils.format[outputFormat]);
},
@@ -338,13 +348,18 @@ const Cipher = {
* @returns {string}
*/
runEvpkdf: function (input, args) {
var keySize = args[0] / 32,
let keySize = args[0] / 32,
iterations = args[1],
salt = CryptoJS.enc.Hex.parse(args[2] || ""),
inputFormat = args[3],
outputFormat = args[4],
hasher = args[2],
salt = CryptoJS.enc.Hex.parse(args[3] || ""),
inputFormat = args[4],
outputFormat = args[5],
passphrase = Utils.format[inputFormat].parse(input),
key = CryptoJS.EvpKDF(passphrase, salt, { keySize: keySize, iterations: iterations });
key = CryptoJS.EvpKDF(passphrase, salt, {
keySize: keySize,
hasher: CryptoJS.algo[hasher],
iterations: iterations,
});
return key.toString(Utils.format[outputFormat]);
},
@@ -358,7 +373,7 @@ const Cipher = {
* @returns {string}
*/
runRc4: function (input, args) {
var message = Utils.format[args[1]].parse(input),
let message = Utils.format[args[1]].parse(input),
passphrase = Utils.format[args[0].option].parse(args[0].string),
encrypted = CryptoJS.RC4.encrypt(message, passphrase);
@@ -380,7 +395,7 @@ const Cipher = {
* @returns {string}
*/
runRc4drop: function (input, args) {
var message = Utils.format[args[1]].parse(input),
let message = Utils.format[args[1]].parse(input),
passphrase = Utils.format[args[0].option].parse(args[0].string),
drop = args[3],
encrypted = CryptoJS.RC4Drop.encrypt(message, passphrase, { drop: drop });
@@ -392,13 +407,13 @@ const Cipher = {
/**
* Vigenère Encode operation.
*
* @author Matt C [matt@artemisbot.pw]
* @author Matt C [matt@artemisbot.uk]
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
runVigenereEnc: function (input, args) {
var alphabet = "abcdefghijklmnopqrstuvwxyz",
let alphabet = "abcdefghijklmnopqrstuvwxyz",
key = args[0].toLowerCase(),
output = "",
fail = 0,
@@ -409,7 +424,7 @@ const Cipher = {
if (!key) return "No key entered";
if (!/^[a-zA-Z]+$/.test(key)) return "The key must consist only of letters";
for (var i = 0; i < input.length; i++) {
for (let i = 0; i < input.length; i++) {
if (alphabet.indexOf(input[i]) >= 0) {
// Get the corresponding character of key for the current letter, accounting
// for chars not in alphabet
@@ -439,13 +454,13 @@ const Cipher = {
/**
* Vigenère Decode operation.
*
* @author Matt C [matt@artemisbot.pw]
* @author Matt C [matt@artemisbot.uk]
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
runVigenereDec: function (input, args) {
var alphabet = "abcdefghijklmnopqrstuvwxyz",
let alphabet = "abcdefghijklmnopqrstuvwxyz",
key = args[0].toLowerCase(),
output = "",
fail = 0,
@@ -456,7 +471,7 @@ const Cipher = {
if (!key) return "No key entered";
if (!/^[a-zA-Z]+$/.test(key)) return "The key must consist only of letters";
for (var i = 0; i < input.length; i++) {
for (let i = 0; i < input.length; i++) {
if (alphabet.indexOf(input[i]) >= 0) {
chr = key[(i - fail) % key.length];
keyIndex = alphabet.indexOf(chr);
@@ -493,13 +508,13 @@ const Cipher = {
/**
* Affine Cipher Encode operation.
*
* @author Matt C [matt@artemisbot.pw]
* @author Matt C [matt@artemisbot.uk]
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
runAffineEnc: function (input, args) {
var alphabet = "abcdefghijklmnopqrstuvwxyz",
let alphabet = "abcdefghijklmnopqrstuvwxyz",
a = args[0],
b = args[1],
output = "";
@@ -508,7 +523,7 @@ const Cipher = {
return "The values of a and b can only be integers.";
}
for (var i = 0; i < input.length; i++) {
for (let i = 0; i < input.length; i++) {
if (alphabet.indexOf(input[i]) >= 0) {
// Uses the affine function ax+b % m = y (where m is length of the alphabet)
output += alphabet[((a * alphabet.indexOf(input[i])) + b) % 26];
@@ -525,15 +540,15 @@ const Cipher = {
/**
* Affine Cipher Encode operation.
* Affine Cipher Decode operation.
*
* @author Matt C [matt@artemisbot.pw]
* @author Matt C [matt@artemisbot.uk]
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
runAffineDec: function (input, args) {
var alphabet = "abcdefghijklmnopqrstuvwxyz",
let alphabet = "abcdefghijklmnopqrstuvwxyz",
a = args[0],
b = args[1],
output = "",
@@ -550,7 +565,7 @@ const Cipher = {
// Calculates modular inverse of a
aModInv = Utils.modInv(a, 26);
for (var i = 0; i < input.length; i++) {
for (let i = 0; i < input.length; i++) {
if (alphabet.indexOf(input[i]) >= 0) {
// Uses the affine decode function (y-b * A') % m = x (where m is length of the alphabet and A' is modular inverse)
output += alphabet[Utils.mod((alphabet.indexOf(input[i]) - b) * aModInv, 26)];
@@ -569,7 +584,7 @@ const Cipher = {
/**
* Atbash Cipher Encode operation.
*
* @author Matt C [matt@artemisbot.pw]
* @author Matt C [matt@artemisbot.uk]
* @param {string} input
* @param {Object[]} args
* @returns {string}
@@ -579,6 +594,159 @@ const Cipher = {
},
/**
* Generates a polybius square for the given keyword
*
* @private
* @author Matt C [matt@artemisbot.uk]
* @param {string} keyword - Must be upper case
* @returns {string}
*/
_genPolybiusSquare: function (keyword) {
const alpha = "ABCDEFGHIKLMNOPQRSTUVWXYZ";
const polArray = `${keyword}${alpha}`.split("").unique();
let polybius = [];
for (let i = 0; i < 5; i++) {
polybius[i] = polArray.slice(i*5, i*5 + 5);
}
return polybius;
},
/**
* Bifid Cipher Encode operation
*
* @author Matt C [matt@artemisbot.uk]
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
runBifidEnc: function (input, args) {
const keywordStr = args[0].toUpperCase().replace("J", "I"),
keyword = keywordStr.split("").unique(),
alpha = "ABCDEFGHIKLMNOPQRSTUVWXYZ";
let output = "",
xCo = [],
yCo = [],
structure = [],
count = 0;
if (keyword.length > 25)
return "The alphabet keyword must be less than 25 characters.";
if (!/^[a-zA-Z]+$/.test(keywordStr) && keyword.length > 0)
return "The key must consist only of letters";
const polybius = Cipher._genPolybiusSquare(keywordStr);
input.replace("J", "I").split("").forEach(letter => {
let alpInd = alpha.split("").indexOf(letter.toLocaleUpperCase()) >= 0,
polInd;
if (alpInd) {
for (let i = 0; i < 5; i++) {
polInd = polybius[i].indexOf(letter.toLocaleUpperCase());
if (polInd >= 0) {
xCo.push(polInd);
yCo.push(i);
}
}
if (alpha.split("").indexOf(letter) >= 0) {
structure.push(true);
} else if (alpInd) {
structure.push(false);
}
} else {
structure.push(letter);
}
});
const trans = `${yCo.join("")}${xCo.join("")}`;
structure.forEach(pos => {
if (typeof pos === "boolean") {
let coords = trans.substr(2*count, 2).split("");
output += pos ?
polybius[coords[0]][coords[1]] :
polybius[coords[0]][coords[1]].toLocaleLowerCase();
count++;
} else {
output += pos;
}
});
return output;
},
/**
* Bifid Cipher Decode operation
*
* @author Matt C [matt@artemisbot.uk]
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
runBifidDec: function (input, args) {
const keywordStr = args[0].toUpperCase().replace("J", "I"),
keyword = keywordStr.split("").unique(),
alpha = "ABCDEFGHIKLMNOPQRSTUVWXYZ";
let output = "",
structure = [],
count = 0,
trans = "";
if (keyword.length > 25)
return "The alphabet keyword must be less than 25 characters.";
if (!/^[a-zA-Z]+$/.test(keywordStr) && keyword.length > 0)
return "The key must consist only of letters";
const polybius = Cipher._genPolybiusSquare(keywordStr);
input.replace("J", "I").split("").forEach((letter) => {
let alpInd = alpha.split("").indexOf(letter.toLocaleUpperCase()) >= 0,
polInd;
if (alpInd) {
for (let i = 0; i < 5; i++) {
polInd = polybius[i].indexOf(letter.toLocaleUpperCase());
if (polInd >= 0) {
trans += `${i}${polInd}`;
}
}
if (alpha.split("").indexOf(letter) >= 0) {
structure.push(true);
} else if (alpInd) {
structure.push(false);
}
} else {
structure.push(letter);
}
});
structure.forEach(pos => {
if (typeof pos === "boolean") {
let coords = [trans[count], trans[count+trans.length/2]];
output += pos ?
polybius[coords[0]][coords[1]] :
polybius[coords[0]][coords[1]].toLocaleLowerCase();
count++;
} else {
output += pos;
}
});
return output;
},
/**
* @constant
* @default
@@ -593,23 +761,23 @@ const Cipher = {
/**
* Substitute operation.
*
* @param {byteArray} input
* @param {string} input
* @param {Object[]} args
* @returns {byteArray}
* @returns {string}
*/
runSubstitute: function (input, args) {
var plaintext = Utils.strToByteArray(Utils.expandAlphRange(args[0]).join()),
ciphertext = Utils.strToByteArray(Utils.expandAlphRange(args[1]).join()),
output = [],
let plaintext = Utils.expandAlphRange(args[0]).join(),
ciphertext = Utils.expandAlphRange(args[1]).join(),
output = "",
index = -1;
if (plaintext.length !== ciphertext.length) {
output = Utils.strToByteArray("Warning: Plaintext and Ciphertext lengths differ\n\n");
output = "Warning: Plaintext and Ciphertext lengths differ\n\n";
}
for (var i = 0; i < input.length; i++) {
for (let i = 0; i < input.length; i++) {
index = plaintext.indexOf(input[i]);
output.push(index > -1 && index < ciphertext.length ? ciphertext[index] : input[i]);
output += index > -1 && index < ciphertext.length ? ciphertext[index] : input[i];
}
return output;
@@ -650,10 +818,10 @@ CryptoJS.kdf.OpenSSL.execute = function (password, keySize, ivSize, salt) {
}
// Derive key and IV
var key = CryptoJS.algo.EvpKDF.create({ keySize: keySize + ivSize }).compute(password, salt);
const key = CryptoJS.algo.EvpKDF.create({ keySize: keySize + ivSize }).compute(password, salt);
// Separate key and IV
var iv = CryptoJS.lib.WordArray.create(key.words.slice(keySize), ivSize * 4);
const iv = CryptoJS.lib.WordArray.create(key.words.slice(keySize), ivSize * 4);
key.sigBytes = keySize * 4;
// Return params

View File

@@ -1,7 +1,10 @@
import {camelCase, kebabCase, snakeCase} from "lodash";
import Utils from "../Utils.js";
import vkbeautify from "vkbeautify";
import {DOMParser as dom} from "xmldom";
import xpath from "xpath";
import jpath from "jsonpath";
import prettyPrintOne from "imports-loader?window=>global!exports-loader?prettyPrintOne!google-code-prettify/bin/prettify.min.js";
@@ -35,7 +38,7 @@ const Code = {
* @returns {html}
*/
runSyntaxHighlight: function(input, args) {
var language = args[0],
let language = args[0],
lineNums = args[1];
return "<code class='prettyprint'>" + prettyPrintOne(Utils.escapeHtml(input), language, lineNums) + "</code>";
},
@@ -55,7 +58,7 @@ const Code = {
* @returns {string}
*/
runXmlBeautify: function(input, args) {
var indentStr = args[0];
const indentStr = args[0];
return vkbeautify.xml(input, indentStr);
},
@@ -68,7 +71,7 @@ const Code = {
* @returns {string}
*/
runJsonBeautify: function(input, args) {
var indentStr = args[0];
const indentStr = args[0];
if (!input) return "";
return vkbeautify.json(input, indentStr);
},
@@ -82,7 +85,7 @@ const Code = {
* @returns {string}
*/
runCssBeautify: function(input, args) {
var indentStr = args[0];
const indentStr = args[0];
return vkbeautify.css(input, indentStr);
},
@@ -95,7 +98,7 @@ const Code = {
* @returns {string}
*/
runSqlBeautify: function(input, args) {
var indentStr = args[0];
const indentStr = args[0];
return vkbeautify.sql(input, indentStr);
},
@@ -114,7 +117,7 @@ const Code = {
* @returns {string}
*/
runXmlMinify: function(input, args) {
var preserveComments = args[0];
const preserveComments = args[0];
return vkbeautify.xmlmin(input, preserveComments);
},
@@ -140,7 +143,7 @@ const Code = {
* @returns {string}
*/
runCssMinify: function(input, args) {
var preserveComments = args[0];
const preserveComments = args[0];
return vkbeautify.cssmin(input, preserveComments);
},
@@ -181,73 +184,69 @@ const Code = {
* @returns {string}
*/
runGenericBeautify: function(input, args) {
var code = input,
let code = input,
t = 0,
preservedTokens = [],
m;
// Remove strings
var sstrings = /'([^'\\]|\\.)*'/g;
const sstrings = /'([^'\\]|\\.)*'/g;
while ((m = sstrings.exec(code))) {
code = preserveToken(code, m, t++);
sstrings.lastIndex = m.index;
}
var dstrings = /"([^"\\]|\\.)*"/g;
const dstrings = /"([^"\\]|\\.)*"/g;
while ((m = dstrings.exec(code))) {
code = preserveToken(code, m, t++);
dstrings.lastIndex = m.index;
}
// Remove comments
var scomments = /\/\/[^\n\r]*/g;
const scomments = /\/\/[^\n\r]*/g;
while ((m = scomments.exec(code))) {
code = preserveToken(code, m, t++);
scomments.lastIndex = m.index;
}
var mcomments = /\/\*[\s\S]*?\*\//gm;
const mcomments = /\/\*[\s\S]*?\*\//gm;
while ((m = mcomments.exec(code))) {
code = preserveToken(code, m, t++);
mcomments.lastIndex = m.index;
}
var hcomments = /(^|\n)#[^\n\r#]+/g;
const hcomments = /(^|\n)#[^\n\r#]+/g;
while ((m = hcomments.exec(code))) {
code = preserveToken(code, m, t++);
hcomments.lastIndex = m.index;
}
// Remove regexes
var regexes = /\/.*?[^\\]\/[gim]{0,3}/gi;
const regexes = /\/.*?[^\\]\/[gim]{0,3}/gi;
while ((m = regexes.exec(code))) {
code = preserveToken(code, m, t++);
regexes.lastIndex = m.index;
}
// Create newlines after ;
code = code.replace(/;/g, ";\n");
// Create newlines after { and around }
code = code.replace(/{/g, "{\n");
code = code.replace(/}/g, "\n}\n");
// Remove carriage returns
code = code.replace(/\r/g, "");
// Remove all indentation
code = code.replace(/^\s+/g, "");
code = code.replace(/\n\s+/g, "\n");
// Remove trailing spaces
code = code.replace(/\s*$/g, "");
// Remove newlines before {
code = code.replace(/\n{/g, "{");
code = code
// Create newlines after ;
.replace(/;/g, ";\n")
// Create newlines after { and around }
.replace(/{/g, "{\n")
.replace(/}/g, "\n}\n")
// Remove carriage returns
.replace(/\r/g, "")
// Remove all indentation
.replace(/^\s+/g, "")
.replace(/\n\s+/g, "\n")
// Remove trailing spaces
.replace(/\s*$/g, "")
.replace(/\n{/g, "{");
// Indent
var i = 0,
level = 0;
let i = 0,
level = 0,
indent;
while (i < code.length) {
switch (code[i]) {
case "{":
@@ -257,7 +256,7 @@ const Code = {
if (i+1 >= code.length) break;
if (code[i+1] === "}") level--;
var indent = (level >= 0) ? Array(level*4+1).join(" ") : "";
indent = (level >= 0) ? Array(level*4+1).join(" ") : "";
code = code.substring(0, i+1) + indent + code.substring(i+1);
if (level > 0) i += level*4;
@@ -266,35 +265,33 @@ const Code = {
i++;
}
// Add strategic spaces
code = code.replace(/\s*([!<>=+-/*]?)=\s*/g, " $1= ");
code = code.replace(/\s*<([=]?)\s*/g, " <$1 ");
code = code.replace(/\s*>([=]?)\s*/g, " >$1 ");
code = code.replace(/([^+])\+([^+=])/g, "$1 + $2");
code = code.replace(/([^-])-([^-=])/g, "$1 - $2");
code = code.replace(/([^*])\*([^*=])/g, "$1 * $2");
code = code.replace(/([^/])\/([^/=])/g, "$1 / $2");
code = code.replace(/\s*,\s*/g, ", ");
code = code.replace(/\s*{/g, " {");
code = code.replace(/}\n/g, "}\n\n");
// Just... don't look at this
code = code.replace(/(if|for|while|with|elif|elseif)\s*\(([^\n]*)\)\s*\n([^{])/gim, "$1 ($2)\n $3");
code = code.replace(/(if|for|while|with|elif|elseif)\s*\(([^\n]*)\)([^{])/gim, "$1 ($2) $3");
code = code.replace(/else\s*\n([^{])/gim, "else\n $1");
code = code.replace(/else\s+([^{])/gim, "else $1");
// Remove strategic spaces
code = code.replace(/\s+;/g, ";");
code = code.replace(/\{\s+\}/g, "{}");
code = code.replace(/\[\s+\]/g, "[]");
code = code.replace(/}\s*(else|catch|except|finally|elif|elseif|else if)/gi, "} $1");
code = code
// Add strategic spaces
.replace(/\s*([!<>=+-/*]?)=\s*/g, " $1= ")
.replace(/\s*<([=]?)\s*/g, " <$1 ")
.replace(/\s*>([=]?)\s*/g, " >$1 ")
.replace(/([^+])\+([^+=])/g, "$1 + $2")
.replace(/([^-])-([^-=])/g, "$1 - $2")
.replace(/([^*])\*([^*=])/g, "$1 * $2")
.replace(/([^/])\/([^/=])/g, "$1 / $2")
.replace(/\s*,\s*/g, ", ")
.replace(/\s*{/g, " {")
.replace(/}\n/g, "}\n\n")
// Hacky horribleness
.replace(/(if|for|while|with|elif|elseif)\s*\(([^\n]*)\)\s*\n([^{])/gim, "$1 ($2)\n $3")
.replace(/(if|for|while|with|elif|elseif)\s*\(([^\n]*)\)([^{])/gim, "$1 ($2) $3")
.replace(/else\s*\n([^{])/gim, "else\n $1")
.replace(/else\s+([^{])/gim, "else $1")
// Remove strategic spaces
.replace(/\s+;/g, ";")
.replace(/\{\s+\}/g, "{}")
.replace(/\[\s+\]/g, "[]")
.replace(/}\s*(else|catch|except|finally|elif|elseif|else if)/gi, "} $1");
// Replace preserved tokens
var ptokens = /###preservedToken(\d+)###/g;
const ptokens = /###preservedToken(\d+)###/g;
while ((m = ptokens.exec(code))) {
var ti = parseInt(m[1], 10);
const ti = parseInt(m[1], 10);
code = code.substring(0, m.index) + preservedTokens[ti] + code.substring(m.index + m[0].length);
ptokens.lastIndex = m.index;
}
@@ -333,25 +330,25 @@ const Code = {
* @param {Object[]} args
* @returns {string}
*/
runXpath:function(input, args) {
var query = args[0],
runXpath: function(input, args) {
let query = args[0],
delimiter = args[1];
var doc;
let doc;
try {
doc = new dom().parseFromString(input);
} catch (err) {
return "Invalid input XML.";
}
var nodes;
let nodes;
try {
nodes = xpath.select(query, doc);
} catch (err) {
return "Invalid XPath. Details:\n" + err.message;
}
var nodeToString = function(node) {
const nodeToString = function(node) {
return node.toString();
};
@@ -359,6 +356,48 @@ const Code = {
},
/**
* @constant
* @default
*/
JPATH_INITIAL: "",
/**
* @constant
* @default
*/
JPATH_DELIMITER: "\\n",
/**
* JPath expression operation.
*
* @author Matt C (matt@artemisbot.uk)
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
runJpath: function(input, args) {
let query = args[0],
delimiter = args[1],
results,
obj;
try {
obj = JSON.parse(input);
} catch (err) {
return "Invalid input JSON: " + err.message;
}
try {
results = jpath.query(obj, query);
} catch (err) {
return "Invalid JPath expression: " + err.message;
}
return results.map(result => JSON.stringify(result)).join(delimiter);
},
/**
* @constant
* @default
@@ -381,7 +420,7 @@ const Code = {
* @returns {string}
*/
runCSSQuery: function(input, args) {
var query = args[0],
let query = args[0],
delimiter = args[1],
parser = new DOMParser(),
html,
@@ -403,7 +442,7 @@ const Code = {
return "Invalid CSS Selector. Details:\n" + err.message;
}
var nodeToString = function(node) {
const nodeToString = function(node) {
switch (node.nodeType) {
case Node.ELEMENT_NODE: return node.outerHTML;
case Node.ATTRIBUTE_NODE: return node.value;
@@ -422,6 +461,84 @@ const Code = {
.join(delimiter);
},
/**
* This tries to rename variable names in a code snippet according to a function.
*
* @param {string} input
* @param {function} replacer - this function will be fed the token which should be renamed.
* @returns {string}
*/
_replaceVariableNames(input, replacer) {
const tokenRegex = /\\"|"(?:\\"|[^"])*"|(\b[a-z0-9\-_]+\b)/ig;
return input.replace(tokenRegex, (...args) => {
let match = args[0],
quotes = args[1];
if (!quotes) {
return match;
} else {
return replacer(match);
}
});
},
/**
* Converts to snake_case.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*
*/
runToSnakeCase(input, args) {
const smart = args[0];
if (smart) {
return Code._replaceVariableNames(input, snakeCase);
} else {
return snakeCase(input);
}
},
/**
* Converts to camelCase.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*
*/
runToCamelCase(input, args) {
const smart = args[0];
if (smart) {
return Code._replaceVariableNames(input, camelCase);
} else {
return camelCase(input);
}
},
/**
* Converts to kebab-case.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*
*/
runToKebabCase(input, args) {
const smart = args[0];
if (smart) {
return Code._replaceVariableNames(input, kebabCase);
} else {
return kebabCase(input);
}
},
};
export default Code;

View File

@@ -6,15 +6,15 @@ import zip from "zlibjs/bin/zip.min";
import unzip from "zlibjs/bin/unzip.min";
import bzip2 from "exports-loader?bzip2!../lib/bzip2.js";
var Zlib = {
const Zlib = {
RawDeflate: rawdeflate.Zlib.RawDeflate,
RawInflate: rawinflate.Zlib.RawInflate,
Deflate: zlibAndGzip.Zlib.Deflate,
Inflate: zlibAndGzip.Zlib.Inflate,
Gzip: zlibAndGzip.Zlib.Gzip,
Gunzip: zlibAndGzip.Zlib.Gunzip,
Zip: zip.Zlib.Zip,
Unzip: unzip.Zlib.Unzip,
Deflate: zlibAndGzip.Zlib.Deflate,
Inflate: zlibAndGzip.Zlib.Inflate,
Gzip: zlibAndGzip.Zlib.Gzip,
Gunzip: zlibAndGzip.Zlib.Gunzip,
Zip: zip.Zlib.Zip,
Unzip: unzip.Zlib.Unzip,
};
@@ -54,9 +54,9 @@ const Compress = {
* @default
*/
RAW_COMPRESSION_TYPE_LOOKUP: {
"Fixed Huffman Coding" : Zlib.RawDeflate.CompressionType.FIXED,
"Dynamic Huffman Coding" : Zlib.RawDeflate.CompressionType.DYNAMIC,
"None (Store)" : Zlib.RawDeflate.CompressionType.NONE,
"Fixed Huffman Coding": Zlib.RawDeflate.CompressionType.FIXED,
"Dynamic Huffman Coding": Zlib.RawDeflate.CompressionType.DYNAMIC,
"None (Store)": Zlib.RawDeflate.CompressionType.NONE,
},
/**
@@ -67,7 +67,7 @@ const Compress = {
* @returns {byteArray}
*/
runRawDeflate: function(input, args) {
var deflate = new Zlib.RawDeflate(input, {
const deflate = new Zlib.RawDeflate(input, {
compressionType: Compress.RAW_COMPRESSION_TYPE_LOOKUP[args[0]]
});
return Array.prototype.slice.call(deflate.compress());
@@ -99,8 +99,8 @@ const Compress = {
* @default
*/
RAW_BUFFER_TYPE_LOOKUP: {
"Adaptive" : Zlib.RawInflate.BufferType.ADAPTIVE,
"Block" : Zlib.RawInflate.BufferType.BLOCK,
"Adaptive": Zlib.RawInflate.BufferType.ADAPTIVE,
"Block": Zlib.RawInflate.BufferType.BLOCK,
},
/**
@@ -113,7 +113,7 @@ const Compress = {
runRawInflate: function(input, args) {
// Deal with character encoding issues
input = Utils.strToByteArray(Utils.byteArrayToUtf8(input));
var inflate = new Zlib.RawInflate(input, {
let inflate = new Zlib.RawInflate(input, {
index: args[0],
bufferSize: args[1],
bufferType: Compress.RAW_BUFFER_TYPE_LOOKUP[args[2]],
@@ -129,8 +129,8 @@ const Compress = {
if (result.length > 158 && result[0] === 93 && result[5] === 93) {
// If the first two square brackets are there, check that the others
// are also there. If they are, throw an error. If not, continue.
var valid = false;
for (var i = 0; i < 155; i += 5) {
let valid = false;
for (let i = 0; i < 155; i += 5) {
if (result[i] !== 93) {
valid = true;
}
@@ -150,9 +150,9 @@ const Compress = {
* @default
*/
ZLIB_COMPRESSION_TYPE_LOOKUP: {
"Fixed Huffman Coding" : Zlib.Deflate.CompressionType.FIXED,
"Dynamic Huffman Coding" : Zlib.Deflate.CompressionType.DYNAMIC,
"None (Store)" : Zlib.Deflate.CompressionType.NONE,
"Fixed Huffman Coding": Zlib.Deflate.CompressionType.FIXED,
"Dynamic Huffman Coding": Zlib.Deflate.CompressionType.DYNAMIC,
"None (Store)": Zlib.Deflate.CompressionType.NONE,
},
/**
@@ -163,7 +163,7 @@ const Compress = {
* @returns {byteArray}
*/
runZlibDeflate: function(input, args) {
var deflate = new Zlib.Deflate(input, {
const deflate = new Zlib.Deflate(input, {
compressionType: Compress.ZLIB_COMPRESSION_TYPE_LOOKUP[args[0]]
});
return Array.prototype.slice.call(deflate.compress());
@@ -175,8 +175,8 @@ const Compress = {
* @default
*/
ZLIB_BUFFER_TYPE_LOOKUP: {
"Adaptive" : Zlib.Inflate.BufferType.ADAPTIVE,
"Block" : Zlib.Inflate.BufferType.BLOCK,
"Adaptive": Zlib.Inflate.BufferType.ADAPTIVE,
"Block": Zlib.Inflate.BufferType.BLOCK,
},
/**
@@ -189,7 +189,7 @@ const Compress = {
runZlibInflate: function(input, args) {
// Deal with character encoding issues
input = Utils.strToByteArray(Utils.byteArrayToUtf8(input));
var inflate = new Zlib.Inflate(input, {
const inflate = new Zlib.Inflate(input, {
index: args[0],
bufferSize: args[1],
bufferType: Compress.ZLIB_BUFFER_TYPE_LOOKUP[args[2]],
@@ -214,7 +214,7 @@ const Compress = {
* @returns {byteArray}
*/
runGzip: function(input, args) {
var filename = args[1],
let filename = args[1],
comment = args[2],
options = {
deflateOptions: {
@@ -234,7 +234,7 @@ const Compress = {
options.comment = comment;
}
var gzip = new Zlib.Gzip(input, options);
const gzip = new Zlib.Gzip(input, options);
return Array.prototype.slice.call(gzip.compress());
},
@@ -249,7 +249,7 @@ const Compress = {
runGunzip: function(input, args) {
// Deal with character encoding issues
input = Utils.strToByteArray(Utils.byteArrayToUtf8(input));
var gunzip = new Zlib.Gunzip(input);
const gunzip = new Zlib.Gunzip(input);
return Array.prototype.slice.call(gunzip.decompress());
},
@@ -264,17 +264,17 @@ const Compress = {
* @default
*/
ZIP_COMPRESSION_METHOD_LOOKUP: {
"Deflate" : Zlib.Zip.CompressionMethod.DEFLATE,
"None (Store)" : Zlib.Zip.CompressionMethod.STORE
"Deflate": Zlib.Zip.CompressionMethod.DEFLATE,
"None (Store)": Zlib.Zip.CompressionMethod.STORE
},
/**
* @constant
* @default
*/
ZIP_OS_LOOKUP: {
"MSDOS" : Zlib.Zip.OperatingSystem.MSDOS,
"Unix" : Zlib.Zip.OperatingSystem.UNIX,
"Macintosh" : Zlib.Zip.OperatingSystem.MACINTOSH
"MSDOS": Zlib.Zip.OperatingSystem.MSDOS,
"Unix": Zlib.Zip.OperatingSystem.UNIX,
"Macintosh": Zlib.Zip.OperatingSystem.MACINTOSH
},
/**
@@ -285,7 +285,7 @@ const Compress = {
* @returns {byteArray}
*/
runPkzip: function(input, args) {
var password = Utils.strToByteArray(args[2]),
let password = Utils.strToByteArray(args[2]),
options = {
filename: Utils.strToByteArray(args[0]),
comment: Utils.strToByteArray(args[1]),
@@ -318,7 +318,7 @@ const Compress = {
* @returns {string}
*/
runPkunzip: function(input, args) {
var options = {
let options = {
password: Utils.strToByteArray(args[0]),
verify: args[1]
},
@@ -327,15 +327,15 @@ const Compress = {
files = [];
filenames.forEach(function(fileName) {
var bytes = unzip.decompress(fileName);
var contents = Utils.byteArrayToUtf8(bytes);
const bytes = unzip.decompress(fileName);
const contents = Utils.byteArrayToUtf8(bytes);
var file = {
const file = {
fileName: fileName,
size: contents.length,
};
var isDir = contents.length === 0 && fileName.endsWith("/");
const isDir = contents.length === 0 && fileName.endsWith("/");
if (!isDir) {
file.bytes = bytes;
file.contents = contents;
@@ -356,7 +356,7 @@ const Compress = {
* @returns {string}
*/
runBzip2Decompress: function(input, args) {
var compressed = new Uint8Array(input),
let compressed = new Uint8Array(input),
bzip2Reader,
plain = "";
@@ -383,19 +383,19 @@ const Compress = {
* @returns {byteArray}
*/
runTar: function(input, args) {
var Tarball = function() {
const Tarball = function() {
this.bytes = new Array(512);
this.position = 0;
};
Tarball.prototype.addEmptyBlock = function() {
var filler = new Array(512);
const filler = new Array(512);
filler.fill(0);
this.bytes = this.bytes.concat(filler);
};
Tarball.prototype.writeBytes = function(bytes) {
var self = this;
const self = this;
if (this.position + bytes.length > this.bytes.length) {
this.addEmptyBlock();
@@ -412,17 +412,17 @@ const Compress = {
};
Tarball.prototype.writeEndBlocks = function() {
var numEmptyBlocks = 2;
for (var i = 0; i < numEmptyBlocks; i++) {
const numEmptyBlocks = 2;
for (let i = 0; i < numEmptyBlocks; i++) {
this.addEmptyBlock();
}
};
var fileSize = Utils.padLeft(input.length.toString(8), 11, "0");
var currentUnixTimestamp = Math.floor(Date.now() / 1000);
var lastModTime = Utils.padLeft(currentUnixTimestamp.toString(8), 11, "0");
const fileSize = Utils.padLeft(input.length.toString(8), 11, "0");
const currentUnixTimestamp = Math.floor(Date.now() / 1000);
const lastModTime = Utils.padLeft(currentUnixTimestamp.toString(8), 11, "0");
var file = {
const file = {
fileName: Utils.padBytesRight(args[0], 100),
fileMode: Utils.padBytesRight("0000664", 8),
ownerUID: Utils.padBytesRight("0", 8),
@@ -441,9 +441,9 @@ const Compress = {
fileNamePrefix: Utils.padBytesRight("", 155),
};
var checksum = 0;
for (var key in file) {
var bytes = file[key];
let checksum = 0;
for (const key in file) {
const bytes = file[key];
Array.prototype.forEach.call(bytes, function(b) {
if (typeof b.charCodeAt !== "undefined") {
checksum += b.charCodeAt();
@@ -455,7 +455,7 @@ const Compress = {
checksum = Utils.padBytesRight(Utils.padLeft(checksum.toString(8), 7, "0"), 8);
file.checksum = checksum;
var tarball = new Tarball();
const tarball = new Tarball();
tarball.writeBytes(file.fileName);
tarball.writeBytes(file.fileMode);
tarball.writeBytes(file.ownerUID);
@@ -490,22 +490,22 @@ const Compress = {
* @returns {html}
*/
runUntar: function(input, args) {
var Stream = function(input) {
const Stream = function(input) {
this.bytes = input;
this.position = 0;
};
Stream.prototype.getBytes = function(bytesToGet) {
var newPosition = this.position + bytesToGet;
var bytes = this.bytes.slice(this.position, newPosition);
const newPosition = this.position + bytesToGet;
const bytes = this.bytes.slice(this.position, newPosition);
this.position = newPosition;
return bytes;
};
Stream.prototype.readString = function(numBytes) {
var result = "";
for (var i = this.position; i < this.position + numBytes; i++) {
var currentByte = this.bytes[i];
let result = "";
for (let i = this.position; i < this.position + numBytes; i++) {
const currentByte = this.bytes[i];
if (currentByte === 0) break;
result += String.fromCharCode(currentByte);
}
@@ -514,7 +514,7 @@ const Compress = {
};
Stream.prototype.readInt = function(numBytes, base) {
var string = this.readString(numBytes);
const string = this.readString(numBytes);
return parseInt(string, base);
};
@@ -522,13 +522,13 @@ const Compress = {
return this.position < this.bytes.length;
};
var stream = new Stream(input),
let stream = new Stream(input),
files = [];
while (stream.hasMore()) {
var dataPosition = stream.position + 512;
const dataPosition = stream.position + 512;
var file = {
const file = {
fileName: stream.readString(100),
fileMode: stream.readString(8),
ownerUID: stream.readString(8),
@@ -555,7 +555,7 @@ const Compress = {
if (file.type === "0") {
// File
files.push(file);
var endPosition = stream.position + file.size;
let endPosition = stream.position + file.size;
if (file.size % 512 !== 0) {
endPosition += 512 - (file.size % 512);
}

View File

@@ -25,36 +25,36 @@ const Convert = {
* @default
*/
DISTANCE_FACTOR: { // Multiples of a metre
"Nanometres (nm)" : 1e-9,
"Micrometres (µm)" : 1e-6,
"Millimetres (mm)" : 1e-3,
"Centimetres (cm)" : 1e-2,
"Metres (m)" : 1,
"Kilometers (km)" : 1e3,
"Nanometres (nm)": 1e-9,
"Micrometres (µm)": 1e-6,
"Millimetres (mm)": 1e-3,
"Centimetres (cm)": 1e-2,
"Metres (m)": 1,
"Kilometers (km)": 1e3,
"Thou (th)" : 0.0000254,
"Inches (in)" : 0.0254,
"Feet (ft)" : 0.3048,
"Yards (yd)" : 0.9144,
"Chains (ch)" : 20.1168,
"Furlongs (fur)" : 201.168,
"Miles (mi)" : 1609.344,
"Leagues (lea)" : 4828.032,
"Thou (th)": 0.0000254,
"Inches (in)": 0.0254,
"Feet (ft)": 0.3048,
"Yards (yd)": 0.9144,
"Chains (ch)": 20.1168,
"Furlongs (fur)": 201.168,
"Miles (mi)": 1609.344,
"Leagues (lea)": 4828.032,
"Fathoms (ftm)" : 1.853184,
"Cables" : 185.3184,
"Nautical miles" : 1853.184,
"Fathoms (ftm)": 1.853184,
"Cables": 185.3184,
"Nautical miles": 1853.184,
"Cars (4m)" : 4,
"Buses (8.4m)" : 8.4,
"Cars (4m)": 4,
"Buses (8.4m)": 8.4,
"American football fields (91m)": 91,
"Football pitches (105m)": 105,
"Earth-to-Moons" : 380000000,
"Earth's equators" : 40075016.686,
"Earth-to-Moons": 380000000,
"Earth's equators": 40075016.686,
"Astronomical units (au)": 149597870700,
"Light-years (ly)" : 9460730472580800,
"Parsecs (pc)" : 3.0856776e16
"Light-years (ly)": 9460730472580800,
"Parsecs (pc)": 3.0856776e16
},
/**
@@ -65,7 +65,7 @@ const Convert = {
* @returns {number}
*/
runDistance: function (input, args) {
var inputUnits = args[0],
let inputUnits = args[0],
outputUnits = args[1];
input = input * Convert.DISTANCE_FACTOR[inputUnits];
@@ -90,52 +90,52 @@ const Convert = {
* @default
*/
DATA_FACTOR: { // Multiples of a bit
"Bits (b)" : 1,
"Nibbles" : 4,
"Octets" : 8,
"Bytes (B)" : 8,
"Bits (b)": 1,
"Nibbles": 4,
"Octets": 8,
"Bytes (B)": 8,
// Binary bits (2^n)
"Kibibits (Kib)" : 1024,
"Mebibits (Mib)" : 1048576,
"Gibibits (Gib)" : 1073741824,
"Tebibits (Tib)" : 1099511627776,
"Pebibits (Pib)" : 1125899906842624,
"Exbibits (Eib)" : 1152921504606846976,
"Zebibits (Zib)" : 1180591620717411303424,
"Yobibits (Yib)" : 1208925819614629174706176,
"Kibibits (Kib)": 1024,
"Mebibits (Mib)": 1048576,
"Gibibits (Gib)": 1073741824,
"Tebibits (Tib)": 1099511627776,
"Pebibits (Pib)": 1125899906842624,
"Exbibits (Eib)": 1152921504606846976,
"Zebibits (Zib)": 1180591620717411303424,
"Yobibits (Yib)": 1208925819614629174706176,
// Decimal bits (10^n)
"Decabits" : 10,
"Hectobits" : 100,
"Kilobits (Kb)" : 1e3,
"Megabits (Mb)" : 1e6,
"Gigabits (Gb)" : 1e9,
"Terabits (Tb)" : 1e12,
"Petabits (Pb)" : 1e15,
"Exabits (Eb)" : 1e18,
"Zettabits (Zb)" : 1e21,
"Yottabits (Yb)" : 1e24,
"Decabits": 10,
"Hectobits": 100,
"Kilobits (Kb)": 1e3,
"Megabits (Mb)": 1e6,
"Gigabits (Gb)": 1e9,
"Terabits (Tb)": 1e12,
"Petabits (Pb)": 1e15,
"Exabits (Eb)": 1e18,
"Zettabits (Zb)": 1e21,
"Yottabits (Yb)": 1e24,
// Binary bytes (8 x 2^n)
"Kibibytes (KiB)" : 8192,
"Mebibytes (MiB)" : 8388608,
"Gibibytes (GiB)" : 8589934592,
"Tebibytes (TiB)" : 8796093022208,
"Pebibytes (PiB)" : 9007199254740992,
"Exbibytes (EiB)" : 9223372036854775808,
"Zebibytes (ZiB)" : 9444732965739290427392,
"Yobibytes (YiB)" : 9671406556917033397649408,
"Kibibytes (KiB)": 8192,
"Mebibytes (MiB)": 8388608,
"Gibibytes (GiB)": 8589934592,
"Tebibytes (TiB)": 8796093022208,
"Pebibytes (PiB)": 9007199254740992,
"Exbibytes (EiB)": 9223372036854775808,
"Zebibytes (ZiB)": 9444732965739290427392,
"Yobibytes (YiB)": 9671406556917033397649408,
// Decimal bytes (8 x 10^n)
"Kilobytes (KB)" : 8e3,
"Megabytes (MB)" : 8e6,
"Gigabytes (GB)" : 8e9,
"Terabytes (TB)" : 8e12,
"Petabytes (PB)" : 8e15,
"Exabytes (EB)" : 8e18,
"Zettabytes (ZB)" : 8e21,
"Yottabytes (YB)" : 8e24,
"Kilobytes (KB)": 8e3,
"Megabytes (MB)": 8e6,
"Gigabytes (GB)": 8e9,
"Terabytes (TB)": 8e12,
"Petabytes (PB)": 8e15,
"Exabytes (EB)": 8e18,
"Zettabytes (ZB)": 8e21,
"Yottabytes (YB)": 8e24,
},
/**
@@ -146,7 +146,7 @@ const Convert = {
* @returns {number}
*/
runDataSize: function (input, args) {
var inputUnits = args[0],
let inputUnits = args[0],
outputUnits = args[1];
input = input * Convert.DATA_FACTOR[inputUnits];
@@ -171,51 +171,51 @@ const Convert = {
*/
AREA_FACTOR: { // Multiples of a square metre
// Metric
"Square metre (sq m)" : 1,
"Square kilometre (sq km)" : 1e6,
"Square metre (sq m)": 1,
"Square kilometre (sq km)": 1e6,
"Centiare (ca)" : 1,
"Deciare (da)" : 10,
"Are (a)" : 100,
"Decare (daa)" : 1e3,
"Hectare (ha)" : 1e4,
"Centiare (ca)": 1,
"Deciare (da)": 10,
"Are (a)": 100,
"Decare (daa)": 1e3,
"Hectare (ha)": 1e4,
// Imperial
"Square inch (sq in)" : 0.00064516,
"Square foot (sq ft)" : 0.09290304,
"Square yard (sq yd)" : 0.83612736,
"Square mile (sq mi)" : 2589988.110336,
"Perch (sq per)" : 42.21,
"Rood (ro)" : 1011,
"International acre (ac)" : 4046.8564224,
"Square inch (sq in)": 0.00064516,
"Square foot (sq ft)": 0.09290304,
"Square yard (sq yd)": 0.83612736,
"Square mile (sq mi)": 2589988.110336,
"Perch (sq per)": 42.21,
"Rood (ro)": 1011,
"International acre (ac)": 4046.8564224,
// US customary units
"US survey acre (ac)" : 4046.87261,
"US survey square mile (sq mi)" : 2589998.470305239,
"US survey township" : 93239944.9309886,
"US survey acre (ac)": 4046.87261,
"US survey square mile (sq mi)": 2589998.470305239,
"US survey township": 93239944.9309886,
// Nuclear physics
"Yoctobarn (yb)" : 1e-52,
"Zeptobarn (zb)" : 1e-49,
"Attobarn (ab)" : 1e-46,
"Femtobarn (fb)" : 1e-43,
"Picobarn (pb)" : 1e-40,
"Nanobarn (nb)" : 1e-37,
"Microbarn (μb)" : 1e-34,
"Millibarn (mb)" : 1e-31,
"Barn (b)" : 1e-28,
"Kilobarn (kb)" : 1e-25,
"Megabarn (Mb)" : 1e-22,
"Yoctobarn (yb)": 1e-52,
"Zeptobarn (zb)": 1e-49,
"Attobarn (ab)": 1e-46,
"Femtobarn (fb)": 1e-43,
"Picobarn (pb)": 1e-40,
"Nanobarn (nb)": 1e-37,
"Microbarn (μb)": 1e-34,
"Millibarn (mb)": 1e-31,
"Barn (b)": 1e-28,
"Kilobarn (kb)": 1e-25,
"Megabarn (Mb)": 1e-22,
"Planck area" : 2.6e-70,
"Shed" : 1e-52,
"Outhouse" : 1e-34,
"Planck area": 2.6e-70,
"Shed": 1e-52,
"Outhouse": 1e-34,
// Comparisons
"Washington D.C." : 176119191.502848,
"Isle of Wight" : 380000000,
"Wales" : 20779000000,
"Texas" : 696241000000,
"Washington D.C.": 176119191.502848,
"Isle of Wight": 380000000,
"Wales": 20779000000,
"Texas": 696241000000,
},
/**
@@ -226,7 +226,7 @@ const Convert = {
* @returns {number}
*/
runArea: function (input, args) {
var inputUnits = args[0],
let inputUnits = args[0],
outputUnits = args[1];
input = input * Convert.AREA_FACTOR[inputUnits];
@@ -252,81 +252,81 @@ const Convert = {
*/
MASS_FACTOR: { // Multiples of a gram
// Metric
"Yoctogram (yg)" : 1e-24,
"Zeptogram (zg)" : 1e-21,
"Attogram (ag)" : 1e-18,
"Femtogram (fg)" : 1e-15,
"Picogram (pg)" : 1e-12,
"Nanogram (ng)" : 1e-9,
"Microgram (μg)" : 1e-6,
"Milligram (mg)" : 1e-3,
"Centigram (cg)" : 1e-2,
"Decigram (dg)" : 1e-1,
"Gram (g)" : 1,
"Decagram (dag)" : 10,
"Hectogram (hg)" : 100,
"Kilogram (kg)" : 1000,
"Megagram (Mg)" : 1e6,
"Tonne (t)" : 1e6,
"Gigagram (Gg)" : 1e9,
"Teragram (Tg)" : 1e12,
"Petagram (Pg)" : 1e15,
"Exagram (Eg)" : 1e18,
"Zettagram (Zg)" : 1e21,
"Yottagram (Yg)" : 1e24,
"Yoctogram (yg)": 1e-24,
"Zeptogram (zg)": 1e-21,
"Attogram (ag)": 1e-18,
"Femtogram (fg)": 1e-15,
"Picogram (pg)": 1e-12,
"Nanogram (ng)": 1e-9,
"Microgram (μg)": 1e-6,
"Milligram (mg)": 1e-3,
"Centigram (cg)": 1e-2,
"Decigram (dg)": 1e-1,
"Gram (g)": 1,
"Decagram (dag)": 10,
"Hectogram (hg)": 100,
"Kilogram (kg)": 1000,
"Megagram (Mg)": 1e6,
"Tonne (t)": 1e6,
"Gigagram (Gg)": 1e9,
"Teragram (Tg)": 1e12,
"Petagram (Pg)": 1e15,
"Exagram (Eg)": 1e18,
"Zettagram (Zg)": 1e21,
"Yottagram (Yg)": 1e24,
// Imperial Avoirdupois
"Grain (gr)" : 64.79891e-3,
"Dram (dr)" : 1.7718451953125,
"Ounce (oz)" : 28.349523125,
"Pound (lb)" : 453.59237,
"Nail" : 3175.14659,
"Stone (st)" : 6.35029318e3,
"Quarter (gr)" : 12700.58636,
"Tod" : 12700.58636,
"US hundredweight (cwt)" : 45.359237e3,
"Imperial hundredweight (cwt)" : 50.80234544e3,
"US ton (t)" : 907.18474e3,
"Imperial ton (t)" : 1016.0469088e3,
"Grain (gr)": 64.79891e-3,
"Dram (dr)": 1.7718451953125,
"Ounce (oz)": 28.349523125,
"Pound (lb)": 453.59237,
"Nail": 3175.14659,
"Stone (st)": 6.35029318e3,
"Quarter (gr)": 12700.58636,
"Tod": 12700.58636,
"US hundredweight (cwt)": 45.359237e3,
"Imperial hundredweight (cwt)": 50.80234544e3,
"US ton (t)": 907.18474e3,
"Imperial ton (t)": 1016.0469088e3,
// Imperial Troy
"Pennyweight (dwt)" : 1.55517384,
"Troy dram (dr t)" : 3.8879346,
"Troy ounce (oz t)" : 31.1034768,
"Troy pound (lb t)" : 373.2417216,
"Mark" : 248.8278144,
"Pennyweight (dwt)": 1.55517384,
"Troy dram (dr t)": 3.8879346,
"Troy ounce (oz t)": 31.1034768,
"Troy pound (lb t)": 373.2417216,
"Mark": 248.8278144,
// Archaic
"Wey" : 76.5e3,
"Wool wey" : 101.7e3,
"Suffolk wey" : 161.5e3,
"Wool sack" : 153000,
"Coal sack" : 50.80234544e3,
"Load" : 918000,
"Last" : 1836000,
"Flax or feather last" : 770e3,
"Gunpowder last" : 1090e3,
"Picul" : 60.478982e3,
"Rice last" : 1200e3,
"Wey": 76.5e3,
"Wool wey": 101.7e3,
"Suffolk wey": 161.5e3,
"Wool sack": 153000,
"Coal sack": 50.80234544e3,
"Load": 918000,
"Last": 1836000,
"Flax or feather last": 770e3,
"Gunpowder last": 1090e3,
"Picul": 60.478982e3,
"Rice last": 1200e3,
// Comparisons
"Big Ben (14 tonnes)" : 14e6,
"Blue whale (180 tonnes)" : 180e6,
"International Space Station (417 tonnes)" : 417e6,
"Space Shuttle (2,041 tonnes)" : 2041e6,
"RMS Titanic (52,000 tonnes)" : 52000e6,
"Great Pyramid of Giza (6,000,000 tonnes)" : 6e12,
"Earth's oceans (1.4 yottagrams)" : 1.4e24,
"Big Ben (14 tonnes)": 14e6,
"Blue whale (180 tonnes)": 180e6,
"International Space Station (417 tonnes)": 417e6,
"Space Shuttle (2,041 tonnes)": 2041e6,
"RMS Titanic (52,000 tonnes)": 52000e6,
"Great Pyramid of Giza (6,000,000 tonnes)": 6e12,
"Earth's oceans (1.4 yottagrams)": 1.4e24,
// Astronomical
"A teaspoon of neutron star (5,500 million tonnes)" : 5.5e15,
"Lunar mass (ML)" : 7.342e25,
"Earth mass (M⊕)" : 5.97219e27,
"Jupiter mass (MJ)" : 1.8981411476999997e30,
"Solar mass (M☉)" : 1.98855e33,
"Sagittarius A* (7.5 x 10^36 kgs-ish)" : 7.5e39,
"Milky Way galaxy (1.2 x 10^42 kgs)" : 1.2e45,
"The observable universe (1.45 x 10^53 kgs)" : 1.45e56,
"A teaspoon of neutron star (5,500 million tonnes)": 5.5e15,
"Lunar mass (ML)": 7.342e25,
"Earth mass (M⊕)": 5.97219e27,
"Jupiter mass (MJ)": 1.8981411476999997e30,
"Solar mass (M☉)": 1.98855e33,
"Sagittarius A* (7.5 x 10^36 kgs-ish)": 7.5e39,
"Milky Way galaxy (1.2 x 10^42 kgs)": 1.2e45,
"The observable universe (1.45 x 10^53 kgs)": 1.45e56,
},
/**
@@ -337,7 +337,7 @@ const Convert = {
* @returns {number}
*/
runMass: function (input, args) {
var inputUnits = args[0],
let inputUnits = args[0],
outputUnits = args[1];
input = input * Convert.MASS_FACTOR[inputUnits];
@@ -361,37 +361,37 @@ const Convert = {
*/
SPEED_FACTOR: { // Multiples of m/s
// Metric
"Metres per second (m/s)" : 1,
"Kilometres per hour (km/h)" : 0.2778,
"Metres per second (m/s)": 1,
"Kilometres per hour (km/h)": 0.2778,
// Imperial
"Miles per hour (mph)" : 0.44704,
"Knots (kn)" : 0.5144,
"Miles per hour (mph)": 0.44704,
"Knots (kn)": 0.5144,
// Comparisons
"Human hair growth rate" : 4.8e-9,
"Bamboo growth rate" : 1.4e-5,
"World's fastest snail" : 0.00275,
"Usain Bolt's top speed" : 12.42,
"Jet airliner cruising speed" : 250,
"Concorde" : 603,
"SR-71 Blackbird" : 981,
"Space Shuttle" : 1400,
"International Space Station" : 7700,
"Human hair growth rate": 4.8e-9,
"Bamboo growth rate": 1.4e-5,
"World's fastest snail": 0.00275,
"Usain Bolt's top speed": 12.42,
"Jet airliner cruising speed": 250,
"Concorde": 603,
"SR-71 Blackbird": 981,
"Space Shuttle": 1400,
"International Space Station": 7700,
// Scientific
"Sound in standard atmosphere" : 340.3,
"Sound in water" : 1500,
"Lunar escape velocity" : 2375,
"Earth escape velocity" : 11200,
"Earth's solar orbit" : 29800,
"Solar system's Milky Way orbit" : 200000,
"Milky Way relative to the cosmic microwave background" : 552000,
"Solar escape velocity" : 617700,
"Neutron star escape velocity (0.3c)" : 100000000,
"Light in a diamond (0.4136c)" : 124000000,
"Signal in an optical fibre (0.667c)" : 200000000,
"Light (c)" : 299792458,
"Sound in standard atmosphere": 340.3,
"Sound in water": 1500,
"Lunar escape velocity": 2375,
"Earth escape velocity": 11200,
"Earth's solar orbit": 29800,
"Solar system's Milky Way orbit": 200000,
"Milky Way relative to the cosmic microwave background": 552000,
"Solar escape velocity": 617700,
"Neutron star escape velocity (0.3c)": 100000000,
"Light in a diamond (0.4136c)": 124000000,
"Signal in an optical fibre (0.667c)": 200000000,
"Light (c)": 299792458,
},
/**
@@ -402,7 +402,7 @@ const Convert = {
* @returns {number}
*/
runSpeed: function (input, args) {
var inputUnits = args[0],
let inputUnits = args[0],
outputUnits = args[1];
input = input * Convert.SPEED_FACTOR[inputUnits];

View File

@@ -1,3 +1,5 @@
import {BigInteger} from "jsbn";
/**
* Date and time operations.
*
@@ -23,7 +25,7 @@ const DateTime = {
* @returns {string}
*/
runFromUnixTimestamp: function(input, args) {
var units = args[0],
let units = args[0],
d;
input = parseFloat(input);
@@ -46,6 +48,12 @@ const DateTime = {
},
/**
* @constant
* @default
*/
TREAT_AS_UTC: true,
/**
* To UNIX Timestamp operation.
*
@@ -54,8 +62,9 @@ const DateTime = {
* @returns {number}
*/
runToUnixTimestamp: function(input, args) {
var units = args[0],
d = moment(input);
let units = args[0],
treatAsUTC = args[1],
d = treatAsUTC ? moment.utc(input) : moment(input);
if (units === "Seconds (s)") {
return d.unix();
@@ -71,6 +80,85 @@ const DateTime = {
},
/**
* Windows Filetime to Unix Timestamp operation.
*
* @author bwhitn [brian.m.whitney@outlook.com]
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
runFromFiletimeToUnix: function(input, args) {
let units = args[0],
format = args[1];
if (format === "Hex") {
input = new BigInteger(input, 16);
} else {
input = new BigInteger(input);
}
input = input.subtract(new BigInteger("116444736000000000"));
if (units === "Seconds (s)"){
input = input.divide(new BigInteger("10000000"));
} else if (units === "Milliseconds (ms)") {
input = input.divide(new BigInteger("10000"));
} else if (units === "Microseconds (μs)") {
input = input.divide(new BigInteger("10"));
} else if (units === "Nanoseconds (ns)") {
input = input.multiply(new BigInteger("100"));
} else {
throw "Unrecognised unit";
}
return input.toString();
},
/**
* Unix Timestamp to Windows Filetime operation.
*
* @author bwhitn [brian.m.whitney@outlook.com]
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
runToFiletimeFromUnix: function(input, args) {
let units = args[0],
format = args[1];
input = new BigInteger(input);
if (units === "Seconds (s)"){
input = input.multiply(new BigInteger("10000000"));
} else if (units === "Milliseconds (ms)") {
input = input.multiply(new BigInteger("10000"));
} else if (units === "Microseconds (μs)") {
input = input.multiply(new BigInteger("10"));
} else if (units === "Nanoseconds (ns)") {
input = input.divide(new BigInteger("100"));
} else {
throw "Unrecognised unit";
}
input = input.add(new BigInteger("116444736000000000"));
if (format === "Hex"){
return input.toString(16);
} else {
return input.toString();
}
},
/**
* @constant
* @default
*/
FILETIME_FORMATS: ["Decimal", "Hex"],
/**
* @constant
* @default
@@ -129,7 +217,7 @@ const DateTime = {
* @returns {html}
*/
runTranslateFormat: function(input, args) {
var inputFormat = args[1],
let inputFormat = args[1],
inputTimezone = args[2],
outputFormat = args[3],
outputTimezone = args[4],
@@ -154,7 +242,7 @@ const DateTime = {
* @returns {html}
*/
runParse: function(input, args) {
var inputFormat = args[1],
let inputFormat = args[1],
inputTimezone = args[2],
date,
output = "";

View File

@@ -36,7 +36,7 @@ const Endian = {
* @returns {string}
*/
runSwapEndianness: function(input, args) {
var dataFormat = args[0],
let dataFormat = args[0],
wordLength = args[1],
padIncompleteWords = args[2],
data = [],
@@ -63,7 +63,7 @@ const Endian = {
// Split up into words
for (i = 0; i < data.length; i += wordLength) {
var word = data.slice(i, i + wordLength);
const word = data.slice(i, i + wordLength);
// Pad word if too short
if (padIncompleteWords && word.length < wordLength){

View File

@@ -26,7 +26,7 @@ const Entropy = {
* @returns {html}
*/
runEntropy: function(input, args) {
var chunkSize = args[0],
let chunkSize = args[0],
output = "",
entropy = Entropy._calcEntropy(input);
@@ -58,9 +58,9 @@ const Entropy = {
]);\
</script>";
var chunkEntropy = 0;
let chunkEntropy = 0;
if (chunkSize !== 0) {
for (var i = 0; i < input.length; i += chunkSize) {
for (let i = 0; i < input.length; i += chunkSize) {
chunkEntropy = Entropy._calcEntropy(input.slice(i, i+chunkSize));
output += "Bytes " + i + " to " + (i+chunkSize) + ": " + chunkEntropy + "\n";
}
@@ -88,15 +88,11 @@ const Entropy = {
runFreqDistrib: function (input, args) {
if (!input.length) return "No data";
var distrib = new Array(256),
let distrib = new Array(256).fill(0),
percentages = new Array(256),
len = input.length,
showZeroes = args[0];
// Initialise distrib to 0
for (var i = 0; i < 256; i++) {
distrib[i] = 0;
}
showZeroes = args[0],
i;
// Count bytes
for (i = 0; i < len; i++) {
@@ -104,14 +100,14 @@ const Entropy = {
}
// Calculate percentages
var repr = 0;
let repr = 0;
for (i = 0; i < 256; i++) {
if (distrib[i] > 0) repr++;
percentages[i] = distrib[i] / len * 100;
}
// Print
var output = "<canvas id='chart-area'></canvas><br>" +
let output = "<canvas id='chart-area'></canvas><br>" +
"Total data length: " + len +
"\nNumber of bytes represented: " + repr +
"\nNumber of bytes not represented: " + (256-repr) +
@@ -147,15 +143,16 @@ const Entropy = {
* @returns {number}
*/
_calcEntropy: function(data) {
var prob = [],
let prob = [],
uniques = data.unique(),
str = Utils.byteArrayToChars(data);
str = Utils.byteArrayToChars(data),
i;
for (var i = 0; i < uniques.length; i++) {
for (i = 0; i < uniques.length; i++) {
prob.push(str.count(Utils.chr(uniques[i])) / data.length);
}
var entropy = 0,
let entropy = 0,
p;
for (i = 0; i < prob.length; i++) {

View File

@@ -21,7 +21,7 @@ const Extract = {
* @returns {string}
*/
_search: function(input, searchRegex, removeRegex, includeTotal) {
var output = "",
let output = "",
total = 0,
match;
@@ -58,7 +58,7 @@ const Extract = {
* @returns {string}
*/
runStrings: function(input, args) {
var minLen = args[0] || Extract.MIN_STRING_LEN,
let minLen = args[0] || Extract.MIN_STRING_LEN,
displayTotal = args[1],
strings = "[A-Z\\d/\\-:.,_$%'\"()<>= !\\[\\]{}@]",
regex = new RegExp(strings + "{" + minLen + ",}", "ig");
@@ -91,7 +91,7 @@ const Extract = {
* @returns {string}
*/
runIp: function(input, args) {
var includeIpv4 = args[0],
let includeIpv4 = args[0],
includeIpv6 = args[1],
removeLocal = args[2],
displayTotal = args[3],
@@ -108,10 +108,10 @@ const Extract = {
}
if (ips) {
var regex = new RegExp(ips, "ig");
const regex = new RegExp(ips, "ig");
if (removeLocal) {
var ten = "10\\..+",
let ten = "10\\..+",
oneninetwo = "192\\.168\\..+",
oneseventwo = "172\\.(?:1[6-9]|2\\d|3[01])\\..+",
onetwoseven = "127\\..+",
@@ -136,7 +136,7 @@ const Extract = {
* @returns {string}
*/
runEmail: function(input, args) {
var displayTotal = args[0],
let displayTotal = args[0],
regex = /\w[-.\w]*@[-\w]+(?:\.[-\w]+)*\.[A-Z]{2,4}/ig;
return Extract._search(input, regex, null, displayTotal);
@@ -151,7 +151,7 @@ const Extract = {
* @returns {string}
*/
runMac: function(input, args) {
var displayTotal = args[0],
let displayTotal = args[0],
regex = /[A-F\d]{2}(?:[:-][A-F\d]{2}){5}/ig;
return Extract._search(input, regex, null, displayTotal);
@@ -166,14 +166,14 @@ const Extract = {
* @returns {string}
*/
runUrls: function(input, args) {
var displayTotal = args[0],
let displayTotal = args[0],
protocol = "[A-Z]+://",
hostname = "[-\\w]+(?:\\.\\w[-\\w]*)+",
port = ":\\d+",
path = "/[^.!,?;\"'<>()\\[\\]{}\\s\\x7F-\\xFF]*";
path = "/[^.!,?\"<>\\[\\]{}\\s\\x7F-\\xFF]*";
path += "(?:[.!,?]+[^.!,?;\"'<>()\\[\\]{}\\s\\x7F-\\xFF]+)*";
var regex = new RegExp(protocol + hostname + "(?:" + port +
path += "(?:[.!,?]+[^.!,?\"<>\\[\\]{}\\s\\x7F-\\xFF]+)*";
const regex = new RegExp(protocol + hostname + "(?:" + port +
")?(?:" + path + ")?", "ig");
return Extract._search(input, regex, null, displayTotal);
},
@@ -187,7 +187,7 @@ const Extract = {
* @returns {string}
*/
runDomains: function(input, args) {
var displayTotal = args[0],
let displayTotal = args[0],
protocol = "https?://",
hostname = "[-\\w\\.]+",
tld = "\\.(?:com|net|org|biz|info|co|uk|onion|int|mobi|name|edu|gov|mil|eu|ac|ae|af|de|ca|ch|cn|cy|es|gb|hk|il|in|io|tv|me|nl|no|nz|ro|ru|tr|us|az|ir|kz|uz|pk)+",
@@ -216,7 +216,7 @@ const Extract = {
* @returns {string}
*/
runFilePaths: function(input, args) {
var includeWinPath = args[0],
let includeWinPath = args[0],
includeUnixPath = args[1],
displayTotal = args[2],
winDrive = "[A-Z]:\\\\",
@@ -236,7 +236,7 @@ const Extract = {
}
if (filePaths) {
var regex = new RegExp(filePaths, "ig");
const regex = new RegExp(filePaths, "ig");
return Extract._search(input, regex, null, displayTotal);
} else {
return "";
@@ -252,7 +252,7 @@ const Extract = {
* @returns {string}
*/
runDates: function(input, args) {
var displayTotal = args[0],
let displayTotal = args[0],
date1 = "(?:19|20)\\d\\d[- /.](?:0[1-9]|1[012])[- /.](?:0[1-9]|[12][0-9]|3[01])", // yyyy-mm-dd
date2 = "(?:0[1-9]|[12][0-9]|3[01])[- /.](?:0[1-9]|1[012])[- /.](?:19|20)\\d\\d", // dd/mm/yyyy
date3 = "(?:0[1-9]|1[012])[- /.](?:0[1-9]|[12][0-9]|3[01])[- /.](?:19|20)\\d\\d", // mm/dd/yyyy
@@ -270,7 +270,7 @@ const Extract = {
* @returns {string}
*/
runAllIdents: function(input, args) {
var output = "";
let output = "";
output += "IP addresses\n";
output += Extract.runIp(input, [true, true, false]);

View File

@@ -20,12 +20,12 @@ const FileType = {
* @returns {string}
*/
runDetect: function(input, args) {
var type = FileType._magicType(input);
const type = FileType.magicType(input);
if (!type) {
return "Unknown file type. Have you tried checking the entropy of this data to determine whether it might be encrypted or compressed?";
} else {
var output = "File extension: " + type.ext + "\n" +
let output = "File extension: " + type.ext + "\n" +
"MIME type: " + type.mime;
if (type.desc && type.desc.length) {
@@ -51,15 +51,15 @@ const FileType = {
* @returns {string}
*/
runScanForEmbeddedFiles: function(input, args) {
var output = "Scanning data for 'magic bytes' which may indicate embedded files. The following results may be false positives and should not be treat as reliable. Any suffiently long file is likely to contain these magic bytes coincidentally.\n",
let output = "Scanning data for 'magic bytes' which may indicate embedded files. The following results may be false positives and should not be treat as reliable. Any suffiently long file is likely to contain these magic bytes coincidentally.\n",
type,
ignoreCommon = args[0],
commonExts = ["ico", "ttf", ""],
numFound = 0,
numCommonFound = 0;
for (var i = 0; i < input.length; i++) {
type = FileType._magicType(input.slice(i));
for (let i = 0; i < input.length; i++) {
type = FileType.magicType(input.slice(i));
if (type) {
if (ignoreCommon && commonExts.indexOf(type.ext) > -1) {
numCommonFound++;
@@ -96,14 +96,13 @@ const FileType = {
* Given a buffer, detects magic byte sequences at specific positions and returns the
* extension and mime type.
*
* @private
* @param {byteArray} buf
* @returns {Object} type
* @returns {string} type.ext - File extension
* @returns {string} type.mime - Mime type
* @returns {string} [type.desc] - Description
*/
_magicType: function (buf) {
magicType: function (buf) {
if (!(buf && buf.length > 1)) {
return null;
}

File diff suppressed because it is too large Load Diff

View File

@@ -12,6 +12,17 @@ import {UAS_parser as UAParser} from "../lib/uas_parser.js";
*/
const HTTP = {
/**
* @constant
* @default
*/
METHODS: [
"GET", "POST", "HEAD",
"PUT", "PATCH", "DELETE",
"CONNECT", "TRACE", "OPTIONS"
],
/**
* Strip HTTP headers operation.
*
@@ -20,7 +31,7 @@ const HTTP = {
* @returns {string}
*/
runStripHeaders: function(input, args) {
var headerEnd = input.indexOf("\r\n\r\n");
let headerEnd = input.indexOf("\r\n\r\n");
headerEnd = (headerEnd < 0) ? input.indexOf("\n\n") + 2 : headerEnd + 4;
return (headerEnd < 2) ? input : input.slice(headerEnd, input.length);
@@ -35,7 +46,7 @@ const HTTP = {
* @returns {string}
*/
runParseUserAgent: function(input, args) {
var ua = UAParser.parse(input);
const ua = UAParser.parse(input);
return "Type: " + ua.type + "\n" +
"Family: " + ua.uaFamily + "\n" +
@@ -51,6 +62,95 @@ const HTTP = {
"Device Type: " + ua.deviceType + "\n";
},
/**
* @constant
* @default
*/
MODE: [
"Cross-Origin Resource Sharing",
"No CORS (limited to HEAD, GET or POST)",
],
/**
* Lookup table for HTTP modes
*
* @private
* @constant
*/
_modeLookup: {
"Cross-Origin Resource Sharing": "cors",
"No CORS (limited to HEAD, GET or POST)": "no-cors",
},
/**
* HTTP request operation.
*
* @author tlwr [toby@toby.codes]
* @author n1474335 [n1474335@gmail.com]
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
runHTTPRequest(input, args) {
const method = args[0],
url = args[1],
headersText = args[2],
mode = args[3],
showResponseMetadata = args[4];
if (url.length === 0) return "";
let headers = new Headers();
headersText.split(/\r?\n/).forEach(line => {
line = line.trim();
if (line.length === 0) return;
let split = line.split(":");
if (split.length !== 2) throw `Could not parse header in line: ${line}`;
headers.set(split[0].trim(), split[1].trim());
});
let config = {
method: method,
headers: headers,
mode: HTTP._modeLookup[mode],
cache: "no-cache",
};
if (method !== "GET" && method !== "HEAD") {
config.body = input;
}
return fetch(url, config)
.then(r => {
if (r.status === 0 && r.type === "opaque") {
return "Error: Null response. Try setting the connection mode to CORS.";
}
if (showResponseMetadata) {
let headers = "";
for (let pair of r.headers.entries()) {
headers += " " + pair[0] + ": " + pair[1] + "\n";
}
return r.text().then(b => {
return "####\n Status: " + r.status + " " + r.statusText +
"\n Exposed headers:\n" + headers + "####\n\n" + b;
});
}
return r.text();
})
.catch(e => {
return e.toString() +
"\n\nThis error could be caused by one of the following:\n" +
" - An invalid URL\n" +
" - Making a request to an insecure resource (HTTP) from a secure source (HTTPS)\n" +
" - Making a cross-origin request to a server which does not support CORS\n";
});
},
};
export default HTTP;

View File

@@ -144,7 +144,7 @@ const Hash = {
*/
runSHA3: function (input, args) {
input = CryptoJS.enc.Latin1.parse(input);
var sha3Length = args[0],
let sha3Length = args[0],
options = {
outputLength: parseInt(sha3Length, 10)
};
@@ -179,9 +179,9 @@ const Hash = {
* @returns {string}
*/
runHMAC: function (input, args) {
var hashFunc = args[1];
const hashFunc = args[1];
input = CryptoJS.enc.Latin1.parse(input);
var execute = {
const execute = {
"MD5": CryptoJS.HmacMD5(input, args[0]),
"SHA1": CryptoJS.HmacSHA1(input, args[0]),
"SHA224": CryptoJS.HmacSHA224(input, args[0]),
@@ -203,7 +203,7 @@ const Hash = {
* @returns {string}
*/
runAll: function (input, args) {
var byteArray = Utils.strToByteArray(input),
let byteArray = Utils.strToByteArray(input),
output = "MD2: " + Hash.runMD2(input, []) +
"\nMD4: " + Hash.runMD4(input, []) +
"\nMD5: " + Hash.runMD5(input, []) +
@@ -240,7 +240,7 @@ const Hash = {
runAnalyse: function(input, args) {
input = input.replace(/\s/g, "");
var output = "",
let output = "",
byteLength = input.length / 2,
bitLength = byteLength * 8,
possibleHashFunctions = [];

View File

@@ -37,19 +37,19 @@ const Hexdump = {
* @returns {string}
*/
runTo: function(input, args) {
var length = args[0] || Hexdump.WIDTH;
var upperCase = args[1];
var includeFinalLength = args[2];
const length = args[0] || Hexdump.WIDTH;
const upperCase = args[1];
const includeFinalLength = args[2];
var output = "", padding = 2;
for (var i = 0; i < input.length; i += length) {
var buff = input.slice(i, i+length);
var hexa = "";
for (var j = 0; j < buff.length; j++) {
let output = "", padding = 2;
for (let i = 0; i < input.length; i += length) {
const buff = input.slice(i, i+length);
let hexa = "";
for (let j = 0; j < buff.length; j++) {
hexa += Utils.hex(buff[j], padding) + " ";
}
var lineNo = Utils.hex(i, 8);
let lineNo = Utils.hex(i, 8);
if (upperCase) {
hexa = hexa.toUpperCase();
@@ -77,19 +77,19 @@ const Hexdump = {
* @returns {byteArray}
*/
runFrom: function(input, args) {
var output = [],
let output = [],
regex = /^\s*(?:[\dA-F]{4,16}:?)?\s*((?:[\dA-F]{2}\s){1,8}(?:\s|[\dA-F]{2}-)(?:[\dA-F]{2}\s){1,8}|(?:[\dA-F]{2}\s|[\dA-F]{4}\s)+)/igm,
block, line;
while ((block = regex.exec(input))) {
line = Utils.fromHex(block[1].replace(/-/g, " "));
for (var i = 0; i < line.length; i++) {
for (let i = 0; i < line.length; i++) {
output.push(line[i]);
}
}
// Is this a CyberChef hexdump or is it from a different tool?
var width = input.indexOf("\n");
var w = (width - 13) / 4;
const width = input.indexOf("\n");
const w = (width - 13) / 4;
// w should be the specified width of the hexdump and therefore a round number
if (Math.floor(w) !== w || input.indexOf("\r") !== -1 || output.indexOf(13) !== -1) {
if (app) app.options.attemptHighlight = false;
@@ -109,7 +109,7 @@ const Hexdump = {
*/
highlightTo: function(pos, args) {
// Calculate overall selection
var w = args[0] || 16,
let w = args[0] || 16,
width = 14 + (w*4),
line = Math.floor(pos[0].start / w),
offset = pos[0].start % w,
@@ -127,8 +127,8 @@ const Hexdump = {
pos[0].end = line*width + 10 + offset*3 - 1;
// Set up multiple selections for bytes
var startLineNum = Math.floor(pos[0].start / width);
var endLineNum = Math.floor(pos[0].end / width);
let startLineNum = Math.floor(pos[0].start / width);
const endLineNum = Math.floor(pos[0].end / width);
if (startLineNum === endLineNum) {
pos.push(pos[0]);
@@ -146,10 +146,10 @@ const Hexdump = {
}
// Set up multiple selections for ASCII
var len = pos.length, lineNum = 0;
let len = pos.length, lineNum = 0;
start = 0;
end = 0;
for (var i = 1; i < len; i++) {
for (let i = 1; i < len; i++) {
lineNum = Math.floor(pos[i].start / width);
start = (((pos[i].start - (lineNum * width)) - 10) / 3) + (width - w -2) + (lineNum * width);
end = (((pos[i].end + 1 - (lineNum * width)) - 10) / 3) + (width - w -2) + (lineNum * width);
@@ -169,11 +169,11 @@ const Hexdump = {
* @returns {Object[]} pos
*/
highlightFrom: function(pos, args) {
var w = args[0] || 16;
var width = 14 + (w*4);
const w = args[0] || 16;
const width = 14 + (w*4);
var line = Math.floor(pos[0].start / width);
var offset = pos[0].start % width;
let line = Math.floor(pos[0].start / width);
let offset = pos[0].start % width;
if (offset < 10) { // In line number section
pos[0].start = line*w;

View File

@@ -38,12 +38,12 @@ const IP = {
* @returns {string}
*/
runParseIpRange: function (input, args) {
var includeNetworkInfo = args[0],
let includeNetworkInfo = args[0],
enumerateAddresses = args[1],
allowLargeList = args[2];
// Check what type of input we are looking at
var ipv4CidrRegex = /^\s*((?:\d{1,3}\.){3}\d{1,3})\/(\d\d?)\s*$/,
let 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*$/,
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,
@@ -82,11 +82,11 @@ const IP = {
* @returns {string}
*/
runParseIPv6: function (input, args) {
var match,
let match,
output = "";
if ((match = IP.IPV6_REGEX.exec(input))) {
var ipv6 = IP._strToIpv6(match[1]),
let ipv6 = IP._strToIpv6(match[1]),
longhand = IP._ipv6ToStr(ipv6),
shorthand = IP._ipv6ToStr(ipv6, true);
@@ -126,7 +126,7 @@ const IP = {
} else if (ipv6[0] === 0x2001 && ipv6[1] === 0) {
// Teredo tunneling
output += "\nTeredo tunneling IPv6 address detected\n";
var serverIpv4 = (ipv6[2] << 16) + ipv6[3],
let serverIpv4 = (ipv6[2] << 16) + ipv6[3],
udpPort = (~ipv6[5]) & 0xffff,
clientIpv4 = ~((ipv6[6] << 16) + ipv6[7]),
flagCone = (ipv6[4] >>> 15) & 1,
@@ -190,7 +190,7 @@ const IP = {
output += "\n6to4 transition IPv6 address detected. See RFC 3056 for more details." +
"\n6to4 prefix range: 2002::/16";
var v4Addr = IP._ipv4ToStr((ipv6[1] << 16) + ipv6[2]),
let v4Addr = IP._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);
@@ -218,7 +218,7 @@ const IP = {
if ((ipv6[5] & 0xff === 0xff) && (ipv6[6] >>> 8 === 0xfe)) {
output += "\n\nThis IPv6 address contains a modified EUI-64 address, identified by the presence of FF:FE in the 12th and 13th octets.";
var intIdent = Utils.hex(ipv6[4] >>> 8) + ":" + Utils.hex(ipv6[4] & 0xff) + ":" +
let intIdent = Utils.hex(ipv6[4] >>> 8) + ":" + Utils.hex(ipv6[4] & 0xff) + ":" +
Utils.hex(ipv6[5] >>> 8) + ":" + Utils.hex(ipv6[5] & 0xff) + ":" +
Utils.hex(ipv6[6] >>> 8) + ":" + Utils.hex(ipv6[6] & 0xff) + ":" +
Utils.hex(ipv6[7] >>> 8) + ":" + Utils.hex(ipv6[7] & 0xff),
@@ -249,16 +249,18 @@ const IP = {
* @returns {string}
*/
runChangeIpFormat: function(input, args) {
var inFormat = args[0],
let inFormat = args[0],
outFormat = args[1],
lines = input.split("\n"),
output = "",
j = 0;
for (var i = 0; i < lines.length; i++) {
for (let i = 0; i < lines.length; i++) {
if (lines[i] === "") continue;
var baIp = [];
let baIp = [];
let octets;
let decimal;
if (inFormat === outFormat) {
output += lines[i] + "\n";
@@ -268,40 +270,44 @@ const IP = {
// Convert to byte array IP from input format
switch (inFormat) {
case "Dotted Decimal":
var octets = lines[i].split(".");
octets = lines[i].split(".");
for (j = 0; j < octets.length; j++) {
baIp.push(parseInt(octets[j], 10));
}
break;
case "Decimal":
var decimal = lines[i].toString();
decimal = lines[i].toString();
baIp.push(decimal >> 24 & 255);
baIp.push(decimal >> 16 & 255);
baIp.push(decimal >> 8 & 255);
baIp.push(decimal & 255);
break;
case "Hex":
baIp = Utils.hexToByteArray(lines[i]);
baIp = Utils.fromHex(lines[i]);
break;
default:
throw "Unsupported input IP format";
}
let ddIp;
let decIp;
let hexIp;
// Convert byte array IP to output format
switch (outFormat) {
case "Dotted Decimal":
var ddIp = "";
ddIp = "";
for (j = 0; j < baIp.length; j++) {
ddIp += baIp[j] + ".";
}
output += ddIp.slice(0, ddIp.length-1) + "\n";
break;
case "Decimal":
var decIp = ((baIp[0] << 24) | (baIp[1] << 16) | (baIp[2] << 8) | baIp[3]) >>> 0;
decIp = ((baIp[0] << 24) | (baIp[1] << 16) | (baIp[2] << 8) | baIp[3]) >>> 0;
output += decIp.toString() + "\n";
break;
case "Hex":
var hexIp = "";
hexIp = "";
for (j = 0; j < baIp.length; j++) {
hexIp += Utils.hex(baIp[j]);
}
@@ -340,7 +346,7 @@ const IP = {
* @returns {string}
*/
runGroupIps: function(input, args) {
var delim = Utils.charRep[args[0]],
let delim = Utils.charRep[args[0]],
cidr = args[1],
onlySubnets = args[2],
ipv4Mask = cidr < 32 ? ~(0xFFFFFFFF >>> cidr) : 0xFFFFFFFF,
@@ -352,14 +358,15 @@ const IP = {
output = "",
ip = null,
network = null,
networkStr = "";
networkStr = "",
i;
if (cidr < 0 || cidr > 127) {
return "CIDR must be less than 32 for IPv4 or 128 for IPv6";
}
// Parse all IPs and add to network dictionary
for (var i = 0; i < ips.length; i++) {
for (i = 0; i < ips.length; i++) {
if ((match = IP.IPV4_REGEX.exec(ips[i]))) {
ip = IP._strToIpv4(match[1]) >>> 0;
network = ip & ipv4Mask;
@@ -374,7 +381,7 @@ const IP = {
network = [];
networkStr = "";
for (var j = 0; j < 8; j++) {
for (let j = 0; j < 8; j++) {
network.push(ip[j] & ipv6Mask[j]);
}
@@ -434,7 +441,7 @@ const IP = {
* @returns {html}
*/
runParseIPv4Header: function(input, args) {
var format = args[0],
let format = args[0],
output;
if (format === "Hex") {
@@ -445,7 +452,7 @@ const IP = {
return "Unrecognised input format.";
}
var version = (input[0] >>> 4) & 0x0f,
let version = (input[0] >>> 4) & 0x0f,
ihl = input[0] & 0x0f,
dscp = (input[1] >>> 2) & 0x3f,
ecn = input[1] & 0x03,
@@ -471,15 +478,15 @@ const IP = {
ihl = ihl + " (Error: this should always be at least 5)";
} else if (ihl > 5) {
// sort out options...
var optionsLen = ihl * 4 - 20;
const optionsLen = ihl * 4 - 20;
options = input.slice(20, optionsLen + 20);
}
// Protocol
var protocolInfo = IP._protocolLookup[protocol] || {keyword: "", protocol: ""};
const protocolInfo = IP._protocolLookup[protocol] || {keyword: "", protocol: ""};
// Checksum
var correctChecksum = Checksum.runTCPIP(checksumHeader, []),
let correctChecksum = Checksum.runTCPIP(checksumHeader, []),
givenChecksum = Utils.hex(checksum),
checksumResult;
if (correctChecksum === givenChecksum) {
@@ -509,7 +516,7 @@ const IP = {
"<tr><td>Destination IP address</td><td>" + IP._ipv4ToStr(dstIP) + "</td></tr>";
if (ihl > 5) {
output += "<tr><td>Options</td><td>" + Utils.byteArrayToHex(options) + "</td></tr>";
output += "<tr><td>Options</td><td>" + Utils.toHex(options) + "</td></tr>";
}
return output + "</table>";
@@ -534,7 +541,7 @@ const IP = {
* @returns {string}
*/
_ipv4CidrRange: function(cidr, includeNetworkInfo, enumerateAddresses, allowLargeList) {
var output = "",
let output = "",
network = IP._strToIpv4(cidr[1]),
cidrRange = parseInt(cidr[2], 10);
@@ -542,7 +549,7 @@ const IP = {
return "IPv4 CIDR must be less than 32";
}
var mask = ~(0xFFFFFFFF >>> cidrRange),
let mask = ~(0xFFFFFFFF >>> cidrRange),
ip1 = network & mask,
ip2 = ip1 | ~mask;
@@ -574,7 +581,7 @@ const IP = {
* @returns {string}
*/
_ipv6CidrRange: function(cidr, includeNetworkInfo) {
var output = "",
let output = "",
network = IP._strToIpv6(cidr[1]),
cidrRange = parseInt(cidr[cidr.length-1], 10);
@@ -582,19 +589,19 @@ const IP = {
return "IPv6 CIDR must be less than 128";
}
var mask = IP._genIpv6Mask(cidrRange),
let mask = IP._genIpv6Mask(cidrRange),
ip1 = new Array(8),
ip2 = new Array(8),
totalDiff = "",
total = new Array(128);
for (var i = 0; i < 8; i++) {
for (let i = 0; i < 8; i++) {
ip1[i] = network[i] & mask[i];
ip2[i] = ip1[i] | (~mask[i] & 0x0000FFFF);
totalDiff = (ip2[i] - ip1[i]).toString(2);
if (totalDiff !== "0") {
for (var n = 0; n < totalDiff.length; n++) {
for (let n = 0; n < totalDiff.length; n++) {
total[i*16 + 16-(totalDiff.length-n)] = totalDiff[n];
}
}
@@ -621,10 +628,10 @@ const IP = {
* @returns {number[]}
*/
_genIpv6Mask: function(cidr) {
var mask = new Array(8),
let mask = new Array(8),
shift;
for (var i = 0; i < 8; i++) {
for (let i = 0; i < 8; i++) {
if (cidr > ((i+1)*16)) {
mask[i] = 0x0000FFFF;
} else {
@@ -650,12 +657,12 @@ const IP = {
* @returns {string}
*/
_ipv4HyphenatedRange: function(range, includeNetworkInfo, enumerateAddresses, allowLargeList) {
var output = "",
let output = "",
ip1 = IP._strToIpv4(range[1]),
ip2 = IP._strToIpv4(range[2]);
// Calculate mask
var diff = ip1 ^ ip2,
let diff = ip1 ^ ip2,
cidr = 32,
mask = 0;
@@ -666,7 +673,7 @@ const IP = {
}
mask = ~mask >>> 0;
var network = ip1 & mask,
let network = ip1 & mask,
subIp1 = network & mask,
subIp2 = subIp1 | ~mask;
@@ -701,21 +708,18 @@ const IP = {
* @returns {string}
*/
_ipv6HyphenatedRange: function(range, includeNetworkInfo) {
var output = "",
let output = "",
ip1 = IP._strToIpv6(range[1]),
ip2 = IP._strToIpv6(range[14]);
var t = "",
total = new Array(128);
// Initialise total array to "0"
for (var i = 0; i < 128; i++)
total[i] = "0";
let t = "",
total = new Array(128).fill(),
i;
for (i = 0; i < 8; i++) {
t = (ip2[i] - ip1[i]).toString(2);
if (t !== "0") {
for (var n = 0; n < t.length; n++) {
for (let n = 0; n < t.length; n++) {
total[i*16 + 16-(t.length-n)] = t[n];
}
}
@@ -743,7 +747,7 @@ const IP = {
* IP._strToIpv4("10.10.0.0");
*/
_strToIpv4: function (ipStr) {
var blocks = ipStr.split("."),
let blocks = ipStr.split("."),
numBlocks = parseBlocks(blocks),
result = 0;
@@ -761,8 +765,8 @@ const IP = {
if (blocks.length !== 4)
throw "More than 4 blocks.";
var numBlocks = [];
for (var i = 0; i < 4; i++) {
const numBlocks = [];
for (let i = 0; i < 4; i++) {
numBlocks[i] = parseInt(blocks[i], 10);
if (numBlocks[i] < 0 || numBlocks[i] > 255)
throw "Block out of range.";
@@ -784,7 +788,7 @@ const IP = {
* IP._ipv4ToStr(168427520);
*/
_ipv4ToStr: function(ipInt) {
var blockA = (ipInt >> 24) & 255,
let blockA = (ipInt >> 24) & 255,
blockB = (ipInt >> 16) & 255,
blockC = (ipInt >> 8) & 255,
blockD = ipInt & 255;
@@ -805,12 +809,12 @@ const IP = {
* IP._strToIpv6("ff00::1111:2222");
*/
_strToIpv6: function(ipStr) {
var blocks = ipStr.split(":"),
let blocks = ipStr.split(":"),
numBlocks = parseBlocks(blocks),
j = 0,
ipv6 = new Array(8);
for (var i = 0; i < 8; i++) {
for (let i = 0; i < 8; i++) {
if (isNaN(numBlocks[j])) {
ipv6[i] = 0;
if (i === (8-numBlocks.slice(j).length)) j++;
@@ -827,8 +831,8 @@ const IP = {
function parseBlocks(blocks) {
if (blocks.length < 3 || blocks.length > 8)
throw "Badly formatted IPv6 address.";
var numBlocks = [];
for (var i = 0; i < blocks.length; i++) {
const numBlocks = [];
for (let i = 0; i < blocks.length; i++) {
numBlocks[i] = parseInt(blocks[i], 16);
if (numBlocks[i] < 0 || numBlocks[i] > 65535)
throw "Block out of range.";
@@ -854,11 +858,11 @@ const IP = {
* IP._ipv6ToStr([65280, 0, 0, 0, 0, 0, 4369, 8738], false);
*/
_ipv6ToStr: function(ipv6, compact) {
var output = "",
let output = "",
i = 0;
if (compact) {
var start = -1,
let start = -1,
end = -1,
s = 0,
e = -1;
@@ -908,7 +912,7 @@ const IP = {
* IP._generateIpv4Range(1, 3);
*/
_generateIpv4Range: function(ip, endIp) {
var range = [];
const range = [];
if (endIp >= ip) {
for (; ip <= endIp; ip++) {
range.push(IP._ipv4ToStr(ip));

View File

@@ -0,0 +1,124 @@
import * as ExifParser from "exif-parser";
import removeEXIF from "../lib/remove-exif.js";
import Utils from "../Utils.js";
import FileType from "./FileType.js";
/**
* Image operations.
*
* @author tlwr [toby@toby.codes]
* @copyright Crown Copyright 2017
* @license Apache-2.0
*
* @namespace
*/
const Image = {
/**
* Extract EXIF operation.
*
* Extracts EXIF data from a byteArray, representing a JPG or a TIFF image.
*
* @param {byteArray} input
* @param {Object[]} args
* @returns {string}
*/
runExtractEXIF(input, args) {
try {
const bytes = Uint8Array.from(input);
const parser = ExifParser.create(bytes.buffer);
const result = parser.parse();
let lines = [];
for (let tagName in result.tags) {
let value = result.tags[tagName];
lines.push(`${tagName}: ${value}`);
}
const numTags = lines.length;
lines.unshift(`Found ${numTags} tags.\n`);
return lines.join("\n");
} catch (err) {
throw "Could not extract EXIF data from image: " + err;
}
},
/**
* Remove EXIF operation.
*
* Removes EXIF data from a byteArray, representing a JPG.
*
* @author David Moodie [davidmoodie12@gmail.com]
* @param {byteArray} input
* @param {Object[]} args
* @returns {string}
*/
runRemoveEXIF(input, args) {
// Do nothing if input is empty
if (input.length === 0) return input;
try {
return removeEXIF(input);
} catch (err) {
// Simply return input if no EXIF data is found
if (err === "Exif not found.") return input;
throw "Could not remove EXIF data from image: " + err;
}
},
/**
* @constant
* @default
*/
INPUT_FORMAT: ["Raw", "Base64", "Hex"],
/**
* Render Image operation.
*
* @author n1474335 [n1474335@gmail.com]
* @param {string} input
* @param {Object[]} args
* @returns {html}
*/
runRenderImage(input, args) {
const inputFormat = args[0];
let dataURI = "data:";
if (!input.length) return "";
// Convert input to raw bytes
switch (inputFormat) {
case "Hex":
input = Utils.fromHex(input);
break;
case "Base64":
// Don't trust the Base64 entered by the user.
// Unwrap it first, then re-encode later.
input = Utils.fromBase64(input, null, "byteArray");
break;
case "Raw":
default:
input = Utils.strToByteArray(input);
break;
}
// Determine file type
const type = FileType.magicType(input);
if (type && type.mime.indexOf("image") === 0) {
dataURI += type.mime + ";";
} else {
throw "Invalid file type";
}
// Add image data to URI
dataURI += "base64," + Utils.toBase64(input);
return "<img src='" + dataURI + "'>";
},
};
export default Image;

View File

@@ -1,4 +1,4 @@
import esprima from "esprima";
import * as esprima from "esprima";
import escodegen from "escodegen";
import esmangle from "esmangle";
@@ -48,7 +48,7 @@ const JS = {
* @returns {string}
*/
runParse: function (input, args) {
var parseLoc = args[0],
let parseLoc = args[0],
parseRange = args[1],
parseTokens = args[2],
parseComment = args[3],
@@ -62,7 +62,7 @@ const JS = {
tolerant: parseTolerant
};
result = esprima.parse(input, options);
result = esprima.parseScript(input, options);
return JSON.stringify(result, null, 2);
},
@@ -96,7 +96,7 @@ const JS = {
* @returns {string}
*/
runBeautify: function(input, args) {
var beautifyIndent = args[0] || JS.BEAUTIFY_INDENT,
let beautifyIndent = args[0] || JS.BEAUTIFY_INDENT,
quotes = args[1].toLowerCase(),
beautifySemicolons = args[2],
beautifyComment = args[3],
@@ -104,13 +104,13 @@ const JS = {
AST;
try {
AST = esprima.parse(input, {
AST = esprima.parseScript(input, {
range: true,
tokens: true,
comment: true
});
var options = {
const options = {
format: {
indent: {
style: beautifyIndent
@@ -141,8 +141,8 @@ const JS = {
* @returns {string}
*/
runMinify: function(input, args) {
var result = "",
AST = esprima.parse(input),
let result = "",
AST = esprima.parseScript(input),
optimisedAST = esmangle.optimize(AST, null),
mangledAST = esmangle.mangle(optimisedAST);

View File

@@ -45,7 +45,7 @@ const MAC = {
runFormat: function(input, args) {
if (!input) return "";
var outputCase = args[0],
let outputCase = args[0],
noDelim = args[1],
dashDelim = args[2],
colonDelim = args[3],
@@ -54,7 +54,7 @@ const MAC = {
macs = input.toLowerCase().split(/[,\s\r\n]+/);
macs.forEach(function(mac) {
var cleanMac = mac.replace(/[:.-]+/g, ""),
let cleanMac = mac.replace(/[:.-]+/g, ""),
macHyphen = cleanMac.replace(/(.{2}(?=.))/g, "$1-"),
macColon = cleanMac.replace(/(.{2}(?=.))/g, "$1:"),
macCisco = cleanMac.replace(/(.{4}(?=.))/g, "$1.");

View File

@@ -97,19 +97,19 @@ const MorseCode = {
* @returns {string}
*/
runTo: function(input, args) {
var format = args[0].split("/");
var dash = format[0];
var dot = format[1];
const format = args[0].split("/");
const dash = format[0];
const dot = format[1];
var letterDelim = Utils.charRep[args[1]];
var wordDelim = Utils.charRep[args[2]];
const letterDelim = Utils.charRep[args[1]];
const wordDelim = Utils.charRep[args[2]];
input = input.split(/\r?\n/);
input = Array.prototype.map.call(input, function(line) {
var words = line.split(/ +/);
let words = line.split(/ +/);
words = Array.prototype.map.call(words, function(word) {
var letters = Array.prototype.map.call(word, function(character) {
var letter = character.toUpperCase();
const letters = Array.prototype.map.call(word, function(character) {
const letter = character.toUpperCase();
if (typeof MorseCode.MORSE_TABLE[letter] == "undefined") {
return "";
}
@@ -148,12 +148,12 @@ const MorseCode = {
* @returns {string}
*/
runFrom: (function() {
var reversedTable = null;
var reverseTable = function() {
let reversedTable = null;
const reverseTable = function() {
reversedTable = {};
for (var letter in MorseCode.MORSE_TABLE) {
var signal = MorseCode.MORSE_TABLE[letter];
for (const letter in MorseCode.MORSE_TABLE) {
const signal = MorseCode.MORSE_TABLE[letter];
reversedTable[signal] = letter;
}
};
@@ -163,17 +163,17 @@ const MorseCode = {
reverseTable();
}
var letterDelim = Utils.charRep[args[0]];
var wordDelim = Utils.charRep[args[1]];
const letterDelim = Utils.charRep[args[0]];
const wordDelim = Utils.charRep[args[1]];
input = input.replace(/-|||_||—|dash/ig, "<dash>"); //hyphen-minus|hyphen|minus-sign|undersore|en-dash|em-dash
input = input.replace(/\.|·|dot/ig, "<dot>");
var words = input.split(wordDelim);
let words = input.split(wordDelim);
words = Array.prototype.map.call(words, function(word) {
var signals = word.split(letterDelim);
const signals = word.split(letterDelim);
var letters = signals.map(function(signal) {
const letters = signals.map(function(signal) {
return reversedTable[signal];
});

View File

@@ -23,10 +23,10 @@ const NetBIOS = {
* @returns {byteArray}
*/
runEncodeName: function(input, args) {
var output = [],
let output = [],
offset = args[0];
for (var i = 0; i < input.length; i++) {
for (let i = 0; i < input.length; i++) {
output.push((input[i] >> 4) + offset);
output.push((input[i] & 0xf) + offset);
}
@@ -43,10 +43,10 @@ const NetBIOS = {
* @returns {byteArray}
*/
runDecodeName: function(input, args) {
var output = [],
let output = [],
offset = args[0];
for (var i = 0; i < input.length; i += 2) {
for (let i = 0; i < input.length; i += 2) {
output.push(((input[i] - offset) << 4) |
((input[i + 1] - offset) & 0xf));
}

View File

@@ -15,7 +15,7 @@ const Numberwang = {
*/
run: function(input, args) {
if (!input) return "Let's play Wangernumb!";
var match = input.match(/\d+/);
const match = input.match(/\d+/);
if (match) {
return match[0] + "! That's Numberwang!";
} else {

View File

@@ -17,26 +17,26 @@ const OS = {
* @returns {string}
*/
runParseUnixPerms: function(input, args) {
var perms = {
d : false, // directory
sl : false, // symbolic link
np : false, // named pipe
s : false, // socket
cd : false, // character device
bd : false, // block device
dr : false, // door
sb : false, // sticky bit
su : false, // setuid
sg : false, // setgid
ru : false, // read user
wu : false, // write user
eu : false, // execute user
rg : false, // read group
wg : false, // write group
eg : false, // execute group
ro : false, // read other
wo : false, // write other
eo : false // execute other
let perms = {
d: false, // directory
sl: false, // symbolic link
np: false, // named pipe
s: false, // socket
cd: false, // character device
bd: false, // block device
dr: false, // door
sb: false, // sticky bit
su: false, // setuid
sg: false, // setgid
ru: false, // read user
wu: false, // write user
eu: false, // execute user
rg: false, // read group
wg: false, // write group
eg: false, // execute group
ro: false, // read other
wo: false, // write other
eo: false // execute other
},
d = 0,
u = 0,
@@ -202,7 +202,7 @@ const OS = {
* @returns {string}
*/
_permsToStr: function(perms) {
var str = "",
let str = "",
type = "-";
if (perms.d) type = "d";
@@ -263,7 +263,7 @@ const OS = {
* @returns {string}
*/
_permsToOctal: function(perms) {
var d = 0,
let d = 0,
u = 0,
g = 0,
o = 0;

File diff suppressed because it is too large Load Diff

View File

@@ -26,7 +26,7 @@ const Punycode = {
* @returns {string}
*/
runToAscii: function(input, args) {
var idn = args[0];
const idn = args[0];
if (idn) {
return punycode.toASCII(input);
@@ -44,7 +44,7 @@ const Punycode = {
* @returns {string}
*/
runToUnicode: function(input, args) {
var idn = args[0];
const idn = args[0];
if (idn) {
return punycode.toUnicode(input);

View File

@@ -40,7 +40,7 @@ const QuotedPrintable = {
* @returns {string}
*/
runTo: function (input, args) {
var mimeEncodedStr = QuotedPrintable.mimeEncode(input);
let mimeEncodedStr = QuotedPrintable.mimeEncode(input);
// fix line breaks
mimeEncodedStr = mimeEncodedStr.replace(/\r?\n|\r/g, function() {
@@ -61,7 +61,7 @@ const QuotedPrintable = {
* @returns {byteArray}
*/
runFrom: function (input, args) {
var str = input.replace(/\=(?:\r?\n|$)/g, "");
const str = input.replace(/=(?:\r?\n|$)/g, "");
return QuotedPrintable.mimeDecode(str);
},
@@ -73,13 +73,13 @@ const QuotedPrintable = {
* @returns {byteArray}
*/
mimeDecode: function(str) {
var encodedBytesCount = (str.match(/\=[\da-fA-F]{2}/g) || []).length,
let encodedBytesCount = (str.match(/=[\da-fA-F]{2}/g) || []).length,
bufferLength = str.length - encodedBytesCount * 2,
chr, hex,
buffer = new Array(bufferLength),
bufferPos = 0;
for (var i = 0, len = str.length; i < len; i++) {
for (let i = 0, len = str.length; i < len; i++) {
chr = str.charAt(i);
if (chr === "=" && (hex = str.substr(i + 1, 2)) && /[\da-fA-F]{2}/.test(hex)) {
buffer[bufferPos++] = parseInt(hex, 16);
@@ -100,7 +100,7 @@ const QuotedPrintable = {
* @returns {string}
*/
mimeEncode: function(buffer) {
var ranges = [
let ranges = [
[0x09],
[0x0A],
[0x0D],
@@ -113,7 +113,7 @@ const QuotedPrintable = {
],
result = "";
for (var i = 0, len = buffer.length; i < len; i++) {
for (let i = 0, len = buffer.length; i < len; i++) {
if (this._checkRanges(buffer[i], ranges)) {
result += String.fromCharCode(buffer[i]);
continue;
@@ -134,7 +134,7 @@ const QuotedPrintable = {
* @returns {bolean}
*/
_checkRanges: function(nr, ranges) {
for (var i = ranges.length - 1; i >= 0; i--) {
for (let i = ranges.length - 1; i >= 0; i--) {
if (!ranges[i].length)
continue;
if (ranges[i].length === 1 && nr === ranges[i][0])
@@ -157,7 +157,7 @@ const QuotedPrintable = {
* @returns {string}
*/
_addSoftLinebreaks: function(str, encoding) {
var lineLengthMax = 76;
const lineLengthMax = 76;
encoding = (encoding || "base64").toString().toLowerCase().trim();
@@ -192,7 +192,7 @@ const QuotedPrintable = {
* @returns {string}
*/
_addQPSoftLinebreaks: function(mimeEncodedStr, lineLengthMax) {
var pos = 0,
let pos = 0,
len = mimeEncodedStr.length,
match, code, line,
lineMargin = Math.floor(lineLengthMax / 3),
@@ -219,21 +219,21 @@ const QuotedPrintable = {
result += line;
pos += line.length;
continue;
} else if (line.length > lineLengthMax - lineMargin && (match = line.substr(-lineMargin).match(/[ \t\.,!\?][^ \t\.,!\?]*$/))) {
} else if (line.length > lineLengthMax - lineMargin && (match = line.substr(-lineMargin).match(/[ \t.,!?][^ \t.,!?]*$/))) {
// truncate to nearest space
line = line.substr(0, line.length - (match[0].length - 1));
} else if (line.substr(-1) === "\r") {
line = line.substr(0, line.length - 1);
} else {
if (line.match(/\=[\da-f]{0,2}$/i)) {
if (line.match(/=[\da-f]{0,2}$/i)) {
// push incomplete encoding sequences to the next line
if ((match = line.match(/\=[\da-f]{0,1}$/i))) {
if ((match = line.match(/=[\da-f]{0,1}$/i))) {
line = line.substr(0, line.length - match[0].length);
}
// ensure that utf-8 sequences are not split
while (line.length > 3 && line.length < len - pos && !line.match(/^(?:=[\da-f]{2}){1,4}$/i) && (match = line.match(/\=[\da-f]{2}$/ig))) {
while (line.length > 3 && line.length < len - pos && !line.match(/^(?:=[\da-f]{2}){1,4}$/i) && (match = line.match(/=[\da-f]{2}$/ig))) {
code = parseInt(match[0].substr(1, 2), 16);
if (code < 128) {
break;
@@ -250,7 +250,7 @@ const QuotedPrintable = {
}
if (pos + line.length < len && line.substr(-1) !== "\n") {
if (line.length === 76 && line.match(/\=[\da-f]{2}$/i)) {
if (line.length === 76 && line.match(/=[\da-f]{2}$/i)) {
line = line.substr(0, line.length - 3);
} else if (line.length === 76) {
line = line.substr(0, line.length - 1);

View File

@@ -32,10 +32,10 @@ const Rotate = {
* @returns {byteArray}
*/
_rot: function(data, amount, algo) {
var result = [];
for (var i = 0; i < data.length; i++) {
var b = data[i];
for (var j = 0; j < amount; j++) {
const result = [];
for (let i = 0; i < data.length; i++) {
let b = data[i];
for (let j = 0; j < amount; j++) {
b = algo(b);
}
result.push(b);
@@ -100,7 +100,7 @@ const Rotate = {
* @returns {byteArray}
*/
runRot13: function(input, args) {
var amount = args[2],
let amount = args[2],
output = input,
chr,
rot13Lowercase = args[0],
@@ -111,7 +111,7 @@ const Rotate = {
amount = 26 - (Math.abs(amount) % 26);
}
for (var i = 0; i < input.length; i++) {
for (let i = 0; i < input.length; i++) {
chr = input[i];
if (rot13Upperacse && chr >= 65 && chr <= 90) { // Upper case
chr = (chr - 65 + amount) % 26;
@@ -135,13 +135,13 @@ const Rotate = {
/**
* ROT47 operation.
*
* @author Matt C [matt@artemisbot.pw]
* @author Matt C [matt@artemisbot.uk]
* @param {byteArray} input
* @param {Object[]} args
* @returns {byteArray}
*/
runRot47: function(input, args) {
var amount = args[0],
let amount = args[0],
output = input,
chr;
@@ -150,7 +150,7 @@ const Rotate = {
amount = 94 - (Math.abs(amount) % 94);
}
for (var i = 0; i < input.length; i++) {
for (let i = 0; i < input.length; i++) {
chr = input[i];
if (chr >= 33 && chr <= 126) {
chr = (chr - 33 + amount) % 94;
@@ -170,7 +170,7 @@ const Rotate = {
* @returns {byte}
*/
_rotr: function(b) {
var bit = (b & 1) << 7;
const bit = (b & 1) << 7;
return (b >> 1) | bit;
},
@@ -183,7 +183,7 @@ const Rotate = {
* @returns {byte}
*/
_rotl: function(b) {
var bit = (b >> 7) & 1;
const bit = (b >> 7) & 1;
return ((b << 1) | bit) & 0xFF;
},
@@ -198,13 +198,13 @@ const Rotate = {
* @returns {byteArray}
*/
_rotrWhole: function(data, amount) {
var carryBits = 0,
let carryBits = 0,
newByte,
result = [];
amount = amount % 8;
for (var i = 0; i < data.length; i++) {
var oldByte = data[i] >>> 0;
for (let i = 0; i < data.length; i++) {
const oldByte = data[i] >>> 0;
newByte = (oldByte >> amount) | carryBits;
carryBits = (oldByte & (Math.pow(2, amount)-1)) << (8-amount);
result.push(newByte);
@@ -224,13 +224,13 @@ const Rotate = {
* @returns {byteArray}
*/
_rotlWhole: function(data, amount) {
var carryBits = 0,
let carryBits = 0,
newByte,
result = [];
amount = amount % 8;
for (var i = data.length-1; i >= 0; i--) {
var oldByte = data[i];
for (let i = data.length-1; i >= 0; i--) {
const oldByte = data[i];
newByte = ((oldByte << amount) | carryBits) & 0xFF;
carryBits = (oldByte >> (8-amount)) & (Math.pow(2, amount)-1);
result[i] = (newByte);

View File

@@ -26,7 +26,7 @@ const SeqUtils = {
* @constant
* @default
*/
SORT_ORDER: ["Alphabetical (case sensitive)", "Alphabetical (case insensitive)", "IP address"],
SORT_ORDER: ["Alphabetical (case sensitive)", "Alphabetical (case insensitive)", "IP address", "Numeric"],
/**
* Sort operation.
@@ -36,7 +36,7 @@ const SeqUtils = {
* @returns {string}
*/
runSort: function (input, args) {
var delim = Utils.charRep[args[0]],
let delim = Utils.charRep[args[0]],
sortReverse = args[1],
order = args[2],
sorted = input.split(delim);
@@ -47,6 +47,8 @@ const SeqUtils = {
sorted = sorted.sort(SeqUtils._caseInsensitiveSort);
} else if (order === "IP address") {
sorted = sorted.sort(SeqUtils._ipSort);
} else if (order === "Numeric") {
sorted = sorted.sort(SeqUtils._numericSort);
}
if (sortReverse) sorted.reverse();
@@ -62,7 +64,7 @@ const SeqUtils = {
* @returns {string}
*/
runUnique: function (input, args) {
var delim = Utils.charRep[args[0]];
const delim = Utils.charRep[args[0]];
return input.split(delim).unique().join(delim);
},
@@ -81,12 +83,12 @@ const SeqUtils = {
* @returns {number}
*/
runCount: function(input, args) {
var search = args[0].string,
let search = args[0].string,
type = args[0].option;
if (type === "Regex" && search) {
try {
var regex = new RegExp(search, "gi"),
let regex = new RegExp(search, "gi"),
matches = input.match(regex);
return matches.length;
} catch (err) {
@@ -117,11 +119,12 @@ const SeqUtils = {
* @returns {byteArray}
*/
runReverse: function (input, args) {
let i;
if (args[0] === "Line") {
var lines = [],
let lines = [],
line = [],
result = [];
for (var i = 0; i < input.length; i++) {
for (i = 0; i < input.length; i++) {
if (input[i] === 0x0a) {
lines.push(line);
line = [];
@@ -150,11 +153,11 @@ const SeqUtils = {
* @returns {string}
*/
runAddLineNumbers: function(input, args) {
var lines = input.split("\n"),
let lines = input.split("\n"),
output = "",
width = lines.length.toString().length;
for (var n = 0; n < lines.length; n++) {
for (let n = 0; n < lines.length; n++) {
output += Utils.pad((n+1).toString(), width, " ") + " " + lines[n] + "\n";
}
return output.slice(0, output.length-1);
@@ -207,7 +210,7 @@ const SeqUtils = {
* @returns {number}
*/
_ipSort: function(a, b) {
var a_ = a.split("."),
let a_ = a.split("."),
b_ = b.split(".");
a_ = a_[0] * 0x1000000 + a_[1] * 0x10000 + a_[2] * 0x100 + a_[3] * 1;
@@ -220,6 +223,35 @@ const SeqUtils = {
return a_ - b_;
},
/**
* Comparison operation for sorting of numeric values.
*
* @author Chris van Marle
* @private
* @param {string} a
* @param {string} b
* @returns {number}
*/
_numericSort: function _numericSort(a, b) {
let a_ = a.split(/([^\d]+)/),
b_ = b.split(/([^\d]+)/);
for (let i = 0; i < a_.length && i < b.length; ++i) {
if (isNaN(a_[i]) && !isNaN(b_[i])) return 1; // Numbers after non-numbers
if (!isNaN(a_[i]) && isNaN(b_[i])) return -1;
if (isNaN(a_[i]) && isNaN(b_[i])) {
let ret = a_[i].localeCompare(b_[i]); // Compare strings
if (ret !== 0) return ret;
}
if (!isNaN(a_[i]) && !isNaN(a_[i])) { // Compare numbers
if (a_[i] - b_[i] !== 0) return a_[i] - b_[i];
}
}
return 0;
},
};
export default SeqUtils;

View File

@@ -36,7 +36,7 @@ const StrUtils = {
},
{
name: "URL",
value: "([A-Za-z]+://)([-\\w]+(?:\\.\\w[-\\w]*)+)(:\\d+)?(/[^.!,?;\"\\x27<>()\\[\\]{}\\s\\x7F-\\xFF]*(?:[.!,?]+[^.!,?;\"\\x27<>()\\[\\]{}\\s\\x7F-\\xFF]+)*)?"
value: "([A-Za-z]+://)([-\\w]+(?:\\.\\w[-\\w]*)+)(:\\d+)?(/[^.!,?\"<>\\[\\]{}\\s\\x7F-\\xFF]*(?:[.!,?]+[^.!,?\"<>\\[\\]{}\\s\\x7F-\\xFF]+)*)?"
},
{
name: "Domain",
@@ -100,7 +100,7 @@ const StrUtils = {
* @returns {html}
*/
runRegex: function(input, args) {
var userRegex = args[1],
let userRegex = args[1],
i = args[2],
m = args[3],
displayTotal = args[4],
@@ -112,7 +112,7 @@ const StrUtils = {
if (userRegex && userRegex !== "^" && userRegex !== "$") {
try {
var regex = new RegExp(userRegex, modifiers);
const regex = new RegExp(userRegex, modifiers);
switch (outputFormat) {
case "Highlight matches":
@@ -149,7 +149,7 @@ const StrUtils = {
* @returns {string}
*/
runUpper: function (input, args) {
var scope = args[0];
const scope = args[0];
switch (scope) {
case "Word":
@@ -193,17 +193,17 @@ const StrUtils = {
* @constant
* @default
*/
FIND_REPLACE_GLOBAL : true,
FIND_REPLACE_GLOBAL: true,
/**
* @constant
* @default
*/
FIND_REPLACE_CASE : false,
FIND_REPLACE_CASE: false,
/**
* @constant
* @default
*/
FIND_REPLACE_MULTILINE : true,
FIND_REPLACE_MULTILINE: true,
/**
* Find / Replace operation.
@@ -213,7 +213,7 @@ const StrUtils = {
* @returns {string}
*/
runFindReplace: function(input, args) {
var find = args[0].string,
let find = args[0].string,
type = args[0].option,
replace = args[1],
g = args[2],
@@ -227,14 +227,16 @@ const StrUtils = {
if (type === "Regex") {
find = new RegExp(find, modifiers);
} else if (type.indexOf("Extended") === 0) {
return input.replace(find, replace);
}
if (type.indexOf("Extended") === 0) {
find = Utils.parseEscapedChars(find);
}
return input.replace(find, replace, modifiers);
// Non-standard addition of flags in the third argument. This will work in Firefox but
// probably nowhere else. The purpose is to allow global matching when the `find` parameter
// is just a string.
find = new RegExp(Utils.escapeRegex(find), modifiers);
return input.replace(find, replace);
},
@@ -257,7 +259,7 @@ const StrUtils = {
* @returns {string}
*/
runSplit: function(input, args) {
var splitDelim = args[0] || StrUtils.SPLIT_DELIM,
let splitDelim = args[0] || StrUtils.SPLIT_DELIM,
joinDelim = Utils.charRep[args[1]],
sections = input.split(splitDelim);
@@ -274,16 +276,17 @@ const StrUtils = {
* @returns {string}
*/
runFilter: function(input, args) {
var delim = Utils.charRep[args[0]],
let delim = Utils.charRep[args[0]],
regex,
reverse = args[2];
try {
var regex = new RegExp(args[1]);
regex = new RegExp(args[1]);
} catch (err) {
return "Invalid regex. Details: " + err.message;
}
var regexFilter = function(value) {
const regexFilter = function(value) {
return reverse ^ regex.test(value);
};
@@ -310,7 +313,7 @@ const StrUtils = {
* @returns {html}
*/
runDiff: function(input, args) {
var sampleDelim = args[0],
let sampleDelim = args[0],
diffBy = args[1],
showAdded = args[2],
showRemoved = args[3],
@@ -354,11 +357,11 @@ const StrUtils = {
return "Invalid 'Diff by' option.";
}
for (var i = 0; i < diff.length; i++) {
for (let i = 0; i < diff.length; i++) {
if (diff[i].added) {
if (showAdded) output += "<span class='hlgreen'>" + Utils.escapeHtml(diff[i].value) + "</span>";
if (showAdded) output += "<span class='hl5'>" + Utils.escapeHtml(diff[i].value) + "</span>";
} else if (diff[i].removed) {
if (showRemoved) output += "<span class='hlred'>" + Utils.escapeHtml(diff[i].value) + "</span>";
if (showRemoved) output += "<span class='hl3'>" + Utils.escapeHtml(diff[i].value) + "</span>";
} else {
output += Utils.escapeHtml(diff[i].value);
}
@@ -382,9 +385,9 @@ const StrUtils = {
* @returns {html}
*/
runOffsetChecker: function(input, args) {
var sampleDelim = args[0],
let sampleDelim = args[0],
samples = input.split(sampleDelim),
outputs = [],
outputs = new Array(samples.length),
i = 0,
s = 0,
match = false,
@@ -396,9 +399,7 @@ const StrUtils = {
}
// Initialise output strings
for (s = 0; s < samples.length; s++) {
outputs[s] = "";
}
outputs.fill("", 0, samples.length);
// Loop through each character in the first sample
for (i = 0; i < samples[0].length; i++) {
@@ -423,7 +424,7 @@ const StrUtils = {
}
if (match && !inMatch) {
outputs[s] += "<span class='hlgreen'>" + Utils.escapeHtml(samples[s][i]);
outputs[s] += "<span class='hl5'>" + Utils.escapeHtml(samples[s][i]);
if (samples[s].length === i + 1) outputs[s] += "</span>";
if (s === samples.length - 1) inMatch = true;
} else if (!match && inMatch) {
@@ -449,14 +450,140 @@ const StrUtils = {
/**
* Parse escaped string operation.
* @constant
* @default
*/
ESCAPE_REPLACEMENTS: [
{"escaped": "\\\\", "unescaped": "\\"}, // Must be first
{"escaped": "\\'", "unescaped": "'"},
{"escaped": "\\\"", "unescaped": "\""},
{"escaped": "\\n", "unescaped": "\n"},
{"escaped": "\\r", "unescaped": "\r"},
{"escaped": "\\t", "unescaped": "\t"},
{"escaped": "\\b", "unescaped": "\b"},
{"escaped": "\\f", "unescaped": "\f"},
],
/**
* Escape string operation.
*
* @author Vel0x [dalemy@microsoft.com]
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*
* @example
* StrUtils.runUnescape("Don't do that", [])
* > "Don\'t do that"
* StrUtils.runUnescape(`Hello
* World`, [])
* > "Hello\nWorld"
*/
runEscape: function(input, args) {
return StrUtils._replaceByKeys(input, "unescaped", "escaped");
},
/**
* Unescape string operation.
*
* @author Vel0x [dalemy@microsoft.com]
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*
* @example
* StrUtils.runUnescape("Don\'t do that", [])
* > "Don't do that"
* StrUtils.runUnescape("Hello\nWorld", [])
* > `Hello
* World`
*/
runUnescape: function(input, args) {
return StrUtils._replaceByKeys(input, "escaped", "unescaped");
},
/**
* Replaces all matching tokens in ESCAPE_REPLACEMENTS with the correction. The
* ordering is determined by the patternKey and the replacementKey.
*
* @author Vel0x [dalemy@microsoft.com]
* @author Matt C [matt@artemisbot.uk]
*
* @param {string} input
* @param {string} pattern_key
* @param {string} replacement_key
* @returns {string}
*/
_replaceByKeys: function(input, patternKey, replacementKey) {
let output = input;
// Catch the \\x encoded characters
if (patternKey === "escaped") output = Utils.parseEscapedChars(input);
StrUtils.ESCAPE_REPLACEMENTS.forEach(replacement => {
output = output.split(replacement[patternKey]).join(replacement[replacementKey]);
});
return output;
},
/**
* Head lines operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
runParseEscapedString: function(input, args) {
return Utils.parseEscapedChars(input);
runHead: function(input, args) {
let delimiter = args[0],
number = args[1];
delimiter = Utils.charRep[delimiter];
const splitInput = input.split(delimiter);
return splitInput
.filter((line, lineIndex) => {
lineIndex += 1;
if (number < 0) {
return lineIndex <= splitInput.length + number;
} else {
return lineIndex <= number;
}
})
.join(delimiter);
},
/**
* Tail lines operation.
*
* @param {string} input
* @param {Object[]} args
* @returns {string}
*/
runTail: function(input, args) {
let delimiter = args[0],
number = args[1];
delimiter = Utils.charRep[delimiter];
const splitInput = input.split(delimiter);
return splitInput
.filter((line, lineIndex) => {
lineIndex += 1;
if (number < 0) {
return lineIndex > -number;
} else {
return lineIndex > splitInput.length - number;
}
})
.join(delimiter);
},
@@ -470,7 +597,7 @@ const StrUtils = {
* @returns {string}
*/
_regexHighlight: function(input, regex, displayTotal) {
var output = "",
let output = "",
m,
hl = 1,
i = 0,
@@ -512,7 +639,7 @@ const StrUtils = {
* @returns {string}
*/
_regexList: function(input, regex, displayTotal, matches, captureGroups) {
var output = "",
let output = "",
total = 0,
match;
@@ -522,7 +649,7 @@ const StrUtils = {
output += match[0] + "\n";
}
if (captureGroups) {
for (var i = 1; i < match.length; i++) {
for (let i = 1; i < match.length; i++) {
if (matches) {
output += " Group " + i + ": ";
}
@@ -536,7 +663,6 @@ const StrUtils = {
return output;
},
};
export default StrUtils;

View File

@@ -16,32 +16,32 @@ const Tidy = {
* @constant
* @default
*/
REMOVE_SPACES : true,
REMOVE_SPACES: true,
/**
* @constant
* @default
*/
REMOVE_CARIAGE_RETURNS : true,
REMOVE_CARIAGE_RETURNS: true,
/**
* @constant
* @default
*/
REMOVE_LINE_FEEDS : true,
REMOVE_LINE_FEEDS: true,
/**
* @constant
* @default
*/
REMOVE_TABS : true,
REMOVE_TABS: true,
/**
* @constant
* @default
*/
REMOVE_FORM_FEEDS : true,
REMOVE_FORM_FEEDS: true,
/**
* @constant
* @default
*/
REMOVE_FULL_STOPS : false,
REMOVE_FULL_STOPS: false,
/**
* Remove whitespace operation.
@@ -51,7 +51,7 @@ const Tidy = {
* @returns {string}
*/
runRemoveWhitespace: function (input, args) {
var removeSpaces = args[0],
let removeSpaces = args[0],
removeCariageReturns = args[1],
removeLineFeeds = args[2],
removeTabs = args[3],
@@ -77,8 +77,8 @@ const Tidy = {
* @returns {byteArray}
*/
runRemoveNulls: function (input, args) {
var output = [];
for (var i = 0; i < input.length; i++) {
const output = [];
for (let i = 0; i < input.length; i++) {
if (input[i] !== 0) output.push(input[i]);
}
return output;
@@ -89,17 +89,17 @@ const Tidy = {
* @constant
* @default
*/
APPLY_TO_EACH_LINE : false,
APPLY_TO_EACH_LINE: false,
/**
* @constant
* @default
*/
DROP_START : 0,
DROP_START: 0,
/**
* @constant
* @default
*/
DROP_LENGTH : 5,
DROP_LENGTH: 5,
/**
* Drop bytes operation.
@@ -109,7 +109,7 @@ const Tidy = {
* @returns {byteArray}
*/
runDropBytes: function(input, args) {
var start = args[0],
let start = args[0],
length = args[1],
applyToEachLine = args[2];
@@ -120,10 +120,11 @@ const Tidy = {
return input.slice(0, start).concat(input.slice(start+length, input.length));
// Split input into lines
var lines = [],
line = [];
let lines = [],
line = [],
i;
for (var i = 0; i < input.length; i++) {
for (i = 0; i < input.length; i++) {
if (input[i] === 0x0a) {
lines.push(line);
line = [];
@@ -133,7 +134,7 @@ const Tidy = {
}
lines.push(line);
var output = [];
let output = [];
for (i = 0; i < lines.length; i++) {
output = output.concat(lines[i].slice(0, start).concat(lines[i].slice(start+length, lines[i].length)));
output.push(0x0a);
@@ -161,7 +162,7 @@ const Tidy = {
* @returns {byteArray}
*/
runTakeBytes: function(input, args) {
var start = args[0],
let start = args[0],
length = args[1],
applyToEachLine = args[2];
@@ -172,10 +173,11 @@ const Tidy = {
return input.slice(start, start+length);
// Split input into lines
var lines = [],
let lines = [],
line = [];
let i;
for (var i = 0; i < input.length; i++) {
for (i = 0; i < input.length; i++) {
if (input[i] === 0x0a) {
lines.push(line);
line = [];
@@ -185,7 +187,7 @@ const Tidy = {
}
lines.push(line);
var output = [];
let output = [];
for (i = 0; i < lines.length; i++) {
output = output.concat(lines[i].slice(start, start+length));
output.push(0x0a);
@@ -198,17 +200,17 @@ const Tidy = {
* @constant
* @default
*/
PAD_POSITION : ["Start", "End"],
PAD_POSITION: ["Start", "End"],
/**
* @constant
* @default
*/
PAD_LENGTH : 5,
PAD_LENGTH: 5,
/**
* @constant
* @default
*/
PAD_CHAR : " ",
PAD_CHAR: " ",
/**
* Pad lines operation.
@@ -218,7 +220,7 @@ const Tidy = {
* @returns {string}
*/
runPad: function(input, args) {
var position = args[0],
let position = args[0],
len = args[1],
chr = args[2],
lines = input.split("\n"),

View File

@@ -28,7 +28,7 @@ const URL_ = {
* @returns {string}
*/
runTo: function(input, args) {
var encodeAll = args[0];
const encodeAll = args[0];
return encodeAll ? URL_._encodeAllChars(input) : encodeURI(input);
},
@@ -41,7 +41,7 @@ const URL_ = {
* @returns {string}
*/
runFrom: function(input, args) {
var data = input.replace(/\+/g, "%20");
const data = input.replace(/\+/g, "%20");
try {
return decodeURIComponent(data);
} catch (err) {
@@ -62,14 +62,14 @@ const URL_ = {
throw "This operation only works in a browser.";
}
var a = document.createElement("a");
const a = document.createElement("a");
// Overwrite base href which will be the current CyberChef URL to reduce confusion.
a.href = "http://example.com/";
a.href = input;
if (a.protocol) {
var output = "";
let output = "";
if (a.hostname !== window.location.hostname) {
output = "Protocol:\t" + a.protocol + "\n";
if (a.hostname) output += "Hostname:\t" + a.hostname + "\n";
@@ -77,7 +77,7 @@ const URL_ = {
}
if (a.pathname && a.pathname !== window.location.pathname) {
var pathname = a.pathname;
let pathname = a.pathname;
if (pathname.indexOf(window.location.pathname) === 0)
pathname = pathname.replace(window.location.pathname, "");
if (pathname)
@@ -90,9 +90,9 @@ const URL_ = {
if (a.search && a.search !== window.location.search) {
output += "Arguments:\n";
var args_ = (a.search.slice(1, a.search.length)).split("&");
var splitArgs = [], padding = 0;
for (var i = 0; i < args_.length; i++) {
const args_ = (a.search.slice(1, a.search.length)).split("&");
let splitArgs = [], padding = 0, i;
for (i = 0; i < args_.length; i++) {
splitArgs.push(args_[i].split("="));
padding = (splitArgs[i][0].length > padding) ? splitArgs[i][0].length : padding;
}
@@ -127,7 +127,7 @@ const URL_ = {
.replace(/\(/g, "%28")
.replace(/\)/g, "%29")
.replace(/\*/g, "%2A")
.replace(/\-/g, "%2D")
.replace(/-/g, "%2D")
.replace(/\./g, "%2E")
.replace(/_/g, "%5F")
.replace(/~/g, "%7E");

View File

@@ -18,18 +18,18 @@ const UUID = {
*/
runGenerateV4: function(input, args) {
if (window && typeof(window.crypto) !== "undefined" && typeof(window.crypto.getRandomValues) !== "undefined") {
var buf = new Uint32Array(4),
let buf = new Uint32Array(4),
i = 0;
window.crypto.getRandomValues(buf);
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
var r = (buf[i >> 3] >> ((i % 8) * 4)) & 0xf,
let r = (buf[i >> 3] >> ((i % 8) * 4)) & 0xf,
v = c === "x" ? r : (r & 0x3 | 0x8);
i++;
return v.toString(16);
});
} else {
return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0,
let r = Math.random() * 16 | 0,
v = c === "x" ? r : (r & 0x3 | 0x8);
return v.toString(16);
});

View File

@@ -26,7 +26,7 @@ const Unicode = {
* @returns {string}
*/
runUnescape: function(input, args) {
var prefix = Unicode._prefixToRegex[args[0]],
let prefix = Unicode._prefixToRegex[args[0]],
regex = new RegExp(prefix+"([a-f\\d]{4,6})", "ig"),
output = "",
m,

View File

@@ -7,19 +7,19 @@
*/
require("babel-polyfill");
var Chef = require("../core/Chef.js").default;
const Chef = require("../core/Chef.js").default;
const CyberChef = module.exports = {
bake: function(input, recipeConfig) {
this.chef = new Chef();
return this.chef.bake(
input,
recipeConfig,
{},
0,
false
);
input,
recipeConfig,
{},
0,
false
);
}
};

View File

@@ -20,21 +20,23 @@ import Split from "split.js";
* @param {String[]} defaultFavourites - A list of default favourite operations.
* @param {Object} options - Default setting for app options.
*/
var App = function(categories, operations, defaultFavourites, defaultOptions) {
this.categories = categories;
this.operations = operations;
this.dfavourites = defaultFavourites;
this.doptions = defaultOptions;
this.options = Utils.extend({}, defaultOptions);
const App = function(categories, operations, defaultFavourites, defaultOptions) {
this.categories = categories;
this.operations = operations;
this.dfavourites = defaultFavourites;
this.doptions = defaultOptions;
this.options = Utils.extend({}, defaultOptions);
this.chef = new Chef();
this.manager = new Manager(this);
this.chef = new Chef();
this.manager = new Manager(this);
this.autoBake_ = false;
this.progress = 0;
this.ingId = 0;
this.baking = false;
this.autoBake_ = false;
this.autoBakePause = false;
this.progress = 0;
this.ingId = 0;
window.chef = this.chef;
window.chef = this.chef;
};
@@ -52,6 +54,30 @@ App.prototype.setup = function() {
this.resetLayout();
this.setCompileMessage();
this.loadURIParams();
this.loaded();
};
/**
* Fires once all setup activities have completed.
*
* @fires Manager#apploaded
*/
App.prototype.loaded = function() {
// Trigger CSS animations to remove preloader
document.body.classList.add("loaded");
// Wait for animations to complete then remove the preloader and loaded style
// so that the animations for existing elements don't play again.
setTimeout(function() {
document.getElementById("loader-wrapper").remove();
document.body.classList.remove("loaded");
}, 1000);
// Clear the loading message interval
clearInterval(window.loadingMsgsInt);
document.dispatchEvent(this.manager.apploaded);
};
@@ -62,24 +88,54 @@ App.prototype.setup = function() {
*/
App.prototype.handleError = function(err) {
console.error(err);
var msg = err.displayStr || err.toString();
const msg = err.displayStr || err.toString();
this.alert(msg, "danger", this.options.errorTimeout, !this.options.showErrors);
};
/**
* Updates the UI to show if baking is in process or not.
*
* @param {bakingStatus}
*/
App.prototype.setBakingStatus = function(bakingStatus) {
this.baking = bakingStatus;
let inputLoadingIcon = document.querySelector("#input .title .loading-icon"),
outputLoadingIcon = document.querySelector("#output .title .loading-icon"),
outputElement = document.querySelector("#output-text");
if (bakingStatus) {
inputLoadingIcon.style.display = "inline-block";
outputLoadingIcon.style.display = "inline-block";
outputElement.classList.add("disabled");
outputElement.disabled = true;
} else {
inputLoadingIcon.style.display = "none";
outputLoadingIcon.style.display = "none";
outputElement.classList.remove("disabled");
outputElement.disabled = false;
}
};
/**
* Calls the Chef to bake the current input using the current recipe.
*
* @param {boolean} [step] - Set to true if we should only execute one operation instead of the
* whole recipe.
*/
App.prototype.bake = function(step) {
var response;
App.prototype.bake = async function(step) {
let response;
if (this.baking) return;
this.setBakingStatus(true);
try {
response = this.chef.bake(
this.getInput(), // The user's input
this.getRecipeConfig(), // The configuration of the recipe
response = await this.chef.bake(
this.getInput(), // The user's input
this.getRecipeConfig(), // The configuration of the recipe
this.options, // Options set by the user
this.progress, // The current position in the recipe
step // Whether or not to take one step or execute the whole recipe
@@ -88,6 +144,8 @@ App.prototype.bake = function(step) {
this.handleError(err);
}
this.setBakingStatus(false);
if (!response) return;
if (response.error) {
@@ -113,7 +171,7 @@ App.prototype.bake = function(step) {
* Runs Auto Bake if it is set.
*/
App.prototype.autoBake = function() {
if (this.autoBake_) {
if (this.autoBake_ && !this.autoBakePause) {
this.bake();
}
};
@@ -129,7 +187,7 @@ App.prototype.autoBake = function() {
* @returns {number} - The number of miliseconds it took to run the silent bake.
*/
App.prototype.silentBake = function() {
var startTime = new Date().getTime(),
let startTime = new Date().getTime(),
recipeConfig = this.getRecipeConfig();
if (this.autoBake_) {
@@ -146,13 +204,7 @@ App.prototype.silentBake = function() {
* @returns {string}
*/
App.prototype.getInput = function() {
var input = this.manager.input.get();
// Save to session storage in case we need to restore it later
sessionStorage.setItem("inputLength", input.length);
sessionStorage.setItem("input", input);
return input;
return this.manager.input.get();
};
@@ -162,8 +214,6 @@ App.prototype.getInput = function() {
* @param {string} input - The string to set the input to
*/
App.prototype.setInput = function(input) {
sessionStorage.setItem("inputLength", input.length);
sessionStorage.setItem("input", input);
this.manager.input.set(input);
};
@@ -178,15 +228,16 @@ App.prototype.populateOperationsList = function() {
// Move edit button away before we overwrite it
document.body.appendChild(document.getElementById("edit-favourites"));
var html = "";
let html = "";
let i;
for (var i = 0; i < this.categories.length; i++) {
var catConf = this.categories[i],
for (i = 0; i < this.categories.length; i++) {
let catConf = this.categories[i],
selected = i === 0,
cat = new HTMLCategory(catConf.name, selected);
for (var j = 0; j < catConf.ops.length; j++) {
var opName = catConf.ops[j],
for (let j = 0; j < catConf.ops.length; j++) {
let opName = catConf.ops[j],
op = new HTMLOperation(opName, this.operations[opName], this, this.manager);
cat.addOperation(op);
}
@@ -196,7 +247,7 @@ App.prototype.populateOperationsList = function() {
document.getElementById("categories").innerHTML = html;
var opLists = document.querySelectorAll("#categories .op-list");
const opLists = document.querySelectorAll("#categories .op-list");
for (i = 0; i < opLists.length; i++) {
opLists[i].dispatchEvent(this.manager.oplistcreate);
@@ -236,7 +287,7 @@ App.prototype.initialiseSplitter = function() {
*/
App.prototype.loadLocalStorage = function() {
// Load options
var lOptions;
let lOptions;
if (localStorage.options !== undefined) {
lOptions = JSON.parse(localStorage.options);
}
@@ -253,7 +304,7 @@ App.prototype.loadLocalStorage = function() {
* If the user currently has no saved favourites, the defaults from the view constructor are used.
*/
App.prototype.loadFavourites = function() {
var favourites = localStorage.favourites &&
let favourites = localStorage.favourites &&
localStorage.favourites.length > 2 ?
JSON.parse(localStorage.favourites) :
this.dfavourites;
@@ -261,7 +312,7 @@ App.prototype.loadFavourites = function() {
favourites = this.validFavourites(favourites);
this.saveFavourites(favourites);
var favCat = this.categories.filter(function(c) {
const favCat = this.categories.filter(function(c) {
return c.name === "Favourites";
})[0];
@@ -284,8 +335,8 @@ App.prototype.loadFavourites = function() {
* @returns {string[]} A list of the valid favourites
*/
App.prototype.validFavourites = function(favourites) {
var validFavs = [];
for (var i = 0; i < favourites.length; i++) {
const validFavs = [];
for (let i = 0; i < favourites.length; i++) {
if (this.operations.hasOwnProperty(favourites[i])) {
validFavs.push(favourites[i]);
} else {
@@ -325,7 +376,7 @@ App.prototype.resetFavourites = function() {
* @param {string} name - The name of the operation
*/
App.prototype.addFavourite = function(name) {
var favourites = JSON.parse(localStorage.favourites);
const favourites = JSON.parse(localStorage.favourites);
if (favourites.indexOf(name) >= 0) {
this.alert("'" + name + "' is already in your favourites", "info", 2000);
@@ -344,61 +395,55 @@ App.prototype.addFavourite = function(name) {
* Checks for input and recipe in the URI parameters and loads them if present.
*/
App.prototype.loadURIParams = function() {
// Load query string from URI
this.queryString = (function(a) {
if (a === "") return {};
var b = {};
for (var i = 0; i < a.length; i++) {
var p = a[i].split("=");
if (p.length !== 2) {
b[a[i]] = true;
} else {
b[p[0]] = decodeURIComponent(p[1].replace(/\+/g, " "));
}
}
return b;
})(window.location.search.substr(1).split("&"));
// Load query string or hash from URI (depending on which is populated)
// We prefer getting the hash by splitting the href rather than referencing
// location.hash as some browsers (Firefox) automatically URL decode it,
// which cause issues.
const params = window.location.search ||
window.location.href.split("#")[1] ||
window.location.hash;
this.uriParams = Utils.parseURIParams(params);
// Turn off auto-bake while loading
var autoBakeVal = this.autoBake_;
this.autoBake_ = false;
// Pause auto-bake while loading but don't modify `this.autoBake_`
// otherwise `manualBake` cannot trigger.
this.autoBakePause = true;
// Read in recipe from query string
if (this.queryString.recipe) {
// Read in recipe from URI params
if (this.uriParams.recipe) {
try {
var recipeConfig = JSON.parse(this.queryString.recipe);
const recipeConfig = Utils.parseRecipeConfig(this.uriParams.recipe);
this.setRecipeConfig(recipeConfig);
} catch (err) {}
} else if (this.queryString.op) {
} else if (this.uriParams.op) {
// If there's no recipe, look for single operations
this.manager.recipe.clearRecipe();
try {
this.manager.recipe.addOperation(this.queryString.op);
this.manager.recipe.addOperation(this.uriParams.op);
} catch (err) {
// If no exact match, search for nearest match and add that
var matchedOps = this.manager.ops.filterOperations(this.queryString.op, false);
const matchedOps = this.manager.ops.filterOperations(this.uriParams.op, false);
if (matchedOps.length) {
this.manager.recipe.addOperation(matchedOps[0].name);
}
// Populate search with the string
var search = document.getElementById("search");
const search = document.getElementById("search");
search.value = this.queryString.op;
search.value = this.uriParams.op;
search.dispatchEvent(new Event("search"));
}
}
// Read in input data from query string
if (this.queryString.input) {
// Read in input data from URI params
if (this.uriParams.input) {
try {
var inputData = Utils.fromBase64(this.queryString.input);
const inputData = Utils.fromBase64(this.uriParams.input);
this.setInput(inputData);
} catch (err) {}
}
// Restore auto-bake state
this.autoBake_ = autoBakeVal;
// Unpause auto-bake
this.autoBakePause = false;
this.autoBake();
};
@@ -419,9 +464,7 @@ App.prototype.nextIngId = function() {
* @returns {Object[]}
*/
App.prototype.getRecipeConfig = function() {
var recipeConfig = this.manager.recipe.getConfig();
sessionStorage.setItem("recipeConfig", JSON.stringify(recipeConfig));
return recipeConfig;
return this.manager.recipe.getConfig();
};
@@ -431,15 +474,15 @@ App.prototype.getRecipeConfig = function() {
* @param {Object[]} recipeConfig - The recipe configuration
*/
App.prototype.setRecipeConfig = function(recipeConfig) {
sessionStorage.setItem("recipeConfig", JSON.stringify(recipeConfig));
document.getElementById("rec-list").innerHTML = null;
for (var i = 0; i < recipeConfig.length; i++) {
var item = this.manager.recipe.addOperation(recipeConfig[i].op);
for (let i = 0; i < recipeConfig.length; i++) {
const item = this.manager.recipe.addOperation(recipeConfig[i].op);
// Populate arguments
var args = item.querySelectorAll(".arg");
for (var j = 0; j < args.length; j++) {
const args = item.querySelectorAll(".arg");
for (let j = 0; j < args.length; j++) {
if (recipeConfig[i].args[j] === undefined) continue;
if (args[j].getAttribute("type") === "checkbox") {
// checkbox
args[j].checked = recipeConfig[i].args[j];
@@ -485,16 +528,25 @@ App.prototype.resetLayout = function() {
*/
App.prototype.setCompileMessage = function() {
// Display time since last build and compile message
var now = new Date(),
timeSinceCompile = Utils.fuzzyTime(now.getTime() - window.compileTime),
compileInfo = "<span style=\"font-weight: normal\">Last build: " +
timeSinceCompile.substr(0, 1).toUpperCase() + timeSinceCompile.substr(1) + " ago";
let now = new Date(),
timeSinceCompile = Utils.fuzzyTime(now.getTime() - window.compileTime);
// Calculate previous version to compare to
let prev = PKG_VERSION.split(".").map(n => {
return parseInt(n, 10);
});
if (prev[2] > 0) prev[2]--;
else if (prev[1] > 0) prev[1]--;
else prev[0]--;
const compareURL = `https://github.com/gchq/CyberChef/compare/v${prev.join(".")}...v${PKG_VERSION}`;
let compileInfo = `<a href='${compareURL}'>Last build: ${timeSinceCompile.substr(0, 1).toUpperCase() + timeSinceCompile.substr(1)} ago</a>`;
if (window.compileMessage !== "") {
compileInfo += " - " + window.compileMessage;
}
compileInfo += "</span>";
document.getElementById("notice").innerHTML = compileInfo;
};
@@ -523,7 +575,7 @@ App.prototype.setCompileMessage = function() {
* this.alert("Happy Christmas!", "info", 5000);
*/
App.prototype.alert = function(str, style, timeout, silent) {
var time = new Date();
const time = new Date();
console.log("[" + time.toLocaleString() + "] " + str);
if (silent) return;
@@ -531,7 +583,7 @@ App.prototype.alert = function(str, style, timeout, silent) {
style = style || "danger";
timeout = timeout || 0;
var alertEl = document.getElementById("alert"),
let alertEl = document.getElementById("alert"),
alertContent = document.getElementById("alert-content");
alertEl.classList.remove("alert-danger");
@@ -619,10 +671,27 @@ App.prototype.alertCloseClick = function() {
App.prototype.stateChange = function(e) {
this.autoBake();
// Set title
const recipeConfig = this.getRecipeConfig();
let title = "CyberChef";
if (recipeConfig.length === 1) {
title = `${recipeConfig[0].op} - ${title}`;
} else if (recipeConfig.length > 1) {
// See how long the full recipe is
const ops = recipeConfig.map(op => op.op).join(", ");
if (ops.length < 45) {
title = `${ops} - ${title}`;
} else {
// If it's too long, just use the first one and say how many more there are
title = `${recipeConfig[0].op}, ${recipeConfig.length - 1} more - ${title}`;
}
}
document.title = title;
// Update the current history state (not creating a new one)
if (this.options.updateUrl) {
this.lastStateUrl = this.manager.controls.generateStateUrl(true, true);
window.history.replaceState({}, "CyberChef", this.lastStateUrl);
this.lastStateUrl = this.manager.controls.generateStateUrl(true, true, recipeConfig);
window.history.replaceState({}, title, this.lastStateUrl);
}
};
@@ -634,9 +703,7 @@ App.prototype.stateChange = function(e) {
* @param {event} e
*/
App.prototype.popState = function(e) {
if (window.location.href.split("#")[0] !== this.lastStateUrl) {
this.loadURIParams();
}
this.loadURIParams();
};
@@ -649,7 +716,7 @@ App.prototype.callApi = function(url, type, data, dataType, contentType) {
dataType = dataType || undefined;
contentType = contentType || "application/json";
var response = null,
let response = null,
success = false;
$.ajax({

View File

@@ -12,7 +12,7 @@ import Utils from "../core/Utils.js";
* @param {App} app - The main view object for CyberChef.
* @param {Manager} manager - The CyberChef event manager.
*/
var ControlsWaiter = function(app, manager) {
const ControlsWaiter = function(app, manager) {
this.app = app;
this.manager = manager;
};
@@ -23,14 +23,14 @@ var ControlsWaiter = function(app, manager) {
* without wrapping or overflowing.
*/
ControlsWaiter.prototype.adjustWidth = function() {
var controls = document.getElementById("controls"),
step = document.getElementById("step"),
clrBreaks = document.getElementById("clr-breaks"),
saveImg = document.querySelector("#save img"),
loadImg = document.querySelector("#load img"),
stepImg = document.querySelector("#step img"),
clrRecipImg = document.querySelector("#clr-recipe img"),
clrBreaksImg = document.querySelector("#clr-breaks img");
const controls = document.getElementById("controls");
const step = document.getElementById("step");
const clrBreaks = document.getElementById("clr-breaks");
const saveImg = document.querySelector("#save img");
const loadImg = document.querySelector("#load img");
const stepImg = document.querySelector("#step img");
const clrRecipImg = document.querySelector("#clr-recipe img");
const clrBreaksImg = document.querySelector("#clr-breaks img");
if (controls.clientWidth < 470) {
step.childNodes[1].nodeValue = " Step";
@@ -66,7 +66,7 @@ ControlsWaiter.prototype.adjustWidth = function() {
* @param {boolean} value - The new value for Auto Bake.
*/
ControlsWaiter.prototype.setAutoBake = function(value) {
var autoBakeCheckbox = document.getElementById("auto-bake");
const autoBakeCheckbox = document.getElementById("auto-bake");
if (autoBakeCheckbox.checked !== value) {
autoBakeCheckbox.click();
@@ -79,7 +79,7 @@ ControlsWaiter.prototype.setAutoBake = function(value) {
*/
ControlsWaiter.prototype.bakeClick = function() {
this.app.bake();
var outputText = document.getElementById("output-text");
const outputText = document.getElementById("output-text");
outputText.focus();
outputText.setSelectionRange(0, 0);
};
@@ -90,7 +90,7 @@ ControlsWaiter.prototype.bakeClick = function() {
*/
ControlsWaiter.prototype.stepClick = function() {
this.app.bake(true);
var outputText = document.getElementById("output-text");
const outputText = document.getElementById("output-text");
outputText.focus();
outputText.setSelectionRange(0, 0);
};
@@ -100,17 +100,17 @@ ControlsWaiter.prototype.stepClick = function() {
* Handler for changes made to the Auto Bake checkbox.
*/
ControlsWaiter.prototype.autoBakeChange = function() {
var autoBakeLabel = document.getElementById("auto-bake-label"),
autoBakeCheckbox = document.getElementById("auto-bake");
const autoBakeLabel = document.getElementById("auto-bake-label");
const autoBakeCheckbox = document.getElementById("auto-bake");
this.app.autoBake_ = autoBakeCheckbox.checked;
if (autoBakeCheckbox.checked) {
autoBakeLabel.classList.remove("btn-default");
autoBakeLabel.classList.add("btn-success");
autoBakeLabel.classList.remove("btn-default");
} else {
autoBakeLabel.classList.remove("btn-success");
autoBakeLabel.classList.add("btn-default");
autoBakeLabel.classList.remove("btn-success");
}
};
@@ -128,9 +128,9 @@ ControlsWaiter.prototype.clearRecipeClick = function() {
* recipe.
*/
ControlsWaiter.prototype.clearBreaksClick = function() {
var bps = document.querySelectorAll("#rec-list li.operation .breakpoint");
const bps = document.querySelectorAll("#rec-list li.operation .breakpoint");
for (var i = 0; i < bps.length; i++) {
for (let i = 0; i < bps.length; i++) {
bps[i].setAttribute("break", "false");
bps[i].classList.remove("breakpoint-selected");
}
@@ -145,10 +145,10 @@ ControlsWaiter.prototype.clearBreaksClick = function() {
ControlsWaiter.prototype.initialiseSaveLink = function(recipeConfig) {
recipeConfig = recipeConfig || this.app.getRecipeConfig();
var includeRecipe = document.getElementById("save-link-recipe-checkbox").checked,
includeInput = document.getElementById("save-link-input-checkbox").checked,
saveLinkEl = document.getElementById("save-link"),
saveLink = this.generateStateUrl(includeRecipe, includeInput, recipeConfig);
const includeRecipe = document.getElementById("save-link-recipe-checkbox").checked;
const includeInput = document.getElementById("save-link-input-checkbox").checked;
const saveLinkEl = document.getElementById("save-link");
const saveLink = this.generateStateUrl(includeRecipe, includeInput, recipeConfig);
saveLinkEl.innerHTML = Utils.truncate(saveLink, 120);
saveLinkEl.setAttribute("href", saveLink);
@@ -167,23 +167,28 @@ ControlsWaiter.prototype.initialiseSaveLink = function(recipeConfig) {
ControlsWaiter.prototype.generateStateUrl = function(includeRecipe, includeInput, recipeConfig, baseURL) {
recipeConfig = recipeConfig || this.app.getRecipeConfig();
var link = baseURL || window.location.protocol + "//" +
window.location.host +
window.location.pathname,
recipeStr = JSON.stringify(recipeConfig),
inputStr = Utils.toBase64(this.app.getInput(), "A-Za-z0-9+/"); // B64 alphabet with no padding
const link = baseURL || window.location.protocol + "//" +
window.location.host +
window.location.pathname;
const recipeStr = Utils.generatePrettyRecipe(recipeConfig);
const inputStr = Utils.toBase64(this.app.getInput(), "A-Za-z0-9+/"); // B64 alphabet with no padding
includeRecipe = includeRecipe && (recipeConfig.length > 0);
includeInput = includeInput && (inputStr.length > 0) && (inputStr.length < 8000);
// Only inlcude input if it is less than 50KB (51200 * 4/3 as it is Base64 encoded)
includeInput = includeInput && (inputStr.length > 0) && (inputStr.length <= 68267);
if (includeRecipe) {
link += "?recipe=" + encodeURIComponent(recipeStr);
}
const params = [
includeRecipe ? ["recipe", recipeStr] : undefined,
includeInput ? ["input", inputStr] : undefined,
];
if (includeRecipe && includeInput) {
link += "&input=" + encodeURIComponent(inputStr);
} else if (includeInput) {
link += "?input=" + encodeURIComponent(inputStr);
const hash = params
.filter(v => v)
.map(([key, value]) => `${key}=${Utils.encodeURIFragment(value)}`)
.join("&");
if (hash) {
return `${link}#${hash}`;
}
return link;
@@ -193,9 +198,9 @@ ControlsWaiter.prototype.generateStateUrl = function(includeRecipe, includeInput
/**
* Handler for changes made to the save dialog text area. Re-initialises the save link.
*/
ControlsWaiter.prototype.saveTextChange = function() {
ControlsWaiter.prototype.saveTextChange = function(e) {
try {
var recipeConfig = JSON.parse(document.getElementById("save-text").value);
const recipeConfig = Utils.parseRecipeConfig(e.target.value);
this.initialiseSaveLink(recipeConfig);
} catch (err) {}
};
@@ -205,10 +210,17 @@ ControlsWaiter.prototype.saveTextChange = function() {
* Handler for the 'Save' command. Pops up the save dialog box.
*/
ControlsWaiter.prototype.saveClick = function() {
var recipeConfig = this.app.getRecipeConfig(),
recipeStr = JSON.stringify(recipeConfig).replace(/},{/g, "},\n{");
const recipeConfig = this.app.getRecipeConfig();
const recipeStr = JSON.stringify(recipeConfig);
document.getElementById("save-text").value = recipeStr;
document.getElementById("save-text-chef").value = Utils.generatePrettyRecipe(recipeConfig, true);
document.getElementById("save-text-clean").value = JSON.stringify(recipeConfig, null, 2)
.replace(/{\n\s+"/g, "{ \"")
.replace(/\[\n\s{3,}/g, "[")
.replace(/\n\s{3,}]/g, "]")
.replace(/\s*\n\s*}/g, " }")
.replace(/\n\s{6,}/g, " ");
document.getElementById("save-text-compact").value = recipeStr;
this.initialiseSaveLink(recipeConfig);
$("#save-modal").modal();
@@ -244,15 +256,15 @@ ControlsWaiter.prototype.loadClick = function() {
* Saves the recipe specified in the save textarea to local storage.
*/
ControlsWaiter.prototype.saveButtonClick = function() {
var recipeName = document.getElementById("save-name").value,
recipeStr = document.getElementById("save-text").value;
const recipeName = Utils.escapeHtml(document.getElementById("save-name").value);
const recipeStr = document.querySelector("#save-texts .tab-pane.active textarea").value;
if (!recipeName) {
this.app.alert("Please enter a recipe name", "danger", 2000);
return;
}
var savedRecipes = localStorage.savedRecipes ?
let savedRecipes = localStorage.savedRecipes ?
JSON.parse(localStorage.savedRecipes) : [],
recipeId = localStorage.recipeId || 0;
@@ -273,22 +285,23 @@ ControlsWaiter.prototype.saveButtonClick = function() {
* Populates the list of saved recipes in the load dialog box from local storage.
*/
ControlsWaiter.prototype.populateLoadRecipesList = function() {
var loadNameEl = document.getElementById("load-name");
const loadNameEl = document.getElementById("load-name");
// Remove current recipes from select
var i = loadNameEl.options.length;
let i = loadNameEl.options.length;
while (i--) {
loadNameEl.remove(i);
}
// Add recipes to select
var savedRecipes = localStorage.savedRecipes ?
JSON.parse(localStorage.savedRecipes) : [];
const savedRecipes = localStorage.savedRecipes ?
JSON.parse(localStorage.savedRecipes) : [];
for (i = 0; i < savedRecipes.length; i++) {
var opt = document.createElement("option");
const opt = document.createElement("option");
opt.value = savedRecipes[i].id;
opt.innerHTML = savedRecipes[i].name;
// Unescape then re-escape in case localStorage has been corrupted
opt.innerHTML = Utils.escapeHtml(Utils.unescapeHtml(savedRecipes[i].name));
loadNameEl.appendChild(opt);
}
@@ -302,13 +315,11 @@ ControlsWaiter.prototype.populateLoadRecipesList = function() {
* Removes the currently selected recipe from local storage.
*/
ControlsWaiter.prototype.loadDeleteClick = function() {
var id = parseInt(document.getElementById("load-name").value, 10),
savedRecipes = localStorage.savedRecipes ?
JSON.parse(localStorage.savedRecipes) : [];
const id = parseInt(document.getElementById("load-name").value, 10);
const rawSavedRecipes = localStorage.savedRecipes ?
JSON.parse(localStorage.savedRecipes) : [];
savedRecipes = savedRecipes.filter(function(r) {
return r.id !== id;
});
const savedRecipes = rawSavedRecipes.filter(r => r.id !== id);
localStorage.savedRecipes = JSON.stringify(savedRecipes);
this.populateLoadRecipesList();
@@ -319,14 +330,12 @@ ControlsWaiter.prototype.loadDeleteClick = function() {
* Displays the selected recipe in the load text box.
*/
ControlsWaiter.prototype.loadNameChange = function(e) {
var el = e.target,
savedRecipes = localStorage.savedRecipes ?
JSON.parse(localStorage.savedRecipes) : [],
id = parseInt(el.value, 10);
const el = e.target;
const savedRecipes = localStorage.savedRecipes ?
JSON.parse(localStorage.savedRecipes) : [];
const id = parseInt(el.value, 10);
var recipe = savedRecipes.filter(function(r) {
return r.id === id;
})[0];
const recipe = savedRecipes.find(r => r.id === id);
document.getElementById("load-text").value = recipe.recipe;
};
@@ -337,7 +346,7 @@ ControlsWaiter.prototype.loadNameChange = function(e) {
*/
ControlsWaiter.prototype.loadButtonClick = function() {
try {
var recipeConfig = JSON.parse(document.getElementById("load-text").value);
const recipeConfig = Utils.parseRecipeConfig(document.getElementById("load-text").value);
this.app.setRecipeConfig(recipeConfig);
$("#rec-list [data-toggle=popover]").popover();
@@ -349,14 +358,21 @@ ControlsWaiter.prototype.loadButtonClick = function() {
/**
* Populates the bug report information box with useful technical info.
*
* @param {event} e
*/
ControlsWaiter.prototype.supportButtonClick = function() {
var reportBugInfo = document.getElementById("report-bug-info"),
saveLink = this.generateStateUrl(true, true, null, "https://gchq.github.io/CyberChef/");
ControlsWaiter.prototype.supportButtonClick = function(e) {
e.preventDefault();
reportBugInfo.innerHTML = "* CyberChef compile time: " + COMPILE_TIME + "\n" +
"* User-Agent: \n" + navigator.userAgent + "\n" +
"* [Link to reproduce](" + saveLink + ")\n\n";
const reportBugInfo = document.getElementById("report-bug-info");
const saveLink = this.generateStateUrl(true, true, null, "https://gchq.github.io/CyberChef/");
if (reportBugInfo) {
reportBugInfo.innerHTML = "* Version: " + PKG_VERSION + "\n" +
"* Compile time: " + COMPILE_TIME + "\n" +
"* User-Agent: \n" + navigator.userAgent + "\n" +
"* [Link to reproduce](" + saveLink + ")\n\n";
}
};
export default ControlsWaiter;

View File

@@ -9,7 +9,7 @@
* @param {string} name - The name of the category.
* @param {boolean} selected - Whether this category is pre-selected or not.
*/
var HTMLCategory = function(name, selected) {
const HTMLCategory = function(name, selected) {
this.name = name;
this.selected = selected;
this.opList = [];
@@ -32,8 +32,8 @@ HTMLCategory.prototype.addOperation = function(operation) {
* @returns {string}
*/
HTMLCategory.prototype.toHtml = function() {
var catName = "cat" + this.name.replace(/[\s/-:_]/g, "");
var html = "<div class='panel category'>\
const catName = "cat" + this.name.replace(/[\s/-:_]/g, "");
let html = "<div class='panel category'>\
<a class='category-title' data-toggle='collapse'\
data-parent='#categories' href='#" + catName + "'>\
" + this.name + "\
@@ -41,7 +41,7 @@ HTMLCategory.prototype.toHtml = function() {
<div id='" + catName + "' class='panel-collapse collapse\
" + (this.selected ? " in" : "") + "'><ul class='op-list'>";
for (var i = 0; i < this.opList.length; i++) {
for (let i = 0; i < this.opList.length; i++) {
html += this.opList[i].toStubHtml();
}

View File

@@ -10,7 +10,7 @@
* @param {App} app - The main view object for CyberChef.
* @param {Manager} manager - The CyberChef event manager.
*/
var HTMLIngredient = function(config, app, manager) {
const HTMLIngredient = function(config, app, manager) {
this.app = app;
this.manager = manager;
@@ -32,7 +32,7 @@ var HTMLIngredient = function(config, app, manager) {
* @returns {string}
*/
HTMLIngredient.prototype.toHtml = function() {
var inline = (this.type === "boolean" ||
let inline = (this.type === "boolean" ||
this.type === "number" ||
this.type === "option" ||
this.type === "shortString" ||
@@ -158,15 +158,14 @@ HTMLIngredient.prototype.toHtml = function() {
* @param {event} e
*/
HTMLIngredient.prototype.toggleDisableArgs = function(e) {
var el = e.target,
op = el.parentNode.parentNode,
args = op.querySelectorAll(".arg-group"),
els;
const el = e.target;
const op = el.parentNode.parentNode;
const args = op.querySelectorAll(".arg-group");
for (var i = 0; i < this.disableArgs.length; i++) {
els = args[this.disableArgs[i]].querySelectorAll("input, select, button");
for (let i = 0; i < this.disableArgs.length; i++) {
const els = args[this.disableArgs[i]].querySelectorAll("input, select, button");
for (var j = 0; j < els.length; j++) {
for (let j = 0; j < els.length; j++) {
if (els[j].getAttribute("disabled")) {
els[j].removeAttribute("disabled");
} else {
@@ -186,9 +185,9 @@ HTMLIngredient.prototype.toggleDisableArgs = function(e) {
* @param {event} e
*/
HTMLIngredient.prototype.populateOptionChange = function(e) {
var el = e.target,
op = el.parentNode.parentNode,
target = op.querySelectorAll(".arg-group")[this.target].querySelector("input, select, textarea");
const el = e.target;
const op = el.parentNode.parentNode;
const target = op.querySelectorAll(".arg-group")[this.target].querySelector("input, select, textarea");
target.value = el.childNodes[el.selectedIndex].getAttribute("populate-value");
@@ -203,7 +202,7 @@ HTMLIngredient.prototype.populateOptionChange = function(e) {
* @param {event} e
*/
HTMLIngredient.prototype.editableOptionChange = function(e) {
var select = e.target,
let select = e.target,
input = select.nextSibling;
input.value = select.childNodes[select.selectedIndex].value;

View File

@@ -14,7 +14,7 @@ import HTMLIngredient from "./HTMLIngredient.js";
* @param {App} app - The main view object for CyberChef.
* @param {Manager} manager - The CyberChef event manager.
*/
var HTMLOperation = function(name, config, app, manager) {
const HTMLOperation = function(name, config, app, manager) {
this.app = app;
this.manager = manager;
@@ -24,8 +24,8 @@ var HTMLOperation = function(name, config, app, manager) {
this.config = config;
this.ingList = [];
for (var i = 0; i < config.args.length; i++) {
var ing = new HTMLIngredient(config.args[i], this.app, this.manager);
for (let i = 0; i < config.args.length; i++) {
const ing = new HTMLIngredient(config.args[i], this.app, this.manager);
this.ingList.push(ing);
}
};
@@ -47,7 +47,7 @@ HTMLOperation.REMOVE_ICON = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABwkl
* @returns {string}
*/
HTMLOperation.prototype.toStubHtml = function(removeIcon) {
var html = "<li class='operation'";
let html = "<li class='operation'";
if (this.description) {
html += " data-container='body' data-toggle='popover' data-placement='auto right'\
@@ -77,9 +77,9 @@ HTMLOperation.prototype.toStubHtml = function(removeIcon) {
* @returns {string}
*/
HTMLOperation.prototype.toFullHtml = function() {
var html = "<div class='arg-title'>" + this.name + "</div>";
let html = "<div class='arg-title'>" + this.name + "</div>";
for (var i = 0; i < this.ingList.length; i++) {
for (let i = 0; i < this.ingList.length; i++) {
html += this.ingList[i].toHtml();
}

View File

@@ -11,7 +11,7 @@ import Utils from "../core/Utils.js";
* @constructor
* @param {App} app - The main view object for CyberChef.
*/
var HighlighterWaiter = function(app) {
const HighlighterWaiter = function(app) {
this.app = app;
this.mouseButtonDown = false;
@@ -41,11 +41,11 @@ HighlighterWaiter.OUTPUT = 1;
* @returns {boolean}
*/
HighlighterWaiter.prototype._isSelectionBackwards = function() {
var backwards = false,
let backwards = false,
sel = window.getSelection();
if (!sel.isCollapsed) {
var range = document.createRange();
const range = document.createRange();
range.setStart(sel.anchorNode, sel.anchorOffset);
range.setEnd(sel.focusNode, sel.focusOffset);
backwards = range.collapsed;
@@ -64,8 +64,8 @@ HighlighterWaiter.prototype._isSelectionBackwards = function() {
* @returns {number}
*/
HighlighterWaiter.prototype._getOutputHtmlOffset = function(node, offset) {
var sel = window.getSelection(),
range = document.createRange();
const sel = window.getSelection();
const range = document.createRange();
range.selectNodeContents(document.getElementById("output-html"));
range.setEnd(node, offset);
@@ -85,8 +85,8 @@ HighlighterWaiter.prototype._getOutputHtmlOffset = function(node, offset) {
* @returns {number} pos.end
*/
HighlighterWaiter.prototype._getOutputHtmlSelectionOffsets = function() {
var sel = window.getSelection(),
range,
const sel = window.getSelection();
let range,
start = 0,
end = 0,
backwards = false;
@@ -121,7 +121,7 @@ HighlighterWaiter.prototype._getOutputHtmlSelectionOffsets = function() {
* @param {event} e
*/
HighlighterWaiter.prototype.inputScroll = function(e) {
var el = e.target;
const el = e.target;
document.getElementById("input-highlighter").scrollTop = el.scrollTop;
document.getElementById("input-highlighter").scrollLeft = el.scrollLeft;
};
@@ -134,7 +134,7 @@ HighlighterWaiter.prototype.inputScroll = function(e) {
* @param {event} e
*/
HighlighterWaiter.prototype.outputScroll = function(e) {
var el = e.target;
const el = e.target;
document.getElementById("output-highlighter").scrollTop = el.scrollTop;
document.getElementById("output-highlighter").scrollLeft = el.scrollLeft;
};
@@ -151,9 +151,9 @@ HighlighterWaiter.prototype.inputMousedown = function(e) {
this.mouseTarget = HighlighterWaiter.INPUT;
this.removeHighlights();
var el = e.target,
start = el.selectionStart,
end = el.selectionEnd;
const el = e.target;
const start = el.selectionStart;
const end = el.selectionEnd;
if (start !== 0 || end !== 0) {
document.getElementById("input-selection-info").innerHTML = this.selectionInfo(start, end);
@@ -173,9 +173,9 @@ HighlighterWaiter.prototype.outputMousedown = function(e) {
this.mouseTarget = HighlighterWaiter.OUTPUT;
this.removeHighlights();
var el = e.target,
start = el.selectionStart,
end = el.selectionEnd;
const el = e.target;
const start = el.selectionStart;
const end = el.selectionEnd;
if (start !== 0 || end !== 0) {
document.getElementById("output-selection-info").innerHTML = this.selectionInfo(start, end);
@@ -194,7 +194,7 @@ HighlighterWaiter.prototype.outputHtmlMousedown = function(e) {
this.mouseButtonDown = true;
this.mouseTarget = HighlighterWaiter.OUTPUT;
var sel = this._getOutputHtmlSelectionOffsets();
const sel = this._getOutputHtmlSelectionOffsets();
if (sel.start !== 0 || sel.end !== 0) {
document.getElementById("output-selection-info").innerHTML = this.selectionInfo(sel.start, sel.end);
}
@@ -244,9 +244,9 @@ HighlighterWaiter.prototype.inputMousemove = function(e) {
this.mouseTarget !== HighlighterWaiter.INPUT)
return;
var el = e.target,
start = el.selectionStart,
end = el.selectionEnd;
const el = e.target;
const start = el.selectionStart;
const end = el.selectionEnd;
if (start !== 0 || end !== 0) {
document.getElementById("input-selection-info").innerHTML = this.selectionInfo(start, end);
@@ -268,9 +268,9 @@ HighlighterWaiter.prototype.outputMousemove = function(e) {
this.mouseTarget !== HighlighterWaiter.OUTPUT)
return;
var el = e.target,
start = el.selectionStart,
end = el.selectionEnd;
const el = e.target;
const start = el.selectionStart;
const end = el.selectionEnd;
if (start !== 0 || end !== 0) {
document.getElementById("output-selection-info").innerHTML = this.selectionInfo(start, end);
@@ -292,7 +292,7 @@ HighlighterWaiter.prototype.outputHtmlMousemove = function(e) {
this.mouseTarget !== HighlighterWaiter.OUTPUT)
return;
var sel = this._getOutputHtmlSelectionOffsets();
const sel = this._getOutputHtmlSelectionOffsets();
if (sel.start !== 0 || sel.end !== 0) {
document.getElementById("output-selection-info").innerHTML = this.selectionInfo(sel.start, sel.end);
}
@@ -308,11 +308,11 @@ HighlighterWaiter.prototype.outputHtmlMousemove = function(e) {
* @returns {string}
*/
HighlighterWaiter.prototype.selectionInfo = function(start, end) {
var width = end.toString().length;
width = width < 2 ? 2 : width;
var startStr = Utils.pad(start.toString(), width, " ").replace(/ /g, "&nbsp;"),
endStr = Utils.pad(end.toString(), width, " ").replace(/ /g, "&nbsp;"),
lenStr = Utils.pad((end-start).toString(), width, " ").replace(/ /g, "&nbsp;");
const len = end.toString().length;
const width = len < 2 ? 2 : len;
const startStr = Utils.pad(start.toString(), width, " ").replace(/ /g, "&nbsp;");
const endStr = Utils.pad(end.toString(), width, " ").replace(/ /g, "&nbsp;");
const lenStr = Utils.pad((end-start).toString(), width, " ").replace(/ /g, "&nbsp;");
return "start: " + startStr + "<br>end: " + endStr + "<br>length: " + lenStr;
};
@@ -339,16 +339,16 @@ HighlighterWaiter.prototype.removeHighlights = function() {
* @returns {Object[]} highlights[].args
*/
HighlighterWaiter.prototype.generateHighlightList = function() {
var recipeConfig = this.app.getRecipeConfig(),
highlights = [];
const recipeConfig = this.app.getRecipeConfig();
const highlights = [];
for (var i = 0; i < recipeConfig.length; i++) {
for (let i = 0; i < recipeConfig.length; i++) {
if (recipeConfig[i].disabled) continue;
// If any breakpoints are set, do not attempt to highlight
if (recipeConfig[i].breakpoint) return false;
var op = this.app.operations[recipeConfig[i].op];
const op = this.app.operations[recipeConfig[i].op];
// If any of the operations do not support highlighting, fail immediately.
if (op.highlight === false || op.highlight === undefined) return false;
@@ -376,13 +376,13 @@ HighlighterWaiter.prototype.generateHighlightList = function() {
* @param {number} pos.end - The end offset.
*/
HighlighterWaiter.prototype.highlightOutput = function(pos) {
var highlights = this.generateHighlightList();
const highlights = this.generateHighlightList();
if (!highlights || !this.app.autoBake_) {
return false;
}
for (var i = 0; i < highlights.length; i++) {
for (let i = 0; i < highlights.length; i++) {
// Remove multiple highlights before processing again
pos = [pos[0]];
@@ -411,13 +411,13 @@ HighlighterWaiter.prototype.highlightOutput = function(pos) {
* @param {number} pos.end - The end offset.
*/
HighlighterWaiter.prototype.highlightInput = function(pos) {
var highlights = this.generateHighlightList();
const highlights = this.generateHighlightList();
if (!highlights || !this.app.autoBake_) {
return false;
}
for (var i = 0; i < highlights.length; i++) {
for (let i = 0; i < highlights.length; i++) {
// Remove multiple highlights before processing again
pos = [pos[0]];
@@ -452,11 +452,11 @@ HighlighterWaiter.prototype.highlight = function(textarea, highlighter, pos) {
// be displayed by the HTML textarea and will mess up highlighting offsets.
if (!this.app.dishStr || this.app.dishStr.indexOf("\r") >= 0) return false;
var startPlaceholder = "[startHighlight]",
startPlaceholderRegex = /\[startHighlight\]/g,
endPlaceholder = "[endHighlight]",
endPlaceholderRegex = /\[endHighlight\]/g,
text = textarea.value;
const startPlaceholder = "[startHighlight]";
const startPlaceholderRegex = /\[startHighlight\]/g;
const endPlaceholder = "[endHighlight]";
const endPlaceholderRegex = /\[endHighlight\]/g;
let text = textarea.value;
// Put placeholders in position
// If there's only one value, select that
@@ -468,11 +468,11 @@ HighlighterWaiter.prototype.highlight = function(textarea, highlighter, pos) {
text.slice(pos[0].end, text.length);
} else {
// O(n^2) - Can anyone improve this without overwriting placeholders?
var result = "",
let result = "",
endPlaced = true;
for (var i = 0; i < text.length; i++) {
for (var j = 1; j < pos.length; j++) {
for (let i = 0; i < text.length; i++) {
for (let j = 1; j < pos.length; j++) {
if (pos[j].end < pos[j].start) continue;
if (pos[j].start === i) {
result += startPlaceholder;
@@ -489,17 +489,18 @@ HighlighterWaiter.prototype.highlight = function(textarea, highlighter, pos) {
text = result;
}
var cssClass = "hl1";
const cssClass = "hl1";
//if (colour) cssClass += "-"+colour;
// Remove HTML tags
text = text.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/\n/g, "&#10;")
// Convert placeholders to tags
.replace(startPlaceholderRegex, "<span class=\""+cssClass+"\">")
.replace(endPlaceholderRegex, "</span>") + "&nbsp;";
text = text
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/\n/g, "&#10;")
// Convert placeholders to tags
.replace(startPlaceholderRegex, "<span class=\""+cssClass+"\">")
.replace(endPlaceholderRegex, "</span>") + "&nbsp;";
// Adjust width to allow for scrollbars
highlighter.style.width = textarea.clientWidth + "px";

View File

@@ -12,7 +12,7 @@ import Utils from "../core/Utils.js";
* @param {App} app - The main view object for CyberChef.
* @param {Manager} manager - The CyberChef event manager.
*/
var InputWaiter = function(app, manager) {
const InputWaiter = function(app, manager) {
this.app = app;
this.manager = manager;
@@ -66,11 +66,11 @@ InputWaiter.prototype.set = function(input) {
* @param {number} lines - The number of the lines in the current input string
*/
InputWaiter.prototype.setInputInfo = function(length, lines) {
var width = length.toString().length;
let width = length.toString().length;
width = width < 2 ? 2 : width;
var lengthStr = Utils.pad(length.toString(), width, " ").replace(/ /g, "&nbsp;");
var linesStr = Utils.pad(lines.toString(), width, " ").replace(/ /g, "&nbsp;");
const lengthStr = Utils.pad(length.toString(), width, " ").replace(/ /g, "&nbsp;");
const linesStr = Utils.pad(lines.toString(), width, " ").replace(/ /g, "&nbsp;");
document.getElementById("input-info").innerHTML = "length: " + lengthStr + "<br>lines: " + linesStr;
};
@@ -92,8 +92,8 @@ InputWaiter.prototype.inputChange = function(e) {
this.app.progress = 0;
// Update the input metadata info
var inputText = this.get(),
lines = inputText.count("\n") + 1;
const inputText = this.get();
const lines = inputText.count("\n") + 1;
this.setInputInfo(inputText.length, lines);
@@ -149,42 +149,42 @@ InputWaiter.prototype.inputDrop = function(e) {
e.stopPropagation();
e.preventDefault();
var el = e.target,
file = e.dataTransfer.files[0],
text = e.dataTransfer.getData("Text"),
reader = new FileReader(),
inputCharcode = "",
offset = 0,
CHUNK_SIZE = 20480; // 20KB
const el = e.target;
const file = e.dataTransfer.files[0];
const text = e.dataTransfer.getData("Text");
const reader = new FileReader();
let inputCharcode = "";
let offset = 0;
const CHUNK_SIZE = 20480; // 20KB
var setInput = function() {
const setInput = function() {
if (inputCharcode.length > 100000 && this.app.autoBake_) {
this.manager.controls.setAutoBake(false);
this.app.alert("Turned off Auto Bake as the input is large", "warning", 5000);
}
this.set(inputCharcode);
var recipeConfig = this.app.getRecipeConfig();
const recipeConfig = this.app.getRecipeConfig();
if (!recipeConfig[0] || recipeConfig[0].op !== "From Hex") {
recipeConfig.unshift({op:"From Hex", args:["Space"]});
recipeConfig.unshift({op: "From Hex", args: ["Space"]});
this.app.setRecipeConfig(recipeConfig);
}
el.classList.remove("loadingFile");
}.bind(this);
var seek = function() {
const seek = function() {
if (offset >= file.size) {
setInput();
return;
}
el.value = "Processing... " + Math.round(offset / file.size * 100) + "%";
var slice = file.slice(offset, offset + CHUNK_SIZE);
const slice = file.slice(offset, offset + CHUNK_SIZE);
reader.readAsArrayBuffer(slice);
};
reader.onload = function(e) {
var data = new Uint8Array(reader.result);
const data = new Uint8Array(reader.result);
inputCharcode += Utils.toHexFast(data);
offset += CHUNK_SIZE;
seek();

View File

@@ -19,7 +19,7 @@ import SeasonalWaiter from "./SeasonalWaiter.js";
* @constructor
* @param {App} app - The main view object for CyberChef.
*/
var Manager = function(app) {
const Manager = function(app) {
this.app = app;
// Define custom events
@@ -27,6 +27,10 @@ var Manager = function(app) {
* @event Manager#appstart
*/
this.appstart = new CustomEvent("appstart", {bubbles: true});
/**
* @event Manager#apploaded
*/
this.apploaded = new CustomEvent("apploaded", {bubbles: true});
/**
* @event Manager#operationadd
*/
@@ -98,7 +102,7 @@ Manager.prototype.initialiseEventListeners = function() {
document.getElementById("load-name").addEventListener("change", this.controls.loadNameChange.bind(this.controls));
document.getElementById("load-button").addEventListener("click", this.controls.loadButtonClick.bind(this.controls));
document.getElementById("support").addEventListener("click", this.controls.supportButtonClick.bind(this.controls));
this.addMultiEventListener("#save-text", "keyup paste", this.controls.saveTextChange, this.controls);
this.addMultiEventListeners("#save-texts textarea", "keyup paste", this.controls.saveTextChange, this.controls);
// Operations
this.addMultiEventListener("#search", "keyup paste search", this.ops.searchOperations, this.ops);
@@ -145,6 +149,7 @@ Manager.prototype.initialiseEventListeners = function() {
document.getElementById("output-html").addEventListener("mousemove", this.highlighter.outputHtmlMousemove.bind(this.highlighter));
this.addMultiEventListener("#output-text", "mousedown dblclick select", this.highlighter.outputMousedown, this.highlighter);
this.addMultiEventListener("#output-html", "mousedown dblclick select", this.highlighter.outputHtmlMousedown, this.highlighter);
this.addDynamicListener(".file-switch", "click", this.output.fileSwitch, this.output);
// Options
document.getElementById("options").addEventListener("click", this.options.optionsClick.bind(this.options));
@@ -154,6 +159,7 @@ Manager.prototype.initialiseEventListeners = function() {
this.addDynamicListener(".option-item input[type=number]", "keyup", this.options.numberChange, this.options);
this.addDynamicListener(".option-item input[type=number]", "change", this.options.numberChange, this.options);
this.addDynamicListener(".option-item select", "change", this.options.selectChange, this.options);
document.getElementById("theme").addEventListener("change", this.options.themeChange.bind(this.options));
// Misc
document.getElementById("alert-close").addEventListener("click", this.app.alertCloseClick.bind(this.app));
@@ -195,8 +201,8 @@ Manager.prototype.addListeners = function(selector, eventType, callback, scope)
* this.addMultiEventListener("search", "keyup paste search", this.search, this);
*/
Manager.prototype.addMultiEventListener = function(selector, eventTypes, callback, scope) {
var evs = eventTypes.split(" ");
for (var i = 0; i < evs.length; i++) {
const evs = eventTypes.split(" ");
for (let i = 0; i < evs.length; i++) {
document.querySelector(selector).addEventListener(evs[i], callback.bind(scope));
}
};
@@ -216,8 +222,8 @@ Manager.prototype.addMultiEventListener = function(selector, eventTypes, callbac
* this.addMultiEventListener(".saveable", "keyup paste", this.save, this);
*/
Manager.prototype.addMultiEventListeners = function(selector, eventTypes, callback, scope) {
var evs = eventTypes.split(" ");
for (var i = 0; i < evs.length; i++) {
const evs = eventTypes.split(" ");
for (let i = 0; i < evs.length; i++) {
this.addListeners(selector, evs[i], callback, scope);
}
};
@@ -238,7 +244,7 @@ Manager.prototype.addMultiEventListeners = function(selector, eventTypes, callba
* this.addDynamicListener("button", "click", alert, this);
*/
Manager.prototype.addDynamicListener = function(selector, eventType, callback, scope) {
var eventConfig = {
const eventConfig = {
selector: selector,
callback: callback.bind(scope || this)
};
@@ -261,15 +267,16 @@ Manager.prototype.addDynamicListener = function(selector, eventType, callback, s
* @param {Event} e - The event to be handled
*/
Manager.prototype.dynamicListenerHandler = function(e) {
var handlers = this.dynamicHandlers[e.type],
matches = e.target.matches ||
e.target.webkitMatchesSelector ||
e.target.mozMatchesSelector ||
e.target.msMatchesSelector ||
e.target.oMatchesSelector;
const { type, target } = e;
const handlers = this.dynamicHandlers[type];
const matches = target.matches ||
target.webkitMatchesSelector ||
target.mozMatchesSelector ||
target.msMatchesSelector ||
target.oMatchesSelector;
for (var i = 0; i < handlers.length; i++) {
if (matches && e.target[matches.name](handlers[i].selector)) {
for (let i = 0; i < handlers.length; i++) {
if (matches && matches.call(target, handlers[i].selector)) {
handlers[i].callback(e);
}
}

View File

@@ -13,7 +13,7 @@ import Sortable from "sortablejs";
* @param {App} app - The main view object for CyberChef.
* @param {Manager} manager - The CyberChef event manager.
*/
var OperationsWaiter = function(app, manager) {
const OperationsWaiter = function(app, manager) {
this.app = app;
this.manager = manager;
@@ -29,7 +29,7 @@ var OperationsWaiter = function(app, manager) {
* @param {event} e
*/
OperationsWaiter.prototype.searchOperations = function(e) {
var ops, selected;
let ops, selected;
if (e.type === "search") { // Search
e.preventDefault();
@@ -68,9 +68,9 @@ OperationsWaiter.prototype.searchOperations = function(e) {
ops[selected-1].classList.add("selected-op");
}
} else {
var searchResultsEl = document.getElementById("search-results"),
el = e.target,
str = el.value;
const searchResultsEl = document.getElementById("search-results");
const el = e.target;
const str = el.value;
while (searchResultsEl.firstChild) {
try {
@@ -81,12 +81,10 @@ OperationsWaiter.prototype.searchOperations = function(e) {
$("#categories .in").collapse("hide");
if (str) {
var matchedOps = this.filterOperations(str, true),
matchedOpsHtml = "";
for (var i = 0; i < matchedOps.length; i++) {
matchedOpsHtml += matchedOps[i].toStubHtml();
}
const matchedOps = this.filterOperations(str, true);
const matchedOpsHtml = matchedOps
.map(v => v.toStubHtml())
.join("");
searchResultsEl.innerHTML = matchedOpsHtml;
searchResultsEl.dispatchEvent(this.manager.oplistcreate);
@@ -103,19 +101,19 @@ OperationsWaiter.prototype.searchOperations = function(e) {
* name and description
* @returns {string[]}
*/
OperationsWaiter.prototype.filterOperations = function(searchStr, highlight) {
var matchedOps = [],
matchedDescs = [];
OperationsWaiter.prototype.filterOperations = function(inStr, highlight) {
const matchedOps = [];
const matchedDescs = [];
searchStr = searchStr.toLowerCase();
const searchStr = inStr.toLowerCase();
for (var opName in this.app.operations) {
var op = this.app.operations[opName],
namePos = opName.toLowerCase().indexOf(searchStr),
descPos = op.description.toLowerCase().indexOf(searchStr);
for (const opName in this.app.operations) {
const op = this.app.operations[opName];
const namePos = opName.toLowerCase().indexOf(searchStr);
const descPos = op.description.toLowerCase().indexOf(searchStr);
if (namePos >= 0 || descPos >= 0) {
var operation = new HTMLOperation(opName, this.app.operations[opName], this.app, this.manager);
const operation = new HTMLOperation(opName, this.app.operations[opName], this.app, this.manager);
if (highlight) {
operation.highlightSearchString(searchStr, namePos, descPos);
}
@@ -140,7 +138,7 @@ OperationsWaiter.prototype.filterOperations = function(searchStr, highlight) {
* @returns {number}
*/
OperationsWaiter.prototype.getSelectedOp = function(ops) {
for (var i = 0; i < ops.length; i++) {
for (let i = 0; i < ops.length; i++) {
if (ops[i].classList.contains("selected-op")) {
return i;
}
@@ -157,7 +155,35 @@ OperationsWaiter.prototype.getSelectedOp = function(ops) {
*/
OperationsWaiter.prototype.opListCreate = function(e) {
this.manager.recipe.createSortableSeedList(e.target);
$("[data-toggle=popover]").popover();
this.enableOpsListPopovers(e.target);
};
/**
* Sets up popovers, allowing the popover itself to gain focus which enables scrolling
* and other interactions.
*
* @param {Element} el - The element to start selecting from
*/
OperationsWaiter.prototype.enableOpsListPopovers = function(el) {
$(el).find("[data-toggle=popover]").addBack("[data-toggle=popover]")
.popover({trigger: "manual"})
.on("mouseenter", function() {
const _this = this;
$(this).popover("show");
$(".popover").on("mouseleave", function () {
$(_this).popover("hide");
});
}).on("mouseleave", function () {
const _this = this;
setTimeout(function() {
// Determine if the popover associated with this element is being hovered over
if ($(_this).data("bs.popover") &&
!$(_this).data("bs.popover").$tip.is(":hover")) {
$(_this).popover("hide");
}
}, 50);
});
};
@@ -168,7 +194,7 @@ OperationsWaiter.prototype.opListCreate = function(e) {
* @param {event} e
*/
OperationsWaiter.prototype.operationDblclick = function(e) {
var li = e.target;
const li = e.target;
this.manager.recipe.addOperation(li.textContent);
this.app.autoBake();
@@ -186,25 +212,25 @@ OperationsWaiter.prototype.editFavouritesClick = function(e) {
e.stopPropagation();
// Add favourites to modal
var favCat = this.app.categories.filter(function(c) {
const favCat = this.app.categories.filter(function(c) {
return c.name === "Favourites";
})[0];
var html = "";
for (var i = 0; i < favCat.ops.length; i++) {
var opName = favCat.ops[i];
var operation = new HTMLOperation(opName, this.app.operations[opName], this.app, this.manager);
let html = "";
for (let i = 0; i < favCat.ops.length; i++) {
const opName = favCat.ops[i];
const operation = new HTMLOperation(opName, this.app.operations[opName], this.app, this.manager);
html += operation.toStubHtml(true);
}
var editFavouritesList = document.getElementById("edit-favourites-list");
const editFavouritesList = document.getElementById("edit-favourites-list");
editFavouritesList.innerHTML = html;
this.removeIntent = false;
var editableList = Sortable.create(editFavouritesList, {
const editableList = Sortable.create(editFavouritesList, {
filter: ".remove-icon",
onFilter: function (evt) {
var el = editableList.closest(evt.item);
const el = editableList.closest(evt.item);
if (el) {
$(el).popover("destroy");
el.parentNode.removeChild(el);
@@ -236,12 +262,8 @@ OperationsWaiter.prototype.editFavouritesClick = function(e) {
* Saves the selected favourites and reloads them.
*/
OperationsWaiter.prototype.saveFavouritesClick = function() {
var favouritesList = [],
favs = document.querySelectorAll("#edit-favourites-list li");
for (var i = 0; i < favs.length; i++) {
favouritesList.push(favs[i].textContent);
}
const favs = document.querySelectorAll("#edit-favourites-list li");
const favouritesList = Array.from(favs, e => e.textContent);
this.app.saveFavourites(favouritesList);
this.app.loadFavourites();
@@ -266,7 +288,7 @@ OperationsWaiter.prototype.resetFavouritesClick = function() {
* @param {event} e
*/
OperationsWaiter.prototype.opIconMouseover = function(e) {
var opEl = e.target.parentNode;
const opEl = e.target.parentNode;
if (e.target.getAttribute("data-toggle") === "popover") {
$(opEl).popover("hide");
}
@@ -281,8 +303,8 @@ OperationsWaiter.prototype.opIconMouseover = function(e) {
* @param {event} e
*/
OperationsWaiter.prototype.opIconMouseleave = function(e) {
var opEl = e.target.parentNode,
toEl = e.toElement || e.relatedElement;
const opEl = e.target.parentNode;
const toEl = e.toElement || e.relatedElement;
if (e.target.getAttribute("data-toggle") === "popover" && toEl === opEl) {
$(opEl).popover("show");

View File

@@ -8,7 +8,7 @@
* @constructor
* @param {App} app - The main view object for CyberChef.
*/
var OptionsWaiter = function(app) {
const OptionsWaiter = function(app) {
this.app = app;
};
@@ -24,26 +24,32 @@ OptionsWaiter.prototype.load = function(options) {
animate: false,
});
for (var option in options) {
for (const option in options) {
this.app.options[option] = options[option];
}
// Set options to match object
var cboxes = document.querySelectorAll("#options-body input[type=checkbox]");
for (var i = 0; i < cboxes.length; i++) {
const cboxes = document.querySelectorAll("#options-body input[type=checkbox]");
let i;
for (i = 0; i < cboxes.length; i++) {
$(cboxes[i]).bootstrapSwitch("state", this.app.options[cboxes[i].getAttribute("option")]);
}
var nboxes = document.querySelectorAll("#options-body input[type=number]");
const nboxes = document.querySelectorAll("#options-body input[type=number]");
for (i = 0; i < nboxes.length; i++) {
nboxes[i].value = this.app.options[nboxes[i].getAttribute("option")];
nboxes[i].dispatchEvent(new CustomEvent("change", {bubbles: true}));
}
var selects = document.querySelectorAll("#options-body select");
const selects = document.querySelectorAll("#options-body select");
for (i = 0; i < selects.length; i++) {
selects[i].value = this.app.options[selects[i].getAttribute("option")];
selects[i].dispatchEvent(new CustomEvent("change", {bubbles: true}));
const val = this.app.options[selects[i].getAttribute("option")];
if (val) {
selects[i].value = val;
selects[i].dispatchEvent(new CustomEvent("change", {bubbles: true}));
} else {
selects[i].selectedIndex = 0;
}
}
};
@@ -51,8 +57,11 @@ OptionsWaiter.prototype.load = function(options) {
/**
* Handler for options click events.
* Dispays the options pane.
*
* @param {event} e
*/
OptionsWaiter.prototype.optionsClick = function() {
OptionsWaiter.prototype.optionsClick = function(e) {
e.preventDefault();
$("#options-modal").modal();
};
@@ -74,8 +83,8 @@ OptionsWaiter.prototype.resetOptionsClick = function() {
* @param {boolean} state
*/
OptionsWaiter.prototype.switchChange = function(e, state) {
var el = e.target,
option = el.getAttribute("option");
const el = e.target;
const option = el.getAttribute("option");
this.app.options[option] = state;
localStorage.setItem("options", JSON.stringify(this.app.options));
@@ -89,8 +98,8 @@ OptionsWaiter.prototype.switchChange = function(e, state) {
* @param {event} e
*/
OptionsWaiter.prototype.numberChange = function(e) {
var el = e.target,
option = el.getAttribute("option");
const el = e.target;
const option = el.getAttribute("option");
this.app.options[option] = parseInt(el.value, 10);
localStorage.setItem("options", JSON.stringify(this.app.options));
@@ -104,8 +113,8 @@ OptionsWaiter.prototype.numberChange = function(e) {
* @param {event} e
*/
OptionsWaiter.prototype.selectChange = function(e) {
var el = e.target,
option = el.getAttribute("option");
const el = e.target;
const option = el.getAttribute("option");
this.app.options[option] = el.value;
localStorage.setItem("options", JSON.stringify(this.app.options));
@@ -131,4 +140,14 @@ OptionsWaiter.prototype.setWordWrap = function() {
}
};
/**
* Changes the theme by setting the class of the <html> element.
*/
OptionsWaiter.prototype.themeChange = function (e) {
const themeClass = e.target.value;
document.querySelector(":root").className = themeClass;
};
export default OptionsWaiter;

View File

@@ -12,7 +12,7 @@ import Utils from "../core/Utils.js";
* @param {App} app - The main view object for CyberChef.
* @param {Manager} manager - The CyberChef event manager.
*/
var OutputWaiter = function(app, manager) {
const OutputWaiter = function(app, manager) {
this.app = app;
this.manager = manager;
};
@@ -36,10 +36,10 @@ OutputWaiter.prototype.get = function() {
* @param {number} duration - The length of time (ms) it took to generate the output
*/
OutputWaiter.prototype.set = function(dataStr, type, duration) {
var outputText = document.getElementById("output-text"),
outputHtml = document.getElementById("output-html"),
outputHighlighter = document.getElementById("output-highlighter"),
inputHighlighter = document.getElementById("input-highlighter");
const outputText = document.getElementById("output-text");
const outputHtml = document.getElementById("output-html");
const outputHighlighter = document.getElementById("output-highlighter");
const inputHighlighter = document.getElementById("input-highlighter");
if (type === "html") {
outputText.style.display = "none";
@@ -51,8 +51,8 @@ OutputWaiter.prototype.set = function(dataStr, type, duration) {
outputHtml.innerHTML = dataStr;
// Execute script sections
var scriptElements = outputHtml.querySelectorAll("script");
for (var i = 0; i < scriptElements.length; i++) {
const scriptElements = outputHtml.querySelectorAll("script");
for (let i = 0; i < scriptElements.length; i++) {
try {
eval(scriptElements[i].innerHTML); // eslint-disable-line no-eval
} catch (err) {
@@ -70,7 +70,7 @@ OutputWaiter.prototype.set = function(dataStr, type, duration) {
}
this.manager.highlighter.removeHighlights();
var lines = dataStr.count("\n") + 1;
const lines = dataStr.count("\n") + 1;
this.setOutputInfo(dataStr.length, lines, duration);
};
@@ -83,12 +83,12 @@ OutputWaiter.prototype.set = function(dataStr, type, duration) {
* @param {number} duration - The length of time (ms) it took to generate the output
*/
OutputWaiter.prototype.setOutputInfo = function(length, lines, duration) {
var width = length.toString().length;
let width = length.toString().length;
width = width < 4 ? 4 : width;
var lengthStr = Utils.pad(length.toString(), width, " ").replace(/ /g, "&nbsp;");
var linesStr = Utils.pad(lines.toString(), width, " ").replace(/ /g, "&nbsp;");
var timeStr = Utils.pad(duration.toString() + "ms", width, " ").replace(/ /g, "&nbsp;");
const lengthStr = Utils.pad(length.toString(), width, " ").replace(/ /g, "&nbsp;");
const linesStr = Utils.pad(lines.toString(), width, " ").replace(/ /g, "&nbsp;");
const timeStr = Utils.pad(duration.toString() + "ms", width, " ").replace(/ /g, "&nbsp;");
document.getElementById("output-info").innerHTML = "time: " + timeStr +
"<br>length: " + lengthStr +
@@ -103,11 +103,11 @@ OutputWaiter.prototype.setOutputInfo = function(length, lines, duration) {
* without wrapping or overflowing.
*/
OutputWaiter.prototype.adjustWidth = function() {
var output = document.getElementById("output"),
saveToFile = document.getElementById("save-to-file"),
switchIO = document.getElementById("switch"),
undoSwitch = document.getElementById("undo-switch"),
maximiseOutput = document.getElementById("maximise-output");
const output = document.getElementById("output");
const saveToFile = document.getElementById("save-to-file");
const switchIO = document.getElementById("switch");
const undoSwitch = document.getElementById("undo-switch");
const maximiseOutput = document.getElementById("maximise-output");
if (output.clientWidth < 680) {
saveToFile.childNodes[1].nodeValue = "";
@@ -129,11 +129,11 @@ OutputWaiter.prototype.adjustWidth = function() {
* Saves the current output to a file, downloaded as a URL octet stream.
*/
OutputWaiter.prototype.saveClick = function() {
var data = Utils.toBase64(this.app.dishStr),
filename = window.prompt("Please enter a filename:", "download.dat");
const data = Utils.toBase64(this.app.dishStr);
const filename = window.prompt("Please enter a filename:", "download.dat");
if (filename) {
var el = document.createElement("a");
const el = document.createElement("a");
el.setAttribute("href", "data:application/octet-stream;base64;charset=utf-8," + data);
el.setAttribute("download", filename);
@@ -167,13 +167,24 @@ OutputWaiter.prototype.undoSwitchClick = function() {
document.getElementById("undo-switch").disabled = true;
};
/**
* Handler for file switch click events.
* Moves a files data for items created via Utils.displayFilesAsHTML to the input.
*/
OutputWaiter.prototype.fileSwitch = function(e) {
e.preventDefault();
this.switchOrigData = this.manager.input.get();
this.app.setInput(e.target.getAttribute("fileValue"));
document.getElementById("undo-switch").disabled = false;
};
/**
* Handler for maximise output click events.
* Resizes the output frame to be as large as possible, or restores it to its original size.
*/
OutputWaiter.prototype.maximiseOutputClick = function(e) {
var el = e.target.id === "maximise-output" ? e.target : e.target.parentNode;
const el = e.target.id === "maximise-output" ? e.target : e.target.parentNode;
if (el.getAttribute("title") === "Maximise") {
this.app.columnSplitter.collapse(0);

View File

@@ -13,7 +13,7 @@ import Sortable from "sortablejs";
* @param {App} app - The main view object for CyberChef.
* @param {Manager} manager - The CyberChef event manager.
*/
var RecipeWaiter = function(app, manager) {
const RecipeWaiter = function(app, manager) {
this.app = app;
this.manager = manager;
this.removeIntent = false;
@@ -24,8 +24,7 @@ var RecipeWaiter = function(app, manager) {
* Sets up the drag and drop capability for operations in the operations and recipe areas.
*/
RecipeWaiter.prototype.initialiseOperationDragNDrop = function() {
var recList = document.getElementById("rec-list");
const recList = document.getElementById("rec-list");
// Recipe list
Sortable.create(recList, {
@@ -45,7 +44,9 @@ RecipeWaiter.prototype.initialiseOperationDragNDrop = function() {
}
}.bind(this),
onSort: function(evt) {
document.dispatchEvent(this.manager.statechange);
if (evt.from.id === "rec-list") {
document.dispatchEvent(this.manager.statechange);
}
}.bind(this)
});
@@ -59,8 +60,8 @@ RecipeWaiter.prototype.initialiseOperationDragNDrop = function() {
}.bind(this));
Sortable.utils.on(recList, "touchend", function(e) {
var loc = e.changedTouches[0],
target = document.elementFromPoint(loc.clientX, loc.clientY);
const loc = e.changedTouches[0];
const target = document.elementFromPoint(loc.clientX, loc.clientY);
this.removeIntent = !recList.contains(target);
}.bind(this));
@@ -75,21 +76,25 @@ RecipeWaiter.prototype.initialiseOperationDragNDrop = function() {
/**
* Creates a drag-n-droppable seed list of operations.
*
* @param {element} listEl - The list the initialise
* @param {element} listEl - The list to initialise
*/
RecipeWaiter.prototype.createSortableSeedList = function(listEl) {
Sortable.create(listEl, {
group: {
name: "recipe",
pull: "clone",
put: false
put: false,
},
sort: false,
setData: function(dataTransfer, dragEl) {
dataTransfer.setData("Text", dragEl.textContent);
},
onStart: function(evt) {
$(evt.item).popover("destroy");
// Removes popover element and event bindings from the dragged operation but not the
// event bindings from the one left in the operations list. Without manually removing
// these bindings, we cannot re-initialise the popover on the stub operation.
$(evt.item).popover("destroy").removeData("bs.popover").off("mouseenter").off("mouseleave");
$(evt.clone).off(".popover").removeData("bs.popover");
evt.item.setAttribute("data-toggle", "popover-disabled");
},
onEnd: this.opSortEnd.bind(this)
@@ -115,8 +120,7 @@ RecipeWaiter.prototype.opSortEnd = function(evt) {
// Reinitialise the popover on the original element in the ops list because for some reason it
// gets destroyed and recreated.
$(evt.clone).popover();
$(evt.clone).children("[data-toggle=popover]").popover();
this.manager.ops.enableOpsListPopovers(evt.clone);
if (evt.item.parentNode.id !== "rec-list") {
return;
@@ -177,7 +181,7 @@ RecipeWaiter.prototype.favDrop = function(e) {
e.preventDefault();
e.target.classList.remove("favourites-hover");
var opName = e.dataTransfer.getData("Text");
const opName = e.dataTransfer.getData("Text");
this.app.addFavourite(opName);
};
@@ -200,7 +204,7 @@ RecipeWaiter.prototype.ingChange = function() {
* @param {event} e
*/
RecipeWaiter.prototype.disableClick = function(e) {
var icon = e.target;
const icon = e.target;
if (icon.getAttribute("disabled") === "false") {
icon.setAttribute("disabled", "true");
@@ -225,7 +229,7 @@ RecipeWaiter.prototype.disableClick = function(e) {
* @param {event} e
*/
RecipeWaiter.prototype.breakpointClick = function(e) {
var bp = e.target;
const bp = e.target;
if (bp.getAttribute("break") === "false") {
bp.setAttribute("break", "true");
@@ -271,16 +275,17 @@ RecipeWaiter.prototype.operationChildDblclick = function(e) {
* @returns {recipeConfig}
*/
RecipeWaiter.prototype.getConfig = function() {
var config = [], ingredients, ingList, disabled, bp, item,
operations = document.querySelectorAll("#rec-list li.operation");
const config = [];
let ingredients, ingList, disabled, bp, item;
const operations = document.querySelectorAll("#rec-list li.operation");
for (var i = 0; i < operations.length; i++) {
for (let i = 0; i < operations.length; i++) {
ingredients = [];
disabled = operations[i].querySelector(".disable-icon");
bp = operations[i].querySelector(".breakpoint");
ingList = operations[i].querySelectorAll(".arg");
for (var j = 0; j < ingList.length; j++) {
for (let j = 0; j < ingList.length; j++) {
if (ingList[j].getAttribute("type") === "checkbox") {
// checkbox
ingredients[j] = ingList[j].checked;
@@ -290,6 +295,9 @@ RecipeWaiter.prototype.getConfig = function() {
option: ingList[j].previousSibling.children[0].textContent.slice(0, -1),
string: ingList[j].value
};
} else if (ingList[j].getAttribute("type") === "number") {
// number
ingredients[j] = parseFloat(ingList[j].value, 10);
} else {
// all others
ingredients[j] = ingList[j].value;
@@ -322,8 +330,8 @@ RecipeWaiter.prototype.getConfig = function() {
* @param {number} position
*/
RecipeWaiter.prototype.updateBreakpointIndicator = function(position) {
var operations = document.querySelectorAll("#rec-list li.operation");
for (var i = 0; i < operations.length; i++) {
const operations = document.querySelectorAll("#rec-list li.operation");
for (let i = 0; i < operations.length; i++) {
if (i === position) {
operations[i].classList.add("break");
} else {
@@ -340,16 +348,15 @@ RecipeWaiter.prototype.updateBreakpointIndicator = function(position) {
* @param {element} el - The operation stub element from the operations pane
*/
RecipeWaiter.prototype.buildRecipeOperation = function(el) {
var opName = el.textContent;
var op = new HTMLOperation(opName, this.app.operations[opName], this.app, this.manager);
const opName = el.textContent;
const op = new HTMLOperation(opName, this.app.operations[opName], this.app, this.manager);
el.innerHTML = op.toFullHtml();
if (this.app.operations[opName].flowControl) {
el.classList.add("flow-control-op");
}
// Disable auto-bake if this is a manual op - this should be moved to the 'operationadd'
// handler after event restructuring
// Disable auto-bake if this is a manual op
if (op.manualBake && this.app.autoBake_) {
this.manager.controls.setAutoBake(false);
this.app.alert("Auto-Bake is disabled by default when using this operation.", "info", 5000);
@@ -364,7 +371,7 @@ RecipeWaiter.prototype.buildRecipeOperation = function(el) {
* @returns {element}
*/
RecipeWaiter.prototype.addOperation = function(name) {
var item = document.createElement("li");
const item = document.createElement("li");
item.classList.add("operation");
item.innerHTML = name;
@@ -382,7 +389,7 @@ RecipeWaiter.prototype.addOperation = function(name) {
* @fires Manager#operationremove
*/
RecipeWaiter.prototype.clearRecipe = function() {
var recList = document.getElementById("rec-list");
const recList = document.getElementById("rec-list");
while (recList.firstChild) {
recList.removeChild(recList.firstChild);
}
@@ -397,8 +404,8 @@ RecipeWaiter.prototype.clearRecipe = function() {
* @param {event} e
*/
RecipeWaiter.prototype.dropdownToggleClick = function(e) {
var el = e.target,
button = el.parentNode.parentNode.previousSibling;
const el = e.target;
const button = el.parentNode.parentNode.previousSibling;
button.innerHTML = el.textContent + " <span class='caret'></span>";
this.ingChange();

View File

@@ -9,7 +9,7 @@
* @param {App} app - The main view object for CyberChef.
* @param {Manager} manager - The CyberChef event manager.
*/
var SeasonalWaiter = function(app, manager) {
const SeasonalWaiter = function(app, manager) {
this.app = app;
this.manager = manager;
};
@@ -19,69 +19,12 @@ var SeasonalWaiter = function(app, manager) {
* Loads all relevant items depending on the current date.
*/
SeasonalWaiter.prototype.load = function() {
//var now = new Date();
// SpiderChef
// if (now.getMonth() === 3 && now.getDate() === 1) { // Apr 1
// this.insertSpiderIcons();
// this.insertSpiderText();
// }
// Konami code
this.kkeys = [];
window.addEventListener("keydown", this.konamiCodeListener.bind(this));
};
/**
* Replaces chef icons with spider icons.
* #spiderchef
*/
SeasonalWaiter.prototype.insertSpiderIcons = function() {
var spider16 = "iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAAB3UlEQVQ4y2NgGJaAmYGBgVnf0oKJgYGBobWtXamqqoYTn2I4CI+LTzM2NTulpKbu+vPHz2dV5RWlluZmi3j5+KqFJSSEzpw8uQPdAEYYIzo5Kfjrl28rWFlZzjAzMYuEBQao3Lh+g+HGvbsMzExMDN++fWf4/PXLBzY2tqYNK1f2+4eHM2xcuRLigsT09Igf3384MTExbf767etBI319jU8fPsi+//jx/72HDxh5uLkZ7ty7y/Dz1687Avz8n2UUFR3Z2NjOySoqfmdhYGBg+PbtuwI7O8e5H79+8X379t357PnzYo+ePP7y6cuXc9++f69nYGRsvf/w4XdtLS2R799/bBUWFHr57sP7Jbs3b/ZkzswvUP3165fZ7z9//r988WIVAyPDr8tXr576+u3bpb9//7YwMjKeV1dV41NWVGoVEhDgPH761DJREeHaz1+/lqlpafUx6+jrRfz4+fPy+w8fTu/fsf3uw7t3L39+//4cv7DwGQYGhpdPbt9m4BcRFlNWVJC4fuvWASszs4C379792Ldt2xZBUdEdDP5hYSqQGIjDGa965uYKCalpZQwMDAxhMTG9DAwMDLaurhIkJY7A8IgGBgYGBgd3Dz2yUpeFo6O4rasrA9T24ZRxAAMTwMpgEJwLAAAAAElFTkSuQmCC",
spider32 = "iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAMAAABEpIrGAAACYVBMVEUAAAAcJSU2Pz85QkM9RUWEhIWMjI2MkJEcJSU2Pz85QkM9RUWWlpc9RUVXXl4cJSU2Pz85QkM8REU9RUVRWFh6ens9RUVCSkpNVFRdY2McJSU5QkM7REQ9RUVGTk5KUlJQVldcY2Rla2uTk5WampscJSVUWltZX2BrcHF1e3scJSUjLCw9RUVASEhFTU1HTk9bYWJeZGRma2xudHV1eHiZmZocJSUyOjpJUFFQVldSWlpTWVpXXl5YXl5rb3B9fX6RkZIcJSUmLy8tNTU9RUVFTU1IT1BOVldRV1hTWlp0enocJSUfKChJUFBWXV1hZ2hnbGwcJSVETExLUlJLU1NNVVVPVlZYXl9cY2RiaGlobW5rcXFyd3h0eHgcJSUpMTFDS0tQV1dRV1hSWFlWXF1bYWJma2tobW5uc3SsrK0cJSVJUFBMVFROVlZVW1xZX2BdYmNhZ2hjaGhla2tqcHBscHE4Pz9KUlJRWVlSWVlXXF1aYGFbYWFfZWZlampqbW4cJSUgKSkiKysuNjY0PD01PT07QkNES0tHTk5JUFBMUlNMU1NOU1ROVVVPVVZRVlZRV1dSWVlWXFxXXV5aX2BbYWFbYWJcYmJcYmNcY2RdYmNgZmZhZmdkaWpkampkamtlamtla2tma2tma2xnbG1obW5pbG1pb3Bqb3Brb3BtcXJudHVvcHFvcXJvc3NwcXNwdXVxc3RzeXl1eXp2eXl3ent6e3x+gYKAhISBg4SKi4yLi4yWlpeampudnZ6fn6CkpaanqKiur6+vr7C4uLm6urq6u7u8vLy9vb3Av8DR0dL2b74UAAAAgHRSTlMAEBAQEBAQECAgICAgMDBAQEBAQEBAUFBQUGBgYGBgYGBgYGBgcHBwcHCAgICAgICAgICAgICPj4+Pj4+Pj4+Pj5+fn5+fn5+fn5+vr6+vr6+/v7+/v7+/v7+/v7+/z8/Pz8/Pz8/Pz8/P39/f39/f39/f39/f7+/v7+/v7+/v78x6RlYAAAGBSURBVDjLY2AYWUCSgUGAk4GBTdlUhQebvP7yjIgCPQbWzBMnjx5wwJSX37Rwfm1isqj9/iPHTuxYlyeMJi+yunfptBkZOw/uWj9h3vatcycu8eRGlldb3Vsts3ph/cFTh7fN3bCoe2Vf8+TZoQhTvBa6REozVC7cuPvQnmULJm1e2z+308eyJieEBSLPXbKQIUqQIczk+N6eNaumtnZMaWhaHM89m8XVCqJA02Y5w0xmga6yfVsamtrN4xoXNzS0JTHkK3CXy4EVFMumcxUy2LbENTVkZfEzMDAudtJyTmNwS2XQreAFyvOlK9louDNVaXurmjkGgnTMkWDgXswtNouFISEX6Awv+RihQi5OcYY4DtVARpCCFCMGhiJ1hjwFBpagEAaWEpFoC0WQOCOjFMRRwXYMDB4BDLJ+QLYsg7GBGjtasLnEMjCIrWBgyAZ7058FI9x1SoFEnTCDsCyIhynPILYYSFgbYpUDA5bpQBluXzxpI1yYAbd2sCMYRhwAAHB9ZPztbuMUAAAAAElFTkSuQmCC",
spider64 = "iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAJZUlEQVR42u1ZaXMU1xXlJ+gHpFITOy5sAcnIYCi2aIL2bTSSZrSP1NpHK41kISQBHgFaQIJBCMwi4TFUGYcPzggwEMcxHVGxQaag5QR/np/QP+Hmnsdr0hpmtEACwulb9aq7p7d3zz333Pt61q2zzTbbbLPNNttss80222yzzTbbVmu7MzKcJRWVkXjntqam6jyURPeGQqeTpqbOqp+evxC5dGlam5m5rE3PzGi8Hzx/4aLzbXDe09HdYxwZHaPc4mLFXVoW9pRXGNv3pDngeHlNLfE2Ljjj4xPOUGjSYKfpq6/+TLdv36bbX39Nt27epGvXvqSLl6bp3LlPtdOnz7jWrPNZ7kLCKCovp5bOTmP/4EHq6vmYMtzuSKbbbQCAHE8Rxd47MjrmuHjxkjF3/z4tLCzQkyc6PX78mB49ekQPHjygub/P0d27f6FrX/6JpqbO0YkT48E1R/sCr9cYHZ+gqrp64mPq+riXcoqKKC0vP9q6VyV/fQOiH+LrsPVY7z82PBKZnb1Bd+7cpfn5eQbgCT1hAADC/MN5uj83R99881eanZ2lL5gN/nrxjihAXwvOJ7l9vuiBQ4dF9LEtLC0V+2rv/ijTX6luaCS3rxT57wADAMTBQ4c9PIIDg4PBwYOHaHhklM5MnSWkwLff/o0+v3qVHv34Iz344QEDc4d8VVXUEAhQXXMzVdQqzKweKq6oABARzOGNOZ+Wl6fD6T25ubQrPT0E5xF93o82tbdjkkZ+iZfAAgbD6fZ6o339A8S0p7HjJ2h4eIQOHf6EujlV9nX3UOj0JDXzfXje+KlTdOPGDeF0T1+fGHg+2JSen08tHZ0CiPySEoPn8vq1IaOgIAzneQK0UzjcQd6qaqrlCVfV1+tpubnRnv5+2p2ZqYMF/oZGPTh0xLhy5Sr9wLn9j++/p5nLn9FxBoLZQJ1dKrkys6iYNeTExEnx3PqWFuF4W9deKq2upkEGCyzyMBC709MFC7r391Fjayv9MSdHZyCU1xJ5FjrNdN6VnU1KS4CjU4Yoh/m8CsezCguFJgAMV05ueP+BfhF5OL+gL9A/f/qJ7t3TaPLMFB09eoy6mTkMGg2PjTELOsS20OcTACgMKqJugqA0NtE7ycn0202b6A+ZmYIVAAKApGZlgRHB/0lqQPAqFEVE9hntM0R0ZblTzeswWdCeU8HAtYW+Uu0AUx+0f/jwoXD+56c/073v7tHU2XMiFbrUfVTNAtfL10FIAQL2QftsBrOEnavld5kg7E7PoF+99x79ev162rJrV9RMi6a2dvKUlQsR5uAgII7/ivMsbEE4g2hggjzC7LQL1OftovoO0WJKUn0gYEAn2hmMXo4QHIXQIfLfsfOXPwuLvB86cpQqamooyEzg1BLMwv04RkoE+B3B4BBBMHEcCwIP0N+ByJdUVhpgBJ7j4WvdANDjeTUglOaWEChfJF7uJzPX2HEPaj1vg7EAbHO5QnAeIPgqKvUB7gtAdbBgcvKMqOnc/NAIVwCcq21qElFnCgvaI9cBBFKhlSPbPzBIbbzduGULpWzfLkDAdZs++sgEwSlZqoIJMg2CzFSNGzODwdBfOi26+w4YTCm9LhDQwQDzdzguFf4FALjciTws8/u1yyx2N2/dovPnL9DRY8PkZ204xtuhoSM0wI7V8DEiirQCCHD+99u2CUdx3Lmvmz7kfemoGDgPEDr4HNKAf1MlAC4wgMGLWFJXQUrklZSEX6rLE2rOyDIQGlhgBUAyYFEZkm2vAGVi4qQ+x83M0389pevXr6OToy07d4qcR+krr/KzqpeJ/IfjGO+npDx3FCKHVPjd1q2LAMBI3ryZ9vL7U56BEzLfD80ACFba876OlGCQV9dAcT0Pyw7PgWij6zPP5Xt9EYgg+n3LosdVzdfz5CI8KY1LH31+5Yro9KanZwjHmPzmHTsoOeVDemfDBuE8dGVnWpqx3unUrE4CDLCAG64XAHB88IFgQV5xMY7DFmc16A6CZvnNBYYVcW+yKj0A/VHTsQ8dwMPNc6X+Gg0VIGbVpzYGWundjRujmGQWi9Eol7+TJ0/R2Nhx2sNlM9YJRPDdDRsM5DGPJB4KHOIhngHhAwixAGAAuDZ2lsuiYnFWBQOYrdEYNochilyiV6YHoH+rRNJkAG+fUw31PzU7Z1EFKPD69CIuQ1Bm6URoh8tFmVym3nc6rZOPyi0cD8HxeHPg3x2InNrbS79JTsYzNXmPuBclsO3ZvKwAOJEGsmI5rT0M+gSf3y9K5LIA1LUEIlL1k0AhCYBH5r9TCqBqib4D+c/1PyInGOThkvuaHCYALhlpbQWBMGR/4IpzTqlpbKQyf0045vdoe0zATHagSYMeWFMkbscnHRYPZjoFJaIiUkz9EJy15j/X3qCsAIqMcFjSWrNE1Iygg0fEmrtLzEUTdT/OhBFht9fHDVCbEUt3LJxi08B8Xj6vTDESriq9lVWqBECgHujqiqAUmufb1X3cfRXoluhjZWiwkOnSUcUS6ZD8LUmmhks6b5j1ezkAkAKZBe5QvPPcNBnoCawMwT66Qxk0R2xwwRAui2iSDGuaPDcubzo3EJq8wcx/9Vmk3QryH42QBQCFF0UagIiJtjX6DskIXTLEucJSHIIIMuO0BOcjn3A3ybU/lu5RCUBc5qA0Ih0Q2EWiCPRk7VfMNhjLW1zETic1tLYZDMKyuSsdfh5l6bwho5+0il4kyA0VohlNcF5FP8DlWo/VB16HYB2hJ0pzgIe2mcXxP2IOumPRY17U0tll8KIkZNb+sppafOxYkQPSaYfchyYoL9GMqWYpTLRIq1QUcT4O3aPQgqVqPwIOIMwDhzX6mQUFIQAgo+9MzcrWrML3mj6+YIKiFCZyhL87RqVQKrEskF+P1BUvfLCAkfRwoPUtq6l5o5+lZb5SolJo6oT8avTCl+c9OTmat6pKW8mLkvBpGzlvsiGuQr4ZEEwA1EQgoR/gNtxIxKBluz+OtMJiF31jHxqXBiAqAUj4WRxpADFM0DCFlv1khvX7Wol4vF4AIldVVxdZqlrIfiCYQPHDy6bAGv7nKYRVY6JewExZVAP+ey5Rv+Ba97aaUHMW5NauLmMZFkegBb/EP14d6NoS9QLWFSzWBmuZza8CQmSpXsAqmGtVy14VALWuuYWWy+W3OteXa4jwceQX6+BKG6J1/8+2VCNkm2222WabbbbZZpttttlmm22rt38DCdA0vq3bcAkAAAAASUVORK5CYII=";
// Favicon
document.querySelector("link[rel=icon]").setAttribute("href", "data:image/png;base64," + spider16);
// Bake button
document.querySelector("#bake img").setAttribute("src", "data:image/png;base64," + spider32);
// About box
document.querySelector(".about-img-left").setAttribute("src", "data:image/png;base64," + spider64);
};
/**
* Replaces all instances of the word "cyber" with "spider".
* #spiderchef
*/
SeasonalWaiter.prototype.insertSpiderText = function() {
// Title
document.title = document.title.replace(/Cyber/g, "Spider");
// Body
SeasonalWaiter.treeWalk(document.body, function(node) {
// process only text nodes
if (node.nodeType === 3) {
node.nodeValue = node.nodeValue.replace(/Cyber/g, "Spider");
}
}, true);
// Bake button
SeasonalWaiter.treeWalk(document.getElementById("bake-group"), function(node) {
// process only text nodes
if (node.nodeType === 3) {
node.nodeValue = node.nodeValue.replace(/Bake/g, "Spin");
}
}, true);
// Recipe title
document.querySelector("#recipe .title").innerHTML = "Web";
};
/**
* Listen for the Konami code sequence of keys. Turn the page upside down if they are all heard in
* sequence.
@@ -89,8 +32,8 @@ SeasonalWaiter.prototype.insertSpiderText = function() {
*/
SeasonalWaiter.prototype.konamiCodeListener = function(e) {
this.kkeys.push(e.keyCode);
var konami = [38, 38, 40, 40, 37, 39, 37, 39, 66, 65];
for (var i = 0; i < this.kkeys.length; i++) {
const konami = [38, 38, 40, 40, 37, 39, 37, 39, 66, 65];
for (let i = 0; i < this.kkeys.length; i++) {
if (this.kkeys[i] !== konami[i]) {
this.kkeys = [];
break;
@@ -102,53 +45,4 @@ SeasonalWaiter.prototype.konamiCodeListener = function(e) {
}
};
/**
* Walks through the entire DOM starting at the specified element and operates on each node.
*
* @static
* @param {element} parent - The DOM node to start from
* @param {Function} fn - The callback function to operate on each node
* @param {booleam} allNodes - Whether to operate on every node or not
*/
SeasonalWaiter.treeWalk = (function() {
// Create closure for constants
var skipTags = {
"SCRIPT": true, "IFRAME": true, "OBJECT": true,
"EMBED": true, "STYLE": true, "LINK": true, "META": true
};
return function(parent, fn, allNodes) {
var node = parent.firstChild;
while (node && node !== parent) {
if (allNodes || node.nodeType === 1) {
if (fn(node) === false) {
return false;
}
}
// If it's an element &&
// has children &&
// has a tagname && is not in the skipTags list
// then, we can enumerate children
if (node.nodeType === 1 &&
node.firstChild &&
!(node.tagName && skipTags[node.tagName])) {
node = node.firstChild;
} else if (node.nextSibling) {
node = node.nextSibling;
} else {
// No child and no nextsibling
// Find parent that has a nextSibling
while ((node = node.parentNode) !== parent) {
if (node.nextSibling) {
node = node.nextSibling;
break;
}
}
}
}
};
})();
export default SeasonalWaiter;

View File

@@ -8,7 +8,7 @@
* @constructor
* @param {App} app - The main view object for CyberChef.
*/
var WindowWaiter = function(app) {
const WindowWaiter = function(app) {
this.app = app;
};
@@ -45,7 +45,7 @@ WindowWaiter.prototype.windowBlur = function() {
* a long time and the browser has swapped out all its memory.
*/
WindowWaiter.prototype.windowFocus = function() {
var unfocusedTime = new Date().getTime() - this.windowBlurTime;
const unfocusedTime = new Date().getTime() - this.windowBlurTime;
if (unfocusedTime > 60000) {
this.app.silentBake();
}

View File

@@ -1,18 +0,0 @@
/**
* CSS index
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2017
* @license Apache-2.0
*/
import "google-code-prettify/src/prettify.css";
import "./lib/bootstrap.less";
import "bootstrap-switch/src/less/bootstrap3/build.less";
import "bootstrap-colorpicker/dist/css/bootstrap-colorpicker.css";
import "./structure/overrides.css";
import "./structure/layout.css";
import "./structure/utils.css";
import "./themes/classic.css";

File diff suppressed because one or more lines are too long

View File

@@ -1,113 +0,0 @@
/* Bootstrap */
button,
a:focus {
outline: none;
-moz-outline-style: none;
}
.btn-default {
border-color: #ddd;
}
.btn-default:focus {
background-color: #fff;
border-color: #adadad;
}
.btn-default:hover,
.btn-default:active {
background-color: #ebebeb;
border-color: #adadad;
}
.btn,
.btn-lg,
.nav-tabs>li>a,
.form-control,
.popover,
.alert,
.modal-content,
.tooltip-inner,
.dropdown-menu {
border-radius: 0 !important;
}
input[type="search"] {
-webkit-appearance: searchfield;
box-shadow: none;
}
input[type="search"]::-webkit-search-cancel-button {
-webkit-appearance: searchfield-cancel-button;
}
.modal {
overflow-y: auto;
}
.form-control {
background-color: transparent;
}
code {
border: 0;
white-space: pre-wrap;
font-family: Consolas, monospace;
}
pre {
border-radius: 0 !important;
}
blockquote {
font-size: inherit;
}
blockquote a {
cursor: pointer;
}
optgroup {
font-weight: bold;
}
.panel-body:before,
.panel-body:after {
content: "";
}
.table-nonfluid {
width: auto !important;
}
/* Bootstrap-switch */
.bootstrap-switch,
.bootstrap-switch-container,
.bootstrap-switch-handle-on,
.bootstrap-switch-handle-off,
.bootstrap-switch-label {
border-radius: 0 !important;
}
/* Sortable */
.sortable-ghost {
opacity: 0.6;
}
/* Bootstrap Colorpicker */
.colorpicker-element {
float: left;
margin-right: 15px;
}
.colorpicker-color,
.colorpicker-color div {
height: 100px;
}

View File

@@ -1,37 +0,0 @@
.word-wrap {
white-space: pre !important;
word-wrap: normal !important;
overflow-x: scroll !important;
}
.clearfix {
clear: both;
height: 0;
}
.blur {
color: transparent !important;
text-shadow: rgba(0, 0, 0, 0.95) 0 0 10px !important;
}
.no-select {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
.konami {
-ms-transform: rotate(180deg);
-webkit-transform: rotate(180deg);
transform: rotate(180deg);
-moz-transform: rotate(180deg);
}
.hl1, .hlyellow { background-color: #fff000; }
.hl2, .hlblue { background-color: #95dfff; }
.hl3, .hlred { background-color: #ffb6b6; } /* Half-Life 3 confirmed :O */
.hl4, .hlorange { background-color: #fcf8e3; }
.hl5, .hlgreen { background-color: #8de768; }

View File

@@ -1,258 +0,0 @@
#banner {
border-bottom: 1px solid #ddd;
}
.title {
border-bottom: 1px solid #ddd;
font-weight: bold;
color: #424242;
background-color: #fafafa;
}
.gutter {
background-color: #eee;
background-repeat: no-repeat;
background-position: 50%;
}
.gutter.gutter-horizontal {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAAeCAYAAAAGos/EAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsQAAA7EAZUrDhsAAAAlSURBVChTYzxz5sx/BiBgAhEgwPju3TtUEZZ79+6BGcNcDQMDACWJMFs4hNOSAAAAAElFTkSuQmCC');
cursor: ew-resize;
}
.gutter.gutter-vertical {
background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAB4AAAACCAYAAABPJGxCAAAABGdBTUEAALGOfPtRkwAAACBjSFJNAACHDwAAjA8AAP1SAACBQAAAfXkAAOmLAAA85QAAGcxzPIV3AAAKL2lDQ1BJQ0MgUHJvZmlsZQAASMedlndUVNcWh8+9d3qhzTDSGXqTLjCA9C4gHQRRGGYGGMoAwwxNbIioQEQREQFFkKCAAaOhSKyIYiEoqGAPSBBQYjCKqKhkRtZKfHl57+Xl98e939pn73P32XuftS4AJE8fLi8FlgIgmSfgB3o401eFR9Cx/QAGeIABpgAwWempvkHuwUAkLzcXerrICfyL3gwBSPy+ZejpT6eD/0/SrFS+AADIX8TmbE46S8T5Ik7KFKSK7TMipsYkihlGiZkvSlDEcmKOW+Sln30W2VHM7GQeW8TinFPZyWwx94h4e4aQI2LER8QFGVxOpohvi1gzSZjMFfFbcWwyh5kOAIoktgs4rHgRm4iYxA8OdBHxcgBwpLgvOOYLFnCyBOJDuaSkZvO5cfECui5Lj25qbc2ge3IykzgCgaE/k5XI5LPpLinJqUxeNgCLZ/4sGXFt6aIiW5paW1oamhmZflGo/7r4NyXu7SK9CvjcM4jW94ftr/xS6gBgzIpqs+sPW8x+ADq2AiB3/w+b5iEAJEV9a7/xxXlo4nmJFwhSbYyNMzMzjbgclpG4oL/rfzr8DX3xPSPxdr+Xh+7KiWUKkwR0cd1YKUkpQj49PZXJ4tAN/zzE/zjwr/NYGsiJ5fA5PFFEqGjKuLw4Ubt5bK6Am8Kjc3n/qYn/MOxPWpxrkSj1nwA1yghI3aAC5Oc+gKIQARJ5UNz13/vmgw8F4psXpjqxOPefBf37rnCJ+JHOjfsc5xIYTGcJ+RmLa+JrCdCAACQBFcgDFaABdIEhMANWwBY4AjewAviBYBAO1gIWiAfJgA8yQS7YDApAEdgF9oJKUAPqQSNoASdABzgNLoDL4Dq4Ce6AB2AEjIPnYAa8AfMQBGEhMkSB5CFVSAsygMwgBmQPuUE+UCAUDkVDcRAPEkK50BaoCCqFKqFaqBH6FjoFXYCuQgPQPWgUmoJ+hd7DCEyCqbAyrA0bwwzYCfaGg+E1cBycBufA+fBOuAKug4/B7fAF+Dp8Bx6Bn8OzCECICA1RQwwRBuKC+CERSCzCRzYghUg5Uoe0IF1IL3ILGUGmkXcoDIqCoqMMUbYoT1QIioVKQ21AFaMqUUdR7age1C3UKGoG9QlNRiuhDdA2aC/0KnQcOhNdgC5HN6Db0JfQd9Dj6DcYDIaG0cFYYTwx4ZgEzDpMMeYAphVzHjOAGcPMYrFYeawB1g7rh2ViBdgC7H7sMew57CB2HPsWR8Sp4sxw7rgIHA+XhyvHNeHO4gZxE7h5vBReC2+D98Oz8dn4Enw9vgt/Az+OnydIE3QIdoRgQgJhM6GC0EK4RHhIeEUkEtWJ1sQAIpe4iVhBPE68QhwlviPJkPRJLqRIkpC0k3SEdJ50j/SKTCZrkx3JEWQBeSe5kXyR/Jj8VoIiYSThJcGW2ChRJdEuMSjxQhIvqSXpJLlWMkeyXPKk5A3JaSm8lLaUixRTaoNUldQpqWGpWWmKtKm0n3SydLF0k/RV6UkZrIy2jJsMWyZf5rDMRZkxCkLRoLhQWJQtlHrKJco4FUPVoXpRE6hF1G+o/dQZWRnZZbKhslmyVbJnZEdoCE2b5kVLopXQTtCGaO+XKC9xWsJZsmNJy5LBJXNyinKOchy5QrlWuTty7+Xp8m7yifK75TvkHymgFPQVAhQyFQ4qXFKYVqQq2iqyFAsVTyjeV4KV9JUCldYpHVbqU5pVVlH2UE5V3q98UXlahabiqJKgUqZyVmVKlaJqr8pVLVM9p/qMLkt3oifRK+g99Bk1JTVPNaFarVq/2ry6jnqIep56q/ojDYIGQyNWo0yjW2NGU1XTVzNXs1nzvhZei6EVr7VPq1drTltHO0x7m3aH9qSOnI6XTo5Os85DXbKug26abp3ubT2MHkMvUe+A3k19WN9CP16/Sv+GAWxgacA1OGAwsBS91Hopb2nd0mFDkqGTYYZhs+GoEc3IxyjPqMPohbGmcYTxbuNe408mFiZJJvUmD0xlTFeY5pl2mf5qpm/GMqsyu21ONnc332jeaf5ymcEyzrKDy+5aUCx8LbZZdFt8tLSy5Fu2WE5ZaVpFW1VbDTOoDH9GMeOKNdra2Xqj9WnrdzaWNgKbEza/2BraJto22U4u11nOWV6/fMxO3Y5pV2s3Yk+3j7Y/ZD/ioObAdKhzeOKo4ch2bHCccNJzSnA65vTC2cSZ79zmPOdi47Le5bwr4urhWuja7ybjFuJW6fbYXd09zr3ZfcbDwmOdx3lPtKe3527PYS9lL5ZXo9fMCqsV61f0eJO8g7wrvZ/46Pvwfbp8Yd8Vvnt8H67UWslb2eEH/Lz89vg98tfxT/P/PgAT4B9QFfA00DQwN7A3iBIUFdQU9CbYObgk+EGIbogwpDtUMjQytDF0Lsw1rDRsZJXxqvWrrocrhHPDOyOwEaERDRGzq91W7109HmkRWRA5tEZnTdaaq2sV1iatPRMlGcWMOhmNjg6Lbor+wPRj1jFnY7xiqmNmWC6sfaznbEd2GXuKY8cp5UzE2sWWxk7G2cXtiZuKd4gvj5/munAruS8TPBNqEuYS/RKPJC4khSW1JuOSo5NP8WR4ibyeFJWUrJSBVIPUgtSRNJu0vWkzfG9+QzqUvia9U0AV/Uz1CXWFW4WjGfYZVRlvM0MzT2ZJZ/Gy+rL1s3dkT+S453y9DrWOta47Vy13c+7oeqf1tRugDTEbujdqbMzfOL7JY9PRzYTNiZt/yDPJK817vSVsS1e+cv6m/LGtHlubCyQK+AXD22y31WxHbedu799hvmP/jk+F7MJrRSZF5UUfilnF174y/ariq4WdsTv7SyxLDu7C7OLtGtrtsPtoqXRpTunYHt897WX0ssKy13uj9l4tX1Zes4+wT7hvpMKnonO/5v5d+z9UxlfeqXKuaq1Wqt5RPXeAfWDwoOPBlhrlmqKa94e4h+7WetS212nXlR/GHM44/LQ+tL73a8bXjQ0KDUUNH4/wjowcDTza02jV2Nik1FTSDDcLm6eORR67+Y3rN50thi21rbTWouPguPD4s2+jvx064X2i+yTjZMt3Wt9Vt1HaCtuh9uz2mY74jpHO8M6BUytOdXfZdrV9b/T9kdNqp6vOyJ4pOUs4m3924VzOudnzqeenL8RdGOuO6n5wcdXF2z0BPf2XvC9duex++WKvU++5K3ZXTl+1uXrqGuNax3XL6+19Fn1tP1j80NZv2d9+w+pG503rm10DywfODjoMXrjleuvyba/b1++svDMwFDJ0dzhyeOQu++7kvaR7L+9n3J9/sOkh+mHhI6lH5Y+VHtf9qPdj64jlyJlR19G+J0FPHoyxxp7/lP7Th/H8p+Sn5ROqE42TZpOnp9ynbj5b/Wz8eerz+emCn6V/rn6h++K7Xxx/6ZtZNTP+kv9y4dfiV/Kvjrxe9rp71n/28ZvkN/NzhW/l3x59x3jX+z7s/cR85gfsh4qPeh+7Pnl/eriQvLDwG/eE8/s3BCkeAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAI0lEQVQYV2M8c+bMfwYgUFJSAlEM9+7dA9O05jOBSboDBgYAtPcYZ1oUA30AAAAASUVORK5CYII=');
cursor: ns-resize;
}
.operation {
border: 1px solid #999;
border-top-width: 0;
}
.op-list .operation { /*blue*/
color: #3a87ad;
background-color: #d9edf7;
border-color: #bce8f1;
}
#rec-list .operation { /*green*/
color: #468847;
background-color: #dff0d8;
border-color: #d6e9c6;
}
#controls {
border-top: 1px solid #ddd;
background-color: #fafafa;
}
.textarea-wrapper textarea,
.textarea-wrapper div {
font-family: Consolas, monospace;
font-size: inherit;
}
.io-info {
font-family: Consolas, monospace;
font-weight: normal;
font-size: 8pt;
}
.arg-title {
font-weight: bold;
}
.arg-input {
height: 34px;
font-size: 15px;
line-height: 1.428571429;
color: #424242;
background-color: #fff;
border: 1px solid #ddd;
font-family: Consolas, monospace;
}
select {
padding: 6px 8px;
height: 34px;
border: 1px solid #ddd;
background-color: #fff;
color: #424242;
}
.arg[disabled] {
background-color: #eee;
}
textarea.arg {
color: #424242;
font-family: Consolas, monospace;
}
.break {
color: #b94a48 !important;
background-color: #f2dede !important;
border-color: #eed3d7 !important;
}
.category-title {
background-color: #fafafa;
border-bottom: 1px solid #eee;
font-weight: bold;
}
.category-title[href='#catFavourites'] {
border-bottom-color: #ddd;
}
.category-title[aria-expanded=true] {
border-bottom-color: #ddd;
}
.category-title.collapsed {
border-bottom-color: #eee;
}
.category-title:hover {
color: #3a87ad;
}
#search {
border-bottom: 1px solid #e3e3e3;
}
.dropping-file {
border: 5px dashed #3a87ad !important;
}
.selected-op {
color: #c09853 !important;
background-color: #fcf8e3 !important;
border-color: #fbeed5 !important;
}
.option-item input[type=number] {
font-size: 14px;
line-height: 1.428571429;
color: #555;
background-color: #fff;
border: 1px solid #ccc;
}
.favourites-hover {
color: #468847;
background-color: #dff0d8;
border: 2px dashed #468847 !important;
padding: 8px 8px 9px 8px;
}
#edit-favourites-list {
border: 1px solid #bce8f1;
}
#edit-favourites-list .operation {
border-left: none;
border-right: none;
}
#edit-favourites-list .operation:last-child {
border-bottom: none;
}
.subtext {
font-style: italic;
font-size: 13px;
color: #999;
}
#save-footer {
border-bottom: 1px solid #e5e5e5;
}
.flow-control-op {
color: #396f3a !important;
background-color: #c7e4ba !important;
border-color: #b3dba2 !important;
}
.flow-control-op.break {
color: #94312f !important;
background-color: #eabfbf !important;
border-color: #e2aeb5 !important;
}
#support-modal textarea {
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
}
#save-text,
#load-text {
font-family: Consolas, monospace;
}
button.dropdown-toggle {
background-color: #f4f4f4;
}
::-webkit-scrollbar {
width: 10px;
height: 10px;
}
::-webkit-scrollbar-track {
background-color: #fafafa;
}
::-webkit-scrollbar-thumb {
background-color: #ccc;
}
::-webkit-scrollbar-thumb:hover {
background-color: #bbb;
}
::-webkit-scrollbar-corner {
background-color: #fafafa;
}
.disabled {
color: #999 !important;
background-color: #dfdfdf !important;
border-color: #cdcdcd !important;
}
.grey {
color: #333;
background-color: #f5f5f5;
border-color: #ddd;
}
.dark-blue {
color: #fff;
background-color: #428bca;
border-color: #428bca;
}
.red {
color: #b94a48;
background-color: #f2dede;
border-color: #eed3d7;
}
.amber {
color: #c09853;
background-color: #fcf8e3;
border-color: #fbeed5;
}
.green {
color: #468847;
background-color: #dff0d8;
border-color: #d6e9c6;
}
.blue {
color: #3a87ad;
background-color: #d9edf7;
border-color: #bce8f1;
}

View File

@@ -20,78 +20,146 @@
-->
<!-- htmlmin:ignore -->
<!DOCTYPE html>
<html>
<html lang="en" class="classic">
<head>
<meta charset="UTF-8">
<title>CyberChef</title>
<meta name="copyright" content="Crown Copyright 2016" />
<meta name="description" content="The Cyber Swiss Army Knife" />
<meta name="description" content="The Cyber Swiss Army Knife - a web app for encryption, encoding, compression and data analysis" />
<meta name="keywords" content="base64, hex, decode, encode, encrypt, decrypt, compress, decompress, regex, regular expressions, hash, crypt, hexadecimal, user agent, url, certificate, x.509, parser, JSON, gzip, md5, sha1, aes, des, blowfish, xor" />
<link rel="icon" type="image/ico" href="<%- require('../static/images/favicon.ico') %>" />
<script type="application/javascript">
"use strict";
// Load theme before the preloader is shown
try {
document.querySelector(":root").className = JSON.parse(localStorage.getItem("options")).theme;
} catch (e) {}
// Define loading messages
const loadingMsgs = [
"Proving P = NP...",
"Computing 6 x 9...",
"Mining bitcoin...",
"Dividing by 0...",
"Initialising Skynet...",
"[REDACTED]",
"Downloading more RAM...",
"Ordering 1s and 0s...",
"Navigating neural network...",
"Importing machine learning...",
"Issuing Alice and Bob one-time pads...",
"Mining bitcoin cash...",
"Generating key material by trying to escape vim...",
"for i in range(additional): Pylon()",
"(creating unresolved tension...",
"Symlinking emacs and vim to ed...",
];
// Shuffle array using Durstenfeld algorithm
for (let i = loadingMsgs.length - 1; i > 0; --i) {
const j = Math.floor(Math.random() * (i + 1));
const temp = loadingMsgs[i];
loadingMsgs[i] = loadingMsgs[j];
loadingMsgs[j] = temp;
}
// Show next loading message and move it to the end of the array
function changeLoadingMsg() {
const msg = loadingMsgs.shift();
loadingMsgs.push(msg);
try {
const el = document.getElementById("preloader-msg");
el.className = "loading"; // Causes CSS transition on first message
el.innerHTML = msg;
} catch (err) {} // Ignore errors if DOM not yet ready
}
changeLoadingMsg();
window.loadingMsgsInt = setInterval(changeLoadingMsg, (Math.random() * 2000) + 1500);
</script>
<% if (!htmlWebpackPlugin.options.inline) { %>
<script type="application/ld+json">
<% print(JSON.stringify(require("../static/structuredData.json"))); %>
</script>
<% } %>
</head>
<body>
<span id="edit-favourites" class="btn btn-default btn-sm"><img src="<%- require('../static/images/favourite-16x16.png') %>" /> Edit</span>
<!-- Preloader overlay -->
<div id="loader-wrapper">
<div id="preloader"></div>
<div id="preloader-msg"></div>
</div>
<!-- End preloader overlay -->
<span id="edit-favourites" class="btn btn-default btn-sm"><img aria-hidden="true" src="<%- require('../static/images/favourite-16x16.png') %>" alt="Star Icon"/> Edit</span>
<div id="alert" class="alert alert-danger">
<button type="button" class="close" id="alert-close">&times;</button>
<span id="alert-content"></span>
</div>
<div id="content-wrapper">
<div id="banner" class="green">
<% if (htmlWebpackPlugin.options.inline) { %>
<span style="float: left; margin-left: 10px;">Compile time: <%= htmlWebpackPlugin.options.compileTime %></span>
<% } else { %>
<a href="cyberchef.htm" style="float: left; margin-left: 10px; margin-right: 80px;" download>Download CyberChef<img src="<%- require('../static/images/download-24x24.png') %>" /></a>
<% } %>
<span id="notice">
<script type="text/javascript">
// Must be text/javascript rather than application/javascript otherwise IE won't recognise it...
if (navigator.userAgent && navigator.userAgent.match(/MSIE \d\d?\./)) {
document.write("Internet Explorer is not supported, please use Firefox or Chrome instead");
alert("Internet Explorer is not supported, please use Firefox or Chrome instead");
}
</script>
<noscript>JavaScript is not enabled. Good luck.</noscript>
</span>
<a href="#" id="support" class="banner-right" data-toggle="modal" data-target="#support-modal">About / Support<img src="<%- require('../static/images/help-22x22.png') %>" /></a>
<a href="#" id="options" class="banner-right">Options<img src="<%- require('../static/images/settings-22x22.png') %>" /></a>
<div id="banner">
<div class="col-md-4" style="text-align: left; padding-left: 10px;">
<% if (htmlWebpackPlugin.options.inline) { %>
<span>Version <%= htmlWebpackPlugin.options.version %></span>
<% } else { %>
<a href="cyberchef.htm" download>Download CyberChef<img aria-hidden="true" src="<%- require('../static/images/download-24x24.png') %>" alt="Download Icon"/></a>
<% } %>
</div>
<div class="col-md-4" style="text-align: center;">
<span id="notice">
<script type="text/javascript">
// Must be text/javascript rather than application/javascript otherwise IE won't recognise it...
if (navigator.userAgent && navigator.userAgent.match(/MSIE \d\d?\./)) {
document.write("Internet Explorer is not supported, please use Firefox or Chrome instead");
alert("Internet Explorer is not supported, please use Firefox or Chrome instead");
}
</script>
<noscript>JavaScript is not enabled. Good luck.</noscript>
</span>
</div>
<div class="col-md-4" style="text-align: right; padding-right: 0;">
<a href="#" id="options">Options<img aria-hidden="true" src="<%- require('../static/images/settings-22x22.png') %>" alt="Settings Icon"/></a>
<a href="#" id="support" data-toggle="modal" data-target="#support-modal">About / Support<img aria-hidden="true" src="<%- require('../static/images/help-22x22.png') %>" alt="Question Mark Icon"/></a>
</div>
</div>
<div id="wrapper">
<div id="workspace-wrapper">
<div id="operations" class="split split-horizontal no-select">
<div class="title no-select">Operations</div>
<input type="search" class="form-control" id="search" placeholder="Search..." autocomplete="off">
<ul class="op-list" id="search-results"></ul>
<div class="panel-group no-select" id="categories"></div>
<input id="search" type="search" class="form-control" placeholder="Search..." autocomplete="off">
<ul id="search-results" class="op-list"></ul>
<div id="categories" class="panel-group no-select"></div>
</div>
<div id="recipe" class="split split-horizontal no-select">
<div class="title no-select">Recipe</div>
<ul id="rec-list" class="no-select"></ul>
<ul id="rec-list" class="list-area no-select"></ul>
<div id="controls" class="no-select">
<div id="operational-controls">
<div id="bake-group">
<button type="button" class="btn btn-success btn-lg" id="bake">
<img src="<%- require('../static/images/cook_male-32x32.png') %>" />
<img aria-hidden="true" src="<%- require('../static/images/cook_male-32x32.png') %>" alt="Chef Icon"/>
Bake!
</button>
<label class="btn btn-success btn-lg" id="auto-bake-label">
<label class="btn btn-success btn-lg" id="auto-bake-label" for="auto-bake">
<input type="checkbox" checked="checked" id="auto-bake">
<div>Auto Bake</div>
</label>
</div>
<div class="btn-group" style="padding-top: 10px;">
<button type="button" class="btn btn-default" id="step"><img src="<%- require('../static/images/step-16x16.png') %>" /> Step through</button>
<button type="button" class="btn btn-default" id="clr-breaks"><img src="<%- require('../static/images/erase-16x16.png') %>" /> Clear breakpoints</button>
<button type="button" class="btn btn-default" id="step"><img aria-hidden="true" src="<%- require('../static/images/step-16x16.png') %>" alt="Footstep Icon"/> Step through</button>
<button type="button" class="btn btn-default" id="clr-breaks"><img aria-hidden="true" src="<%- require('../static/images/erase-16x16.png') %>" alt="Eraser Icon"/> Clear breakpoints</button>
</div>
</div>
<div class="btn-group-vertical" id="extra-controls">
<button type="button" class="btn btn-default" id="save"><img src="<%- require('../static/images/save-16x16.png') %>" /> Save recipe</button>
<button type="button" class="btn btn-default" id="load"><img src="<%- require('../static/images/open_yellow-16x16.png') %>" /> Load recipe</button>
<button type="button" class="btn btn-default" id="clr-recipe"><img src="<%- require('../static/images/clean-16x16.png') %>" /> Clear recipe</button>
<button type="button" class="btn btn-default" id="save"><img aria-hidden="true" src="<%- require('../static/images/save-16x16.png') %>" alt="Save Icon"/> Save recipe</button>
<button type="button" class="btn btn-default" id="load"><img aria-hidden="true" src="<%- require('../static/images/open_yellow-16x16.png') %>" alt="Open Icon"/> Load recipe</button>
<button type="button" class="btn btn-default" id="clr-recipe"><img aria-hidden="true" src="<%- require('../static/images/clean-16x16.png') %>" alt="Broom Icon"/> Clear recipe</button>
</div>
</div>
</div>
@@ -99,10 +167,11 @@
<div class="split split-horizontal" id="IO">
<div id="input" class="split no-select">
<div class="title no-select">
Input
<label for="input-text">Input</label>
<div class="loading-icon" style="display: none"></div>
<div class="btn-group io-btn-group">
<button type="button" class="btn btn-default btn-sm" id="clr-io"><img src="<%- require('../static/images/recycle-16x16.png') %>" /> Clear I/O</button>
<button type="button" class="btn btn-default btn-sm" id="reset-layout"><img src="<%- require('../static/images/layout-16x16.png') %>" /> Reset layout</button>
<button type="button" class="btn btn-default btn-sm" id="clr-io"><img aria-hidden="true" src="<%- require('../static/images/recycle-16x16.png') %>" alt="Recycle Icon"/> Clear I/O</button>
<button type="button" class="btn btn-default btn-sm" id="reset-layout"><img aria-hidden="true" src="<%- require('../static/images/layout-16x16.png') %>" alt="Grid Icon"/> Reset layout</button>
</div>
<div class="io-info" id="input-info"></div>
<div class="io-info" id="input-selection-info"></div>
@@ -115,12 +184,13 @@
<div id="output" class="split">
<div class="title no-select">
Output
<label for="output-text">Output</label>
<div class="loading-icon" style="display: none"></div>
<div class="btn-group io-btn-group">
<button type="button" class="btn btn-default btn-sm" id="save-to-file" title="Save to file"><img src="<%- require('../static/images/save_as-16x16.png') %>" /> Save to file</button>
<button type="button" class="btn btn-default btn-sm" id="switch" title="Move output to input"><img src="<%- require('../static/images/switch-16x16.png') %>" /> Move output to input</button>
<button type="button" class="btn btn-default btn-sm" id="undo-switch" title="Undo move" disabled="disabled"><img src="<%- require('../static/images/undo-16x16.png') %>" /> Undo</button>
<button type="button" class="btn btn-default btn-sm" id="maximise-output" title="Maximise"><img src="<%- require('../static/images/maximise-16x16.png') %>" /> Max</button>
<button type="button" class="btn btn-default btn-sm" id="save-to-file" title="Save to file"><img aria-hidden="true" src="<%- require('../static/images/save_as-16x16.png') %>" alt="Save Icon"/> Save to file</button>
<button type="button" class="btn btn-default btn-sm" id="switch" title="Move output to input"><img aria-hidden="true" src="<%- require('../static/images/switch-16x16.png') %>" alt="Switch Icon"/> Move output to input</button>
<button type="button" class="btn btn-default btn-sm" id="undo-switch" title="Undo move" disabled="disabled"><img aria-hidden="true" src="<%- require('../static/images/undo-16x16.png') %>" alt="Undo Icon"/> Undo</button>
<button type="button" class="btn btn-default btn-sm" id="maximise-output" title="Maximise"><img aria-hidden="true" src="<%- require('../static/images/maximise-16x16.png') %>" alt="Maximise Icon"/> Max</button>
</div>
<div class="io-info" id="output-info"></div>
<div class="io-info" id="output-selection-info"></div>
@@ -139,13 +209,28 @@
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<img class="pull-right" src="<%- require('../static/images/save-22x22.png') %>" />
<img aria-hidden="true" class="pull-right" src="<%- require('../static/images/save-22x22.png') %>" alt="Save Icon"/>
<h4 class="modal-title">Save recipe</h4>
</div>
<div class="modal-body">
<div class="form-group">
<label for="save-text">Save your recipe to local storage or copy the following string to load later</label>
<textarea class="form-control" id="save-text" rows="5"></textarea>
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="active"><a href="#chef-format" role="tab" data-toggle="tab">Chef format</a></li>
<li role="presentation"><a href="#clean-json" role="tab" data-toggle="tab">Clean JSON</a></li>
<li role="presentation"><a href="#compact-json" role="tab" data-toggle="tab">Compact JSON</a></li>
</ul>
<div class="tab-content" id="save-texts">
<div role="tabpanel" class="tab-pane active" id="chef-format">
<textarea class="form-control" id="save-text-chef" rows="5"></textarea>
</div>
<div role="tabpanel" class="tab-pane" id="clean-json">
<textarea class="form-control" id="save-text-clean" rows="5"></textarea>
</div>
<div role="tabpanel" class="tab-pane" id="compact-json">
<textarea class="form-control" id="save-text-compact" rows="5"></textarea>
</div>
</div>
</div>
<div class="form-group">
<label for="save-name">Recipe name</label>
@@ -160,9 +245,10 @@
<div class="form-group" id="save-link-group">
<label>Data link</label>
<div class="save-link-options">
<input type="checkbox" id="save-link-recipe-checkbox" checked> Include recipe
<input type="checkbox" id="save-link-input-checkbox" checked> Include input
<input type="checkbox" id="save-link-recipe-checkbox" checked> <label for="save-link-recipe-checkbox"> Include recipe </label>
<input type="checkbox" id="save-link-input-checkbox" checked> <label for="save-link-input-checkbox"> Include input </label>
</div>
<br>
<a id="save-link" style="word-wrap: break-word;"></a>
</div>
</div>
@@ -174,15 +260,16 @@
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<img class="pull-right" src="<%- require('../static/images/open_yellow-24x24.png') %>" />
<img aria-hidden="true" class="pull-right" src="<%- require('../static/images/open_yellow-24x24.png') %>" alt="Open Icon"/>
<h4 class="modal-title">Load recipe</h4>
</div>
<div class="modal-body">
<div class="form-group">
<label for="load-name">Load your recipe from local storage or paste it into the box below</label>
<label for="load-name">Load your recipe from local storage by selecting its name from the drop-down</label>
<select class="form-control" id="load-name"></select>
</div>
<div class="form-group">
<label for="load-text">Load your recipe by pasting it in the box below</label>
<textarea class="form-control" id="load-text" rows="5"></textarea>
</div>
</div>
@@ -199,38 +286,46 @@
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<img class="pull-right" src="<%- require('../static/images/settings-22x22.png') %>" />
<img aria-hidden="true" class="pull-right" src="<%- require('../static/images/settings-22x22.png') %>" alt="Settings Icon"/>
<h4 class="modal-title">Options</h4>
</div>
<div class="modal-body" id="options-body">
<p style="font-weight: bold">Please note that these options will persist between sessions.</p>
<div class="option-item">
<input type="checkbox" option="update_url" checked />
Update the URL when the input or recipe changes
<select option="theme" id="theme">
<option value="classic">Classic</option>
<option value="dark">Dark</option>
<option value="geocities">GeoCities</option>
</select>
<label for="theme"> Theme (only supported in modern browsers)</label>
</div>
<div class="option-item">
<input type="checkbox" option="show_highlighter" checked />
Highlight selected bytes in output and input (when possible)
<input type="checkbox" option="updateUrl" id="updateUrl" checked />
<label for="updateUrl"> Update the URL when the input or recipe changes </label>
</div>
<div class="option-item">
<input type="checkbox" option="treat_as_utf8" checked />
Treat output as UTF-8 if possible
<input type="checkbox" option="showHighlighter" id="showHighlighter" checked />
<label for="showHighlighter"> Highlight selected bytes in output and input (when possible) </label>
</div>
<div class="option-item">
<input type="checkbox" option="word_wrap" checked />
Word wrap the input and output
<input type="checkbox" option="treatAsUtf8" id="treatAsUtf8" checked />
<label for="treatAsUtf8"> Treat output as UTF-8 if possible </label>
</div>
<div class="option-item">
<input type="checkbox" option="show_errors" checked />
Operation error reporting (recommended)
<input type="checkbox" option="wordWrap" id="wordWrap" checked />
<label for="wordWrap"> Word wrap the input and output </label>
</div>
<div class="option-item">
<input type="number" option="error_timeout" />
Operation error timeout in ms (0 for never)
<input type="checkbox" option="showErrors" id="showErrors" checked />
<label for="showErrors"> Operation error reporting (recommended) </label>
</div>
<div class="option-item">
<input type="number" option="auto_bake_threshold" />
Auto Bake threshold in ms
<input type="number" option="errorTimeout" id="errorTimeout" />
<label for="errorTimeout"> Operation error timeout in ms (0 for never) </label>
</div>
<div class="option-item">
<input type="number" option="autoBakeThreshold" id="autoBakeThreshold"/>
<label for="autoBakeThreshold"> Auto Bake threshold in ms </label>
</div>
</div>
<div class="modal-footer">
@@ -245,10 +340,10 @@
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<img class="pull-right" src="<%- require('../static/images/favourite-24x24.png') %>" />
<img aria-hidden="true" class="pull-right" src="<%- require('../static/images/favourite-24x24.png') %>" alt="Star Icon"/>
<h4 class="modal-title">Edit Favourites</h4>
</div>
<div class="modal-body" id="options-body">
<div class="modal-body" id="favourites-body">
<ul>
<li><span style="font-weight: bold">To add:</span> drag the operation over the favourites category</li>
<li><span style="font-weight: bold">To reorder:</span> drag up and down in the list below</li>
@@ -272,28 +367,31 @@
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<img class="pull-right" src="<%- require('../static/images/help-22x22.png') %>" />
<img aria-hidden="true" class="pull-right" src="<%- require('../static/images/help-22x22.png') %>" alt="Question Mark Icon"/>
<h4 class="modal-title">CyberChef - The Cyber Swiss Army Knife</h4>
</div>
<div class="modal-body">
<img class="about-img-left" src="<%- require('../static/images/cyberchef-128x128.png') %>" />
<p class="subtext">Compile time: <%= htmlWebpackPlugin.options.compileTime %></p>
<p>&copy Crown Copyright 2016.</p>
<p>Licenced under the Apache Licence, Version 2.0.</p>
<img aria-hidden="true" class="about-img-left" src="<%- require('../static/images/cyberchef-128x128.png') %>" alt="CyberChef Logo"/>
<p class="subtext">
Version <%= htmlWebpackPlugin.options.version %><br>
Compile time: <%= htmlWebpackPlugin.options.compileTime %>
</p>
<p>&copy; Crown Copyright 2016.</p>
<p>Released under the Apache Licence, Version 2.0.</p>
<br>
<br>
<div>
<ul class="nav nav-tabs" role="tablist">
<li role="presentation" class="active"><a href="#faqs" aria-controls="profile" role="tab" data-toggle="tab">
<img src="<%- require('../static/images/help-16x16.png') %>" />
<img aria-hidden="true" src="<%- require('../static/images/help-16x16.png') %>" alt="Question Mark Icon"/>
FAQs
</a></li>
<li role="presentation"><a href="#report-bug" aria-controls="messages" role="tab" data-toggle="tab">
<img src="<%- require('../static/images/bug-16x16.png') %>" />
<img aria-hidden="true" src="<%- require('../static/images/bug-16x16.png') %>" alt="Bug Icon"/>
Report a bug
</a></li>
<li role="presentation"><a href="#about" aria-controls="messages" role="tab" data-toggle="tab">
<img src="<%- require('../static/images/speech-16x16.png') %>" />
<img aria-hidden="true" src="<%- require('../static/images/speech-16x16.png') %>" alt="Speech Balloon Icon"/>
About
</a></li>
</ul>
@@ -306,14 +404,14 @@
</a>
</blockquote>
<div class="collapse" id="faq-examples">
<p>There are well over 100 operations in CyberChef allowing you to carry simple and complex tasks easily. Here are some examples:</p>
<p>There are around 200 operations in CyberChef allowing you to carry out simple and complex tasks easily. Here are some examples:</p>
<ul>
<li><a href="?recipe=%5B%7B%22op%22%3A%22From%20Base64%22%2C%22args%22%3A%5B%22A-Za-z0-9%2B%2F%3D%22%2Ctrue%5D%7D%5D&input=VTI4Z2JHOXVaeUJoYm1RZ2RHaGhibXR6SUdadmNpQmhiR3dnZEdobElHWnBjMmd1">Decode a Base64-encoded string</a></li>
<li><a href="?recipe=%5B%7B%22op%22%3A%22Translate%20DateTime%20Format%22%2C%22args%22%3A%5B%22Standard%20date%20and%20time%22%2C%22DD%2FMM%2FYYYY%20HH%3Amm%3Ass%22%2C%22UTC%22%2C%22dddd%20Do%20MMMM%20YYYY%20HH%3Amm%3Ass%20Z%20z%22%2C%22Australia%2FQueensland%22%5D%7D%5D&input=MTUvMDYvMjAxNSAyMDo0NTowMA">Convert a date and time to a different time zone</a></li>
<li><a href="?recipe=%5B%7B%22op%22%3A%22Parse%20IPv6%20address%22%2C%22args%22%3A%5B%5D%7D%5D&input=MjAwMTowMDAwOjQxMzY6ZTM3ODo4MDAwOjYzYmY6M2ZmZjpmZGQy">Parse a Teredo IPv6 address</a></li>
<li><a href="?recipe=%5B%7B%22op%22%3A%22From%20Hexdump%22%2C%22args%22%3A%5B%5D%7D%2C%7B%22op%22%3A%22Gunzip%22%2C%22args%22%3A%5B%5D%7D%5D&input=MDAwMDAwMDAgIDFmIDhiIDA4IDAwIDEyIGJjIGYzIDU3IDAwIGZmIDBkIGM3IGMxIDA5IDAwIDIwICB8Li4uLi6881cu%2Fy7HwS4uIHwKMDAwMDAwMTAgIDA4IDA1IGQwIDU1IGZlIDA0IDJkIGQzIDA0IDFmIGNhIDhjIDQ0IDIxIDViIGZmICB8Li7QVf4uLdMuLsouRCFb%2F3wKMDAwMDAwMjAgIDYwIGM3IGQ3IDAzIDE2IGJlIDQwIDFmIDc4IDRhIDNmIDA5IDg5IDBiIDlhIDdkICB8YMfXLi6%2BQC54Sj8uLi4ufXwKMDAwMDAwMzAgIDRlIGM4IDRlIDZkIDA1IDFlIDAxIDhiIDRjIDI0IDAwIDAwIDAwICAgICAgICAgICB8TshObS4uLi5MJC4uLnw">Convert data from a hexdump, then decompress</a></li>
<li><a href="?recipe=%5B%7B%22op%22%3A%22Fork%22%2C%22args%22%3A%5B%22%5C%5Cn%22%2C%22%5C%5Cn%22%5D%7D%2C%7B%22op%22%3A%22From%20UNIX%20Timestamp%22%2C%22args%22%3A%5B%22Seconds%20(s)%22%5D%7D%5D&input=OTc4MzQ2ODAwCjEwMTI2NTEyMDAKMTA0NjY5NjQwMAoxMDgxMDg3MjAwCjExMTUzMDUyMDAKMTE0OTYwOTYwMA">Display multiple timestamps as full dates</a></li>
<li><a href="?recipe=%5B%7B%22op%22%3A%22Fork%22%2C%22args%22%3A%5B%22%5C%5Cn%22%2C%22%5C%5Cn%22%5D%7D%2C%7B%22op%22%3A%22Conditional%20Jump%22%2C%22args%22%3A%5B%221%22%2C%222%22%2C%2210%22%5D%7D%2C%7B%22op%22%3A%22To%20Hex%22%2C%22args%22%3A%5B%22Space%22%5D%7D%2C%7B%22op%22%3A%22Return%22%2C%22args%22%3A%5B%5D%7D%2C%7B%22op%22%3A%22To%20Base64%22%2C%22args%22%3A%5B%22A-Za-z0-9%2B%2F%3D%22%5D%7D%5D&input=U29tZSBkYXRhIHdpdGggYSAxIGluIGl0ClNvbWUgZGF0YSB3aXRoIGEgMiBpbiBpdA">Carry out different operations on data of different types</a></li>
<li><a href="#recipe=From_Base64('A-Za-z0-9%2B/%3D',true)&input=VTI4Z2JHOXVaeUJoYm1RZ2RHaGhibXR6SUdadmNpQmhiR3dnZEdobElHWnBjMmd1">Decode a Base64-encoded string</a></li>
<li><a href="#recipe=Translate_DateTime_Format('Standard%20date%20and%20time','DD/MM/YYYY%20HH:mm:ss','UTC','dddd%20Do%20MMMM%20YYYY%20HH:mm:ss%20Z%20z','Australia/Queensland')&input=MTUvMDYvMjAxNSAyMDo0NTowMA">Convert a date and time to a different time zone</a></li>
<li><a href="#recipe=Parse_IPv6_address()&input=MjAwMTowMDAwOjQxMzY6ZTM3ODo4MDAwOjYzYmY6M2ZmZjpmZGQy">Parse a Teredo IPv6 address</a></li>
<li><a href="#recipe=From_Hexdump()Gunzip()&input=MDAwMDAwMDAgIDFmIDhiIDA4IDAwIDEyIGJjIGYzIDU3IDAwIGZmIDBkIGM3IGMxIDA5IDAwIDIwICB8Li4uLi6881cu/y7HwS4uIHwKMDAwMDAwMTAgIDA4IDA1IGQwIDU1IGZlIDA0IDJkIGQzIDA0IDFmIGNhIDhjIDQ0IDIxIDViIGZmICB8Li7QVf4uLdMuLsouRCFb/3wKMDAwMDAwMjAgIDYwIGM3IGQ3IDAzIDE2IGJlIDQwIDFmIDc4IDRhIDNmIDA5IDg5IDBiIDlhIDdkICB8YMfXLi6%2BQC54Sj8uLi4ufXwKMDAwMDAwMzAgIDRlIGM4IDRlIDZkIDA1IDFlIDAxIDhiIDRjIDI0IDAwIDAwIDAwICAgICAgICAgICB8TshObS4uLi5MJC4uLnw">Convert data from a hexdump, then decompress</a></li>
<li><a href="#recipe=Fork('%5C%5Cn','%5C%5Cn',false)From_UNIX_Timestamp('Seconds%20(s)')&input=OTc4MzQ2ODAwCjEwMTI2NTEyMDAKMTA0NjY5NjQwMAoxMDgxMDg3MjAwCjExMTUzMDUyMDAKMTE0OTYwOTYwMA">Display multiple timestamps as full dates</a></li>
<li><a href="#recipe=Fork('%5C%5Cn','%5C%5Cn',false)Conditional_Jump('1',2,10)To_Hex('Space')Return()To_Base64('A-Za-z0-9%2B/%3D')&input=U29tZSBkYXRhIHdpdGggYSAxIGluIGl0ClNvbWUgZGF0YSB3aXRoIGEgMiBpbiBpdA">Carry out different operations on data of different types</a></li>
</ul>
</div>
<blockquote>
@@ -333,7 +431,7 @@
<div class="collapse" id="faq-fork">
<p>Maybe you have 10 timestamps that you want to parse or 16 encoded strings that all have the same key.</p>
<p>The 'Fork' operation (found in the 'Flow control' category) splits up the input line by line and runs all subsequent operations on each line separately. Each output is then displayed on a separate line. These delimiters can be changed, so if your inputs are separated by commas, you can change the split delimiter to a comma instead.</p>
<p><a href='?recipe=%5B%7B"op"%3A"Fork"%2C"args"%3A%5B"%5C%5Cn"%2C"%5C%5Cn"%5D%7D%2C%7B"op"%3A"From%20UNIX%20Timestamp"%2C"args"%3A%5B"Seconds%20(s)"%5D%7D%5D&input=OTc4MzQ2ODAwCjEwMTI2NTEyMDAKMTA0NjY5NjQwMAoxMDgxMDg3MjAwCjExMTUzMDUyMDAKMTE0OTYwOTYwMA%3D%3D'>Click here</a> for an example.</p>
<p><a href="#recipe=Fork('%5C%5Cn','%5C%5Cn',false)From_UNIX_Timestamp('Seconds%20(s)')&input=OTc4MzQ2ODAwCjEwMTI2NTEyMDAKMTA0NjY5NjQwMAoxMDgxMDg3MjAwCjExMTUzMDUyMDAKMTE0OTYwOTYwMA">Click here</a> for an example.</p>
</div>
</div>
<div role="tabpanel" class="tab-pane" id="report-bug">
@@ -345,21 +443,25 @@
<a class="btn btn-primary" href="https://github.com/gchq/CyberChef/issues/new" role="button">Raise issue on GitHub</a>
</div>
<div role="tabpanel" class="tab-pane" id="about" style="padding: 20px;">
<h4>What</h4>
<p>A simple, intuitive web app for analysing and decoding data without having to deal with complex tools or programming languages. CyberChef encourages both technical and non-technical people to explore data formats, encryption and compression.</p>
<h5><strong>What</strong></h5>
<p>A simple, intuitive web app for analysing and decoding data without having to deal with complex tools or programming languages. CyberChef encourages both technical and non-technical people to explore data formats, encryption and compression.</p><br>
<h4>Why</h4>
<p>Digital data comes in all shapes, sizes and formats in the modern world CyberChef helps to make sense of this data all on one easy-to-use platform.</p>
<h5><strong>Why</strong></h5>
<p>Digital data comes in all shapes, sizes and formats in the modern world CyberChef helps to make sense of this data all on one easy-to-use platform.</p><br>
<h4>How</h4>
<h5><strong>How</strong></h5>
<p>The interface is designed with simplicity at its heart. Complex techniques are now as trivial as drag-and-drop. Simple functions can be combined to build up a "recipe", potentially resulting in complex analysis, which can be shared with other users and used with their input.</p>
<p>For those comfortable writing code, CyberChef is a quick and efficient way to prototype solutions to a problem which can then be scripted once proven to work.</p>
<p>For those comfortable writing code, CyberChef is a quick and efficient way to prototype solutions to a problem which can then be scripted once proven to work.</p><br>
<h4>Who</h4>
<p>It is expected that CyberChef will be useful for cybersecurity and antivirus companies. It should also appeal to the academic world and any individuals or companies involved in the analysis of digital data, be that software developers, analysts, mathematicians or casual puzzle solvers.</p>
<h5><strong>Who</strong></h5>
<p>It is expected that CyberChef will be useful for cybersecurity and antivirus companies. It should also appeal to the academic world and any individuals or companies involved in the analysis of digital data, be that software developers, analysts, mathematicians or casual puzzle solvers.</p><br>
<h4>Aim</h4>
<p>It is hoped that by releasing CyberChef through <a href="https://github.com/gchq/cyberchef">GitHub</a>, contributions can be added which can be rolled out into future versions of the tool.</p>
<h5><strong>Aim</strong></h5>
<p>It is hoped that by releasing CyberChef through <a href="https://github.com/gchq/CyberChef">GitHub</a>, contributions can be added which can be rolled out into future versions of the tool.</p><br>
<br>
<p>There are around 150 useful operations in CyberChef for anyone working on anything vaguely Internet-related, whether you just want to convert a timestamp to a different format, decompress gzipped data, create a SHA3 hash, or parse an X.509 certificate to find out who issued it.</p>
@@ -372,7 +474,7 @@
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
<a href="https://github.com/gchq/CyberChef">
<img style="position: absolute; top: 0; right: 0; border: 0;" src="<%- require('../static/images/fork_me.png') %>" alt="Fork me on GitHub">
<img aria-hidden="true" style="position: absolute; top: 0; right: 0; border: 0;" src="<%- require('../static/images/fork_me.png') %>" alt="Fork me on GitHub">
</a>
</div>
</div>
@@ -387,11 +489,11 @@
<div class="modal-body" id="confirm-body"></div>
<div class="modal-footer">
<button type="button" class="btn btn-success" id="confirm-yes">
<img src="<%- require('../static/images/thumb_up-16x16.png') %>" />
<img aria-hidden="true" src="<%- require('../static/images/thumb_up-16x16.png') %>" alt="Thumbs Up"/>
Yes
</button>
<button type="button" class="btn btn-danger" id="confirm-no" data-dismiss="modal">
<img src="<%- require('../static/images/thumb_down-16x16.png') %>" />
<img aria-hidden="true" src="<%- require('../static/images/thumb_down-16x16.png') %>" alt="Thumbs Down"/>
No
</button>
</div>

View File

@@ -4,8 +4,8 @@
* @license Apache-2.0
*/
// CSS
import "./css/index.js";
// Styles
import "./stylesheets/index.js";
// Libs
import "babel-polyfill";
@@ -23,8 +23,8 @@ import OperationConfig from "../core/config/OperationConfig.js";
/**
* Main function used to build the CyberChef web app.
*/
var main = function() {
var defaultFavourites = [
function main() {
const defaultFavourites = [
"To Base64",
"From Base64",
"To Hex",
@@ -37,21 +37,22 @@ var main = function() {
"Fork"
];
var defaultOptions = {
updateUrl : true,
showHighlighter : true,
treatAsUtf8 : true,
wordWrap : true,
showErrors : true,
errorTimeout : 4000,
autoBakeThreshold : 200,
attemptHighlight : true,
const defaultOptions = {
updateUrl: true,
showHighlighter: true,
treatAsUtf8: true,
wordWrap: true,
showErrors: true,
errorTimeout: 4000,
autoBakeThreshold: 200,
attemptHighlight: true,
theme: "classic",
};
document.removeEventListener("DOMContentLoaded", main, false);
window.app = new App(Categories, OperationConfig, defaultFavourites, defaultOptions);
window.app.setup();
};
}
// Fix issues with browsers that don't support console.log()
window.console = console || {log: function() {}, error: function() {}};

View File

@@ -9,7 +9,7 @@
ga('create', 'UA-85682716-2', 'auto');
// Specifying location.pathname here overrides the default URL which would include arguments.
// Specifying location.pathname here overrides the default URL which could include arguments.
// This method prevents Google Analytics from logging any recipe or input data in the URL.
ga('send', 'pageview', location.pathname);

View File

@@ -0,0 +1,23 @@
[
{
"@context": "http://schema.org",
"@type": "Organization",
"url": "https://gchq.github.io/CyberChef/",
"logo": "https://gchq.github.io/CyberChef/images/cyberchef-128x128.png",
"sameAs": [
"https://github.com/gchq/CyberChef",
"https://www.npmjs.com/package/cyberchef"
]
},
{
"@context": "http://schema.org",
"@type": "WebSite",
"url": "https://gchq.github.io/CyberChef/",
"name": "CyberChef",
"potentialAction": {
"@type": "SearchAction",
"target": "https://gchq.github.io/CyberChef/?op={operation_search_term}",
"query-input": "required name=operation_search_term"
}
}
]

View File

@@ -0,0 +1,22 @@
/**
* Alert styles
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2017
* @license Apache-2.0
*/
#alert {
position: fixed;
width: 30%;
margin: 30px auto;
top: 10px;
left: 0;
right: 0;
z-index: 2000;
display: none;
}
#alert a {
text-decoration: underline;
}

View File

@@ -0,0 +1,13 @@
/**
* Button styles
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2017
* @license Apache-2.0
*/
button img,
span.btn img {
margin-right: 3px;
margin-bottom: 1px;
}

View File

@@ -0,0 +1,43 @@
/**
* Operation list styles
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2017
* @license Apache-2.0
*/
.op-list {
list-style-type: none;
margin: 0;
padding: 0;
}
.category-title {
display: block;
padding: 10px;
background-color: var(--secondary-background-colour);
border-bottom: 1px solid var(--secondary-border-colour);
font-weight: var(--title-weight);
}
.category-title[href='#catFavourites'] {
border-bottom-color: var(--primary-border-colour);
}
.category-title[aria-expanded=true] {
border-bottom-color: var(--primary-border-colour);
}
.category-title.collapsed {
border-bottom-color: var(--secondary-border-colour);
}
.category-title:hover {
color: var(--op-list-operation-font-colour);
}
.category {
margin: 0 !important;
border-radius: 0 !important;
border: none;
}

View File

@@ -0,0 +1,197 @@
/**
* Operation styles
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2017
* @license Apache-2.0
*/
.operation {
cursor: pointer;
padding: 10px;
list-style-type: none;
position: relative;
border-width: 1px;
border-style: solid;
border-top: none;
border-left: none;
border-right: none;
}
.arg-group {
display: table;
width: 100%;
margin-top: 10px;
}
.arg-group-text {
display: block;
}
.inline-args {
float: left;
width: auto;
margin-right: 30px;
height: 34px;
}
.inline-args input[type="checkbox"] {
margin-top: 10px;
}
.inline-args input[type="number"] {
width: 100px;
}
.arg-title {
font-weight: var(--arg-title-font-weight);
}
.arg-input {
display: table-cell;
width: 100%;
padding: 6px 12px;
vertical-align: middle;
height: var(--arg-input-height);
font-size: var(--arg-input-font-size);
line-height: var(--arg-input-line-height);
color: var(--arg-font-colour);
background-color: var(--arg-background);
border: 1px solid var(--arg-border-colour);
font-family: var(--fixed-width-font-family);
text-overflow: ellipsis;
}
.short-string {
width: 150px;
}
select {
display: block;
padding: 6px 8px;
height: 34px;
border: 1px solid var(--arg-border-colour);
background-color: var(--arg-background);
color: var(--arg-font-colour);
}
.arg[disabled] {
cursor: not-allowed;
opacity: 1;
background-color: var(--arg-disabled-background);
}
textarea.arg {
width: 100%;
min-height: 50px;
height: 70px;
margin-top: 5px;
border: 1px solid var(--arg-border-colour);
resize: vertical;
color: var(--arg-font-colour);
background-color: var(--arg-background);
font-family: var(--fixed-width-font-family);
}
.arg-label {
display: table-cell;
width: 1px;
padding-right: 10px;
font-weight: normal;
vertical-align: middle;
white-space: pre;
}
.editable-option {
position: relative;
display: inline-block;
}
.editable-option-select {
min-width: 250px;
}
.editable-option-input {
position: absolute;
top: 1px;
left: 1px;
width: calc(100% - 20px);
height: calc(100% - 2px) !important;
border: none !important;
}
button.dropdown-toggle {
background-color: var(--secondary-background-colour);
}
.op-icon {
float: right;
margin-left: 10px;
margin-top: 3px;
}
.recip-icons {
position: absolute;
top: 13px;
right: 10px;
height: 16px;
}
.recip-icon {
margin-right: 10px;
vertical-align: baseline;
float: right;
}
.disable-icon {
width: 16px;
height: 16px;
margin-top: -1px;
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAABmJLR0QA/wD/AP+gvaeTAAAACXBIWXMAAAsTAAALEwEAmpwYAAACfElEQVQ4y6WTPWgTYRjHf8nlfVvuoDVIP4Yuki4WHKoUqggFRUTsUEGkVG2hmCq6OnTwIxYHB+eijZOKdLNDW1pKKyGigh8dBHUJElxyBgx3vEnukvdyDrUhRXDxGR+e/+/583xEwjDkfyIGwNVTzURm4tYAMA6MAoN/0tvAMrA48uL+l2bx4w0iYRjSuHKC6OnTZLqHk8CcaZq9bW1tSCkBqNVq+L5PpVIpAHdGfr5LN9bXiT7Z2nGgteb1/qFkLBJZ6OjowHEc8vk8pVIJgHg8TldXF52dnb2u6y5s7R/iuF5JSyAKkLl4eyAMwznLsrBtm1wu99Z13amk+BFJih8R13WXANrb27EsizAM5zIXbw+wC9Baj0spe5VSFAqFt4ZhXJ6ufXuK55E5cDKVSCTGenp6yGazKKWQUvZqrcebgCAIRqWUOI6DEOLR1K8POapVMgfPpoC7u2LLspYcx0FKSRAEo60OBg3DwPd9Jr5vPqWvj8zh83vEwL2J75vnfN/HMAy01oPNNQZBQBAEO1OvVsl0D/8lTuZfpYDd7gRBQKuD7XK5jGmarB679PIv8deVFJUKq8cuTZqmSblcRmu93QpYVkohhMCyrLE94n2/UlSrbJy5kRBCXBNCoJRCa73cClh0XbfgeR6WZZHNZunv719KvnmeYnWVVxdmJ2Ox2DMhxFHP83Bdt6C1XgR2LvHzQDvvb84npZQL8Xgc0zSJRqN7br7RaFCpVCiVStRqtZmhh9fTh754TQdMr82nPc+bsW27UCwWUUpRr9ep1+sopSgWi9i2XfA8b2Z6bT6ttabp4GMi0uz0aXbhn890+MFM85mO5MIdwP/Eb1pMUCdctYRzAAAAAElFTkSuQmCC') no-repeat;
}
.disable-icon-selected {
background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAACFUlEQVR4XqWTP0tbURjGn9zY3mjBwsUhBQtS6XKxiNypIGZJ6SKYUYdaKWg7OrrE3pYO+Qit3dpFuuQO6lI7Z4nESQdjlJbkJh0MksSb3Jvk9H0gjZFu9YWH83LO7zn/3nNCSincJobAeP1sEDBFi6J50UyPy4l2RNuioz756Ts0tt1OB4jH2a52Ne2HGh9PwrJm2EcxZx/HyPRYMDgB2u02/N3d1c7w8BZMM1ptNJBPp3GwsUExB/s4RoYsPf0JOkFgdoH34YkJ/D48xC/HyTTOzl5ayWSIktwxqlVo0SjIkKWnP0Hg+4swjGitVMJFNpu5o+svptfXv6DZBDIZezoWS3Db3A0ZsvRcH8H354dGR9EoFHA3EvlorqycwvOAXM4G8Pav+f7YmEOGLD1gsIzl54+V+vBK/Yw9ZAv1LQW1FrdFSnKVfQTK5liPUfRI9I8ArqiPjLAF9vcHVybyzlpasgcZeq7voNXKNSsV3DMMXB4fp/8xLyzYuLri2DIZsvQM3sFOzXURiUR4zsQNcyrFleFVKpNyP2/IkKVnsArbF65bbkqplJSJZrl5x5qbs7G3h3artSyV+arr+lMyZOnpP2Wp6ZFos3R+vvUgCGDNzgKalkA4rECIr07662J2i0X4nrfJJ33jJT6Zmvpcr9XWCicn5WI+j7rrAmKgmLOPY2TI0sPgb8TBZOi/PpN1qnDr7/wH3jxgB/FKIXkAAAAASUVORK5CYII=') no-repeat;
}
.breakpoint {
float: right;
width: 14px;
height: 14px;
background-color: #eee;
border: 1px solid #aaa;
}
.breakpoint-selected {
background: #eee url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAAAXVBMVEXIUkvzUVHzTEzzn5785eXrbW24BgbzWVnze3vzVVXzY2Pyion509PzbW3zXV1UMxj0l5f1srKbRTRgOxzJDg796ur74ODfIyP5zs6LLx3pNTXYGxuxdkVZNhn////sCC1eAAAAAXRSTlMAQObYZgAAAAFiS0dEAIgFHUgAAAAJcEhZcwAACxMAAAsTAQCanBgAAABWSURBVBjTnc+7EoAgDERRTOQVxMEZFAf//z8FjAUFDbfb060QU2FwxngimxnCea3bjegSgz+0tguAfBgIy64QGfZQdg91dgAtqUZgnfz6IacYVWvu2AvR4wNAv0nxrAAAAABJRU5ErkJggg==') no-repeat -2px -2px;
}
.break {
color: var(--breakpoint-font-colour) !important;
background-color: var(--breakpoint-bg-colour) !important;
border-color: var(--breakpoint-border-colour) !important;
}
.selected-op {
color: var(--selected-operation-font-color) !important;
background-color: var(--selected-operation-bg-colour) !important;
border-color: var(--selected-operation-border-colour) !important;
}
.flow-control-op {
color: var(--fc-operation-font-colour) !important;
background-color: var(--fc-operation-bg-colour) !important;
border-color: var(--fc-operation-border-colour) !important;
}
.flow-control-op.break {
color: var(--fc-breakpoint-operation-font-colour) !important;
background-color: var(--fc-breakpoint-operation-bg-colour) !important;
border-color: var(--fc-breakpoint-operation-border-colour) !important;
}
.disabled {
color: var(--disabled-font-colour) !important;
background-color: var(--disabled-bg-colour) !important;
border-color: var(--disabled-border-colour) !important;
}

View File

@@ -0,0 +1,30 @@
/**
* Workspace pane styles
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2017
* @license Apache-2.0
*/
:root {
--title-height: 43px;
}
.title {
padding: 10px;
height: var(--title-height);
border-bottom: 1px solid var(--primary-border-colour);
font-weight: var(--title-weight);
color: var(--title-colour);
background-color: var(--title-background-colour);
}
.list-area {
position: absolute;
top: var(--title-height);
bottom: 0;
width: 100%;
list-style-type: none;
margin: 0;
padding: 0;
}

View File

@@ -0,0 +1,35 @@
/**
* CyberChef styles
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2017
* @license Apache-2.0
*/
/* Themes */
@import "./themes/_classic.css";
@import "./themes/_dark.css";
@import "./themes/_geocities.css";
/* Utilities */
@import "./utils/_overrides.css";
@import "./utils/_general.css";
/* Preloader styles */
@import "./preloader.css";
/* Components */
@import "./components/_alert.css";
@import "./components/_button.css";
@import "./components/_list.css";
@import "./components/_operation.css";
@import "./components/_pane.css";
/* Layout */
@import "./layout/_banner.css";
@import "./layout/_controls.css";
@import "./layout/_io.css";
@import "./layout/_modals.css";
@import "./layout/_operations.css";
@import "./layout/_recipe.css";
@import "./layout/_structure.css";

View File

@@ -0,0 +1,18 @@
/**
* Styles index
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2017
* @license Apache-2.0
*/
/* Libraries */
import "google-code-prettify/src/prettify.css";
/* Frameworks */
import "./vendors/bootstrap.less";
import "bootstrap-switch/dist/css/bootstrap3/bootstrap-switch.css";
import "bootstrap-colorpicker/dist/css/bootstrap-colorpicker.css";
/* CyberChef styles */
import "./index.css";

View File

@@ -0,0 +1,24 @@
/**
* Banner area styles
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2017
* @license Apache-2.0
*/
#banner {
position: absolute;
height: 30px;
width: 100%;
line-height: 30px;
border-bottom: 1px solid var(--primary-border-colour);
color: var(--banner-font-colour);
background-color: var(--banner-bg-colour);
}
#banner img {
margin-bottom: 2px;
margin-left: 8px;
padding-right: 10px;
}

View File

@@ -0,0 +1,65 @@
/**
* Controls area styles
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2017
* @license Apache-2.0
*/
:root {
--controls-height: 120px;
--controls-division: 65%;
}
#controls {
position: absolute;
width: 100%;
height: var(--controls-height);
bottom: 0;
padding: 10px;
border-top: 1px solid var(--primary-border-colour);
background-color: var(--secondary-background-colour);
}
#operational-controls {
width: var(--controls-division);
float: left;
text-align: center;
}
#bake-group {
display: table;
width: 100%;
}
#bake {
display: table-cell;
width: 100%;
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
#auto-bake-label {
display: table-cell;
padding: 1px;
line-height: 1.35;
width: 60px;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
border-left: 1px solid var(--btn-success-bg-colour);
}
#auto-bake-label:hover {
border-left-color: var(--btn-success-hover-border-colour);
}
#auto-bake-label div {
font-size: 10px;
padding: 2px;
}
#extra-controls {
float: right;
width: calc(100% - var(--controls-division));
padding-left: 10px;
}

View File

@@ -0,0 +1,109 @@
/**
* Input/Output area styles
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2017
* @license Apache-2.0
*/
#input-text,
#output-text,
#output-html {
position: relative;
width: 100%;
height: 100%;
margin: 0;
padding: 3px;
-moz-padding-start: 3px;
-moz-padding-end: 3px;
border: none;
border-width: 0px;
resize: none;
background-color: transparent;
white-space: pre-wrap;
word-wrap: break-word;
}
#output-html {
display: none;
overflow-y: auto;
-moz-padding-start: 1px; /* Fixes bug in Firefox */
}
.textarea-wrapper {
position: absolute;
top: 43px;
bottom: 0;
width: 100%;
overflow: hidden;
}
.textarea-wrapper textarea,
.textarea-wrapper div {
font-family: var(--fixed-width-font-family);
font-size: var(--fixed-width-font-size);
color: var(--fixed-width-font-colour);
}
#input-highlighter,
#output-highlighter {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
padding: 3px;
margin: 0;
overflow: hidden;
letter-spacing: normal;
white-space: pre-wrap;
word-wrap: break-word;
color: #fff;
background-color: transparent;
border: none;
}
.io-btn-group {
float: right;
margin-top: -4px;
}
.io-info {
margin-right: 20px;
margin-top: -4px;
float: right;
height: 30px;
text-align: right;
line-height: 10px;
font-family: var(--fixed-width-font-family);
font-weight: normal;
font-size: 8pt;
}
#input-info {
line-height: 15px;
}
.dropping-file {
border: 5px dashed var(--drop-file-border-colour) !important;
}
@keyframes spinner {
from {
transform:rotate(0deg);
}
to {
transform:rotate(359deg);
}
}
.loading-icon::before {
content: "\21bb";
}
.loading-icon {
animation-name: spinner;
animation-duration: 1000ms;
animation-iteration-count: infinite;
animation-timing-function: linear;
}

View File

@@ -0,0 +1,90 @@
/**
* Modal layout styles
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2017
* @license Apache-2.0
*/
.option-item .bootstrap-switch {
margin: 15px 10px;
}
.option-item button {
margin: 10px;
}
.option-item label {
font-weight: normal;
}
.option-item input[type=number] {
margin: 15px 10px;
width: 80px;
height: 28px;
padding: 3px 10px;
vertical-align: middle;
font-size: calc(var(--arg-input-font-size) - 1px);
line-height: var(--arg-input-line-height);
color: var(--arg-font-colour);
background-color: var(--arg-background);
border: 1px solid var(--primary-border-colour);
}
.option-item select {
margin: 10px;
display: inline-block;
}
#edit-favourites-list {
margin: 10px;
border: 1px solid var(--op-list-operation-border-colour);
}
#edit-favourites-list .operation {
border-left: none;
border-right: none;
}
#edit-favourites-list .operation:last-child {
border-bottom: none;
}
.about-img-left {
float: left;
margin: 10px 20px 20px 0;
}
.about-img-right {
float: right;
margin: 10px 0 20px 20px;
}
.save-link-options {
float: right;
}
.save-link-options input{
margin-left: 10px;
}
#save-footer {
border-top: none;
margin-top: 0;
border-bottom: 1px solid var(--primary-border-colour);
}
#support-modal textarea {
font-family: var(--primary-font-family);
}
#save-texts textarea,
#load-text {
font-family: var(--fixed-width-font-family);
}
#save-texts textarea {
border-top: none;
box-shadow: none;
height: 200px;
}

View File

@@ -0,0 +1,32 @@
/**
* Operation area styles
*
* @author n1474335 [n1474335@gmail.com]
* @copyright Crown Copyright 2017
* @license Apache-2.0
*/
.op-list .operation {
color: var(--op-list-operation-font-colour);
background-color: var(--op-list-operation-bg-colour);
border-color: var(--op-list-operation-border-colour);
}
#search {
border-radius: 0;
border: none;
border-bottom: 1px solid var(--primary-border-colour);
color: var(--primary-font-colour);
}
#edit-favourites {
float: right;
margin-top: -5px;
}
.favourites-hover {
color: var(--rec-list-operation-font-colour);
background-color: var(--rec-list-operation-bg-colour);
border: 2px dashed var(--rec-list-operation-font-colour) !important;
padding: 8px 8px 9px 8px;
}

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