mirror of
https://github.com/gchq/CyberChef.git
synced 2026-02-25 19:21:46 +01:00
Compare commits
59 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2821bdd52b | ||
|
|
d37300be39 | ||
|
|
15b83072bb | ||
|
|
6d2e2259db | ||
|
|
5b70614212 | ||
|
|
4363da534d | ||
|
|
685f7a4f00 | ||
|
|
6e26f25418 | ||
|
|
d8051ce9a2 | ||
|
|
00e7d8a390 | ||
|
|
61951e76ac | ||
|
|
47cf763b3f | ||
|
|
04aac03d6e | ||
|
|
3faef2c9c9 | ||
|
|
eda17d1671 | ||
|
|
fbd6ead6b7 | ||
|
|
bf2950abdd | ||
|
|
3eacc325a3 | ||
|
|
15decd9cd9 | ||
|
|
c0142adba9 | ||
|
|
ec01333c83 | ||
|
|
8110384ea2 | ||
|
|
0c2c0d7b8b | ||
|
|
ae38bb0927 | ||
|
|
003e076b00 | ||
|
|
2c2a0eb7d9 | ||
|
|
e7f5b17184 | ||
|
|
69e12b1067 | ||
|
|
fef446687a | ||
|
|
3affce8f98 | ||
|
|
0b91468edc | ||
|
|
127364e8a4 | ||
|
|
a144f65dcf | ||
|
|
96ec3a869b | ||
|
|
52426bc1a4 | ||
|
|
cbab995c6d | ||
|
|
d27fa43120 | ||
|
|
45a9da5b30 | ||
|
|
aed22aebb2 | ||
|
|
369d213da5 | ||
|
|
e92775eec2 | ||
|
|
2c0f48f4e5 | ||
|
|
a5f1c430a3 | ||
|
|
e4a91b5397 | ||
|
|
cbcd45cd70 | ||
|
|
0968912954 | ||
|
|
3bfe22c0f7 | ||
|
|
6cf64d794f | ||
|
|
6741ba0783 | ||
|
|
f1e7bc3363 | ||
|
|
2dbe2d044e | ||
|
|
ea3630e018 | ||
|
|
c6391d958d | ||
|
|
71aa4033a4 | ||
|
|
57dcd961d5 | ||
|
|
83878d6b05 | ||
|
|
9055fc72d2 | ||
|
|
fb4ab56b47 | ||
|
|
51e195ed17 |
@@ -93,6 +93,7 @@
|
||||
"moment": false,
|
||||
|
||||
"COMPILE_TIME": false,
|
||||
"COMPILE_MSG": false
|
||||
"COMPILE_MSG": false,
|
||||
"PKG_VERSION": false
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ deploy:
|
||||
local_dir: build/prod/
|
||||
target_branch: gh-pages
|
||||
on:
|
||||
repo: gchq/CyberChef
|
||||
branch: master
|
||||
- provider: releases
|
||||
skip_cleaup: true
|
||||
|
||||
46
CODE_OF_CONDUCT.md
Normal file
46
CODE_OF_CONDUCT.md
Normal 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/
|
||||
@@ -164,7 +164,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"),
|
||||
],
|
||||
|
||||
14
README.md
14
README.md
@@ -84,10 +84,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=%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
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cyberchef",
|
||||
"version": "5.7.2",
|
||||
"version": "5.10.5",
|
||||
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
|
||||
"author": "n1474335 <n1474335@gmail.com>",
|
||||
"homepage": "https://gchq.github.io/CyberChef",
|
||||
|
||||
@@ -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);
|
||||
},
|
||||
|
||||
@@ -216,7 +238,7 @@ const Utils = {
|
||||
str = Utils.byteArrayToChars(Utils.strToByteArray(str));
|
||||
}
|
||||
|
||||
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-\uF8FF\uFA6E\uFA6F\uFADA-\uFAFF\uFB07-\uFB12\uFB18-\uFB1C\uFB37\uFB3D\uFB3F\uFB42\uFB45\uFBC2-\uFBD2\uFD40-\uFD4F\uFD90\uFD91\uFDC8-\uFDEF\uFDFE\uFDFF\uFE1A-\uFE1F\uFE27-\uFE2F\uFE53\uFE67\uFE6C-\uFE6F\uFE75\uFEFD-\uFF00\uFFBF-\uFFC1\uFFC8\uFFC9\uFFD0\uFFD1\uFFD8\uFFD9\uFFDD-\uFFDF\uFFE7\uFFEF-\uFFFB\uFFFE\uFFFF]/g;
|
||||
const re = /[\0-\x08\x0B-\x0C\x0E-\x1F\x7F-\x9F\xAD\u0378\u0379\u037F-\u0383\u038B\u038D\u03A2\u0528-\u0530\u0557\u0558\u0560\u0588\u058B-\u058E\u0590\u05C8-\u05CF\u05EB-\u05EF\u05F5-\u0605\u061C\u061D\u06DD\u070E\u070F\u074B\u074C\u07B2-\u07BF\u07FB-\u07FF\u082E\u082F\u083F\u085C\u085D\u085F-\u089F\u08A1\u08AD-\u08E3\u08FF\u0978\u0980\u0984\u098D\u098E\u0991\u0992\u09A9\u09B1\u09B3-\u09B5\u09BA\u09BB\u09C5\u09C6\u09C9\u09CA\u09CF-\u09D6\u09D8-\u09DB\u09DE\u09E4\u09E5\u09FC-\u0A00\u0A04\u0A0B-\u0A0E\u0A11\u0A12\u0A29\u0A31\u0A34\u0A37\u0A3A\u0A3B\u0A3D\u0A43-\u0A46\u0A49\u0A4A\u0A4E-\u0A50\u0A52-\u0A58\u0A5D\u0A5F-\u0A65\u0A76-\u0A80\u0A84\u0A8E\u0A92\u0AA9\u0AB1\u0AB4\u0ABA\u0ABB\u0AC6\u0ACA\u0ACE\u0ACF\u0AD1-\u0ADF\u0AE4\u0AE5\u0AF2-\u0B00\u0B04\u0B0D\u0B0E\u0B11\u0B12\u0B29\u0B31\u0B34\u0B3A\u0B3B\u0B45\u0B46\u0B49\u0B4A\u0B4E-\u0B55\u0B58-\u0B5B\u0B5E\u0B64\u0B65\u0B78-\u0B81\u0B84\u0B8B-\u0B8D\u0B91\u0B96-\u0B98\u0B9B\u0B9D\u0BA0-\u0BA2\u0BA5-\u0BA7\u0BAB-\u0BAD\u0BBA-\u0BBD\u0BC3-\u0BC5\u0BC9\u0BCE\u0BCF\u0BD1-\u0BD6\u0BD8-\u0BE5\u0BFB-\u0C00\u0C04\u0C0D\u0C11\u0C29\u0C34\u0C3A-\u0C3C\u0C45\u0C49\u0C4E-\u0C54\u0C57\u0C5A-\u0C5F\u0C64\u0C65\u0C70-\u0C77\u0C80\u0C81\u0C84\u0C8D\u0C91\u0CA9\u0CB4\u0CBA\u0CBB\u0CC5\u0CC9\u0CCE-\u0CD4\u0CD7-\u0CDD\u0CDF\u0CE4\u0CE5\u0CF0\u0CF3-\u0D01\u0D04\u0D0D\u0D11\u0D3B\u0D3C\u0D45\u0D49\u0D4F-\u0D56\u0D58-\u0D5F\u0D64\u0D65\u0D76-\u0D78\u0D80\u0D81\u0D84\u0D97-\u0D99\u0DB2\u0DBC\u0DBE\u0DBF\u0DC7-\u0DC9\u0DCB-\u0DCE\u0DD5\u0DD7\u0DE0-\u0DF1\u0DF5-\u0E00\u0E3B-\u0E3E\u0E5C-\u0E80\u0E83\u0E85\u0E86\u0E89\u0E8B\u0E8C\u0E8E-\u0E93\u0E98\u0EA0\u0EA4\u0EA6\u0EA8\u0EA9\u0EAC\u0EBA\u0EBE\u0EBF\u0EC5\u0EC7\u0ECE\u0ECF\u0EDA\u0EDB\u0EE0-\u0EFF\u0F48\u0F6D-\u0F70\u0F98\u0FBD\u0FCD\u0FDB-\u0FFF\u10C6\u10C8-\u10CC\u10CE\u10CF\u1249\u124E\u124F\u1257\u1259\u125E\u125F\u1289\u128E\u128F\u12B1\u12B6\u12B7\u12BF\u12C1\u12C6\u12C7\u12D7\u1311\u1316\u1317\u135B\u135C\u137D-\u137F\u139A-\u139F\u13F5-\u13FF\u169D-\u169F\u16F1-\u16FF\u170D\u1715-\u171F\u1737-\u173F\u1754-\u175F\u176D\u1771\u1774-\u177F\u17DE\u17DF\u17EA-\u17EF\u17FA-\u17FF\u180F\u181A-\u181F\u1878-\u187F\u18AB-\u18AF\u18F6-\u18FF\u191D-\u191F\u192C-\u192F\u193C-\u193F\u1941-\u1943\u196E\u196F\u1975-\u197F\u19AC-\u19AF\u19CA-\u19CF\u19DB-\u19DD\u1A1C\u1A1D\u1A5F\u1A7D\u1A7E\u1A8A-\u1A8F\u1A9A-\u1A9F\u1AAE-\u1AFF\u1B4C-\u1B4F\u1B7D-\u1B7F\u1BF4-\u1BFB\u1C38-\u1C3A\u1C4A-\u1C4C\u1C80-\u1CBF\u1CC8-\u1CCF\u1CF7-\u1CFF\u1DE7-\u1DFB\u1F16\u1F17\u1F1E\u1F1F\u1F46\u1F47\u1F4E\u1F4F\u1F58\u1F5A\u1F5C\u1F5E\u1F7E\u1F7F\u1FB5\u1FC5\u1FD4\u1FD5\u1FDC\u1FF0\u1FF1\u1FF5\u1FFF\u200B-\u200F\u202A-\u202E\u2060-\u206F\u2072\u2073\u208F\u209D-\u209F\u20BB-\u20CF\u20F1-\u20FF\u218A-\u218F\u23F4-\u23FF\u2427-\u243F\u244B-\u245F\u2700\u2B4D-\u2B4F\u2B5A-\u2BFF\u2C2F\u2C5F\u2CF4-\u2CF8\u2D26\u2D28-\u2D2C\u2D2E\u2D2F\u2D68-\u2D6E\u2D71-\u2D7E\u2D97-\u2D9F\u2DA7\u2DAF\u2DB7\u2DBF\u2DC7\u2DCF\u2DD7\u2DDF\u2E3C-\u2E7F\u2E9A\u2EF4-\u2EFF\u2FD6-\u2FEF\u2FFC-\u2FFF\u3040\u3097\u3098\u3100-\u3104\u312E-\u3130\u318F\u31BB-\u31BF\u31E4-\u31EF\u321F\u32FF\u4DB6-\u4DBF\u9FCD-\u9FFF\uA48D-\uA48F\uA4C7-\uA4CF\uA62C-\uA63F\uA698-\uA69E\uA6F8-\uA6FF\uA78F\uA794-\uA79F\uA7AB-\uA7F7\uA82C-\uA82F\uA83A-\uA83F\uA878-\uA87F\uA8C5-\uA8CD\uA8DA-\uA8DF\uA8FC-\uA8FF\uA954-\uA95E\uA97D-\uA97F\uA9CE\uA9DA-\uA9DD\uA9E0-\uA9FF\uAA37-\uAA3F\uAA4E\uAA4F\uAA5A\uAA5B\uAA7C-\uAA7F\uAAC3-\uAADA\uAAF7-\uAB00\uAB07\uAB08\uAB0F\uAB10\uAB17-\uAB1F\uAB27\uAB2F-\uABBF\uABEE\uABEF\uABFA-\uABFF\uD7A4-\uD7AF\uD7C7-\uD7CA\uD7FC-\uD7FF\uE000-\uF8FF\uFA6E\uFA6F\uFADA-\uFAFF\uFB07-\uFB12\uFB18-\uFB1C\uFB37\uFB3D\uFB3F\uFB42\uFB45\uFBC2-\uFBD2\uFD40-\uFD4F\uFD90\uFD91\uFDC8-\uFDEF\uFDFE\uFDFF\uFE1A-\uFE1F\uFE27-\uFE2F\uFE53\uFE67\uFE6C-\uFE6F\uFE75\uFEFD-\uFF00\uFFBF-\uFFC1\uFFC8\uFFC9\uFFD0\uFFD1\uFFD8\uFFD9\uFFDD-\uFFDF\uFFE7\uFFEF-\uFFFB\uFFFE\uFFFF]/g;
|
||||
const wsRe = /[\x09-\x10\x0D\u2028\u2029]/g;
|
||||
|
||||
str = str.replace(re, ".");
|
||||
@@ -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.
|
||||
*
|
||||
@@ -396,7 +434,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 +447,23 @@ const Utils = {
|
||||
* Utils.strToCharcode("你好");
|
||||
*/
|
||||
strToCharcode: function(str) {
|
||||
const byteArray = new Array(str.length);
|
||||
let 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;
|
||||
},
|
||||
|
||||
|
||||
@@ -965,6 +1014,37 @@ const Utils = {
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* 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 &
|
||||
const params = paramStr.substr(1).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.
|
||||
*
|
||||
|
||||
@@ -126,6 +126,7 @@ const Categories = [
|
||||
{
|
||||
name: "Networking",
|
||||
ops: [
|
||||
"HTTP request",
|
||||
"Strip HTTP headers",
|
||||
"Parse User Agent",
|
||||
"Parse IP range",
|
||||
@@ -192,6 +193,8 @@ const Categories = [
|
||||
"Translate DateTime Format",
|
||||
"From UNIX Timestamp",
|
||||
"To UNIX Timestamp",
|
||||
"Windows Filetime to UNIX Timestamp",
|
||||
"UNIX Timestamp to Windows Filetime",
|
||||
"Extract dates",
|
||||
]
|
||||
},
|
||||
@@ -288,6 +291,8 @@ const Categories = [
|
||||
"Scan for Embedded Files",
|
||||
"Generate UUID",
|
||||
"Render Image",
|
||||
"Remove EXIF",
|
||||
"Extract EXIF",
|
||||
"Numberwang",
|
||||
]
|
||||
},
|
||||
|
||||
@@ -605,7 +605,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,
|
||||
@@ -1919,7 +1919,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",
|
||||
@@ -2231,7 +2231,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",
|
||||
@@ -2244,7 +2244,7 @@ const OperationConfig = {
|
||||
]
|
||||
},
|
||||
"To UNIX Timestamp": {
|
||||
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>",
|
||||
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",
|
||||
@@ -2261,6 +2261,32 @@ const OperationConfig = {
|
||||
}
|
||||
]
|
||||
},
|
||||
"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
|
||||
}
|
||||
]
|
||||
},
|
||||
"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
|
||||
}
|
||||
]
|
||||
},
|
||||
"Translate DateTime Format": {
|
||||
description: "Parses a datetime string in one format and re-writes it in another.<br><br>Run with no input to see the relevant format string examples.",
|
||||
run: DateTime.runTranslateFormat,
|
||||
@@ -3370,7 +3396,7 @@ const OperationConfig = {
|
||||
"<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.runEXIF,
|
||||
run: Image.runExtractEXIF,
|
||||
inputType: "byteArray",
|
||||
outputType: "string",
|
||||
args: [],
|
||||
@@ -3388,6 +3414,59 @@ const OperationConfig = {
|
||||
}
|
||||
]
|
||||
},
|
||||
"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,
|
||||
}
|
||||
]
|
||||
},
|
||||
};
|
||||
|
||||
export default OperationConfig;
|
||||
|
||||
153
src/core/lib/remove-exif.js
Normal file
153
src/core/lib/remove-exif.js
Normal 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;
|
||||
@@ -108,8 +108,9 @@ const ByteRepr = {
|
||||
throw "Error: Base argument must be between 2 and 36";
|
||||
}
|
||||
|
||||
for (let 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;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import {BigInteger} from "jsbn";
|
||||
|
||||
/**
|
||||
* Date and time operations.
|
||||
*
|
||||
@@ -78,6 +80,58 @@ 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];
|
||||
input = new BigInteger(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];
|
||||
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";
|
||||
}
|
||||
return input.add(new BigInteger("116444736000000000")).toString();
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* @constant
|
||||
* @default
|
||||
|
||||
@@ -91,7 +91,7 @@ const HTML = {
|
||||
const bite = HTML._entityToByte[m[1]];
|
||||
if (bite) {
|
||||
output += Utils.chr(bite);
|
||||
} else if (!bite && m[1][0] === "#" && m[1].length > 1 && /^#\d{1,5}$/.test(m[1])) {
|
||||
} else if (!bite && m[1][0] === "#" && m[1].length > 1 && /^#\d{1,6}$/.test(m[1])) {
|
||||
// Numeric entity (e.g. )
|
||||
const num = m[1].slice(1, m[1].length);
|
||||
output += Utils.chr(parseInt(num, 10));
|
||||
|
||||
@@ -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.
|
||||
*
|
||||
@@ -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;
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import * as ExifParser from "exif-parser";
|
||||
import removeEXIF from "../lib/remove-exif.js";
|
||||
import Utils from "../Utils.js";
|
||||
import FileType from "./FileType.js";
|
||||
|
||||
@@ -23,7 +24,7 @@ const Image = {
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
runEXIF(input, args) {
|
||||
runExtractEXIF(input, args) {
|
||||
try {
|
||||
const bytes = Uint8Array.from(input);
|
||||
const parser = ExifParser.create(bytes.buffer);
|
||||
@@ -44,6 +45,30 @@ const Image = {
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
@@ -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.
|
||||
@@ -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();
|
||||
@@ -221,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;
|
||||
|
||||
@@ -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);
|
||||
},
|
||||
|
||||
|
||||
|
||||
@@ -21,21 +21,22 @@ import Split from "split.js";
|
||||
* @param {Object} options - Default setting for app options.
|
||||
*/
|
||||
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.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.baking = false;
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
@@ -166,7 +167,7 @@ App.prototype.bake = async function(step) {
|
||||
* Runs Auto Bake if it is set.
|
||||
*/
|
||||
App.prototype.autoBake = function() {
|
||||
if (this.autoBake_) {
|
||||
if (this.autoBake_ && !this.autoBakePause) {
|
||||
this.bake();
|
||||
}
|
||||
};
|
||||
@@ -398,39 +399,28 @@ 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 {};
|
||||
const b = {};
|
||||
for (let i = 0; i < a.length; i++) {
|
||||
const 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)
|
||||
const params = window.location.search || window.location.hash;
|
||||
this.uriParams = Utils.parseURIParams(params);
|
||||
|
||||
// Turn off auto-bake while loading
|
||||
const 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 {
|
||||
const recipeConfig = JSON.parse(this.queryString.recipe);
|
||||
const recipeConfig = JSON.parse(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
|
||||
const 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);
|
||||
}
|
||||
@@ -438,21 +428,21 @@ App.prototype.loadURIParams = function() {
|
||||
// Populate search with the string
|
||||
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 {
|
||||
const 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();
|
||||
};
|
||||
|
||||
@@ -688,9 +678,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();
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -174,20 +174,21 @@ ControlsWaiter.prototype.generateStateUrl = function(includeRecipe, includeInput
|
||||
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);
|
||||
|
||||
const params = [
|
||||
includeRecipe ? ["recipe", recipeStr] : undefined,
|
||||
includeInput ? ["input", inputStr] : undefined,
|
||||
];
|
||||
|
||||
const query = params
|
||||
const hash = params
|
||||
.filter(v => v)
|
||||
.map(([key, value]) => `${key}=${encodeURIComponent(value)}`)
|
||||
.join("&");
|
||||
|
||||
if (query) {
|
||||
return `${link}?${query}`;
|
||||
if (hash) {
|
||||
return `${link}#${hash}`;
|
||||
}
|
||||
|
||||
return link;
|
||||
@@ -350,14 +351,21 @@ ControlsWaiter.prototype.loadButtonClick = function() {
|
||||
|
||||
/**
|
||||
* Populates the bug report information box with useful technical info.
|
||||
*
|
||||
* @param {event} e
|
||||
*/
|
||||
ControlsWaiter.prototype.supportButtonClick = function() {
|
||||
ControlsWaiter.prototype.supportButtonClick = function(e) {
|
||||
e.preventDefault();
|
||||
|
||||
const reportBugInfo = document.getElementById("report-bug-info");
|
||||
const saveLink = this.generateStateUrl(true, true, null, "https://gchq.github.io/CyberChef/");
|
||||
|
||||
reportBugInfo.innerHTML = "* CyberChef compile time: " + COMPILE_TIME + "\n" +
|
||||
"* User-Agent: \n" + navigator.userAgent + "\n" +
|
||||
"* [Link to reproduce](" + saveLink + ")\n\n";
|
||||
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;
|
||||
|
||||
@@ -47,6 +47,8 @@ OptionsWaiter.prototype.load = function(options) {
|
||||
if (val) {
|
||||
selects[i].value = val;
|
||||
selects[i].dispatchEvent(new CustomEvent("change", {bubbles: true}));
|
||||
} else {
|
||||
selects[i].selectedIndex = 0;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -55,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();
|
||||
};
|
||||
|
||||
|
||||
@@ -354,8 +354,7 @@ RecipeWaiter.prototype.buildRecipeOperation = function(el) {
|
||||
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);
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
// Load theme before the preloader is shown
|
||||
document.querySelector(":root").className = JSON.parse(localStorage.getItem("options")).theme;
|
||||
|
||||
// Cycle loading messages
|
||||
// Define loading messages
|
||||
const loadingMsgs = [
|
||||
"Proving P = NP...",
|
||||
"Computing 6 x 9...",
|
||||
@@ -49,15 +49,28 @@
|
||||
"Navigating neural network...",
|
||||
"Importing machine learning..."
|
||||
];
|
||||
|
||||
// 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 then move it to the end of the array
|
||||
function changeLoadingMsg() {
|
||||
const msg = loadingMsgs.shift();
|
||||
try {
|
||||
const el = document.getElementById("preloader-msg");
|
||||
el.className = "loading"; // Causes CSS transition on first message
|
||||
el.innerHTML = loadingMsgs[Math.floor(Math.random()*loadingMsgs.length)];
|
||||
} catch (err) {}
|
||||
el.innerHTML = msg;
|
||||
} catch (err) {} // Ignore errors if DOM not yet ready
|
||||
loadingMsgs.push(msg);
|
||||
}
|
||||
|
||||
changeLoadingMsg();
|
||||
window.loadingMsgsInt = setInterval(changeLoadingMsg, (Math.random()*500) + 500);
|
||||
window.loadingMsgsInt = setInterval(changeLoadingMsg, (Math.random() * 1000) + 1000);
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
@@ -328,7 +341,7 @@
|
||||
Compile time: <%= htmlWebpackPlugin.options.compileTime %>
|
||||
</p>
|
||||
<p>© Crown Copyright 2016.</p>
|
||||
<p>Licenced under the Apache Licence, Version 2.0.</p>
|
||||
<p>Released under the Apache Licence, Version 2.0.</p>
|
||||
<br>
|
||||
<br>
|
||||
<div>
|
||||
@@ -355,14 +368,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=%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>
|
||||
</ul>
|
||||
</div>
|
||||
<blockquote>
|
||||
@@ -382,7 +395,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=%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>
|
||||
</div>
|
||||
</div>
|
||||
<div role="tabpanel" class="tab-pane" id="report-bug">
|
||||
@@ -394,21 +407,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>
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -14,6 +14,10 @@
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.option-item label {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.option-item input[type=number] {
|
||||
margin: 15px 10px;
|
||||
width: 80px;
|
||||
|
||||
@@ -202,6 +202,11 @@ optgroup {
|
||||
border-color: var(--primary-border-colour);
|
||||
}
|
||||
|
||||
.bootstrap-switch .bootstrap-switch-handle-off.bootstrap-switch-default {
|
||||
background-color: var(--primary-border-colour);
|
||||
color: var(--primary-font-colour);
|
||||
}
|
||||
|
||||
|
||||
/* Sortable */
|
||||
|
||||
|
||||
2
src/web/stylesheets/vendors/bootstrap.less
vendored
2
src/web/stylesheets/vendors/bootstrap.less
vendored
@@ -19,7 +19,7 @@
|
||||
@import "~bootstrap/less/scaffolding.less";
|
||||
@import "~bootstrap/less/type.less";
|
||||
@import "~bootstrap/less/code.less";
|
||||
// @import "~bootstrap/less/grid.less";
|
||||
@import "~bootstrap/less/grid.less";
|
||||
@import "~bootstrap/less/tables.less";
|
||||
@import "~bootstrap/less/forms.less";
|
||||
@import "~bootstrap/less/buttons.less";
|
||||
|
||||
@@ -16,10 +16,12 @@ import "./tests/operations/ByteRepr.js";
|
||||
import "./tests/operations/CharEnc.js";
|
||||
import "./tests/operations/Code.js";
|
||||
import "./tests/operations/Compress.js";
|
||||
import "./tests/operations/DateTime.js";
|
||||
import "./tests/operations/FlowControl.js";
|
||||
import "./tests/operations/Image.js";
|
||||
import "./tests/operations/MorseCode.js";
|
||||
import "./tests/operations/StrUtils.js";
|
||||
import "./tests/operations/SeqUtils.js";
|
||||
|
||||
let allTestsPassing = true;
|
||||
const testStatusCounts = {
|
||||
|
||||
34
test/tests/operations/DateTime.js
Normal file
34
test/tests/operations/DateTime.js
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* DateTime tests.
|
||||
*
|
||||
* @author bwhitn [brian.m.whitney@outlook.com]
|
||||
*
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
import TestRegister from "../../TestRegister.js";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "Filetime to Unix",
|
||||
input: "129207366395297693",
|
||||
expectedOutput: "1276263039529769300",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "Windows Filetime to UNIX Timestamp",
|
||||
args: ["Nanoseconds (ns)"],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "Unix to Filetime",
|
||||
input: "1276263039529769300",
|
||||
expectedOutput: "129207366395297693",
|
||||
recipeConfig: [
|
||||
{
|
||||
op: "UNIX Timestamp to Windows Filetime",
|
||||
args: ["Nanoseconds (ns)"],
|
||||
},
|
||||
],
|
||||
},
|
||||
]);
|
||||
File diff suppressed because one or more lines are too long
33
test/tests/operations/SeqUtils.js
Normal file
33
test/tests/operations/SeqUtils.js
Normal file
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* SeqUtils tests.
|
||||
*
|
||||
* @author Chris van Marle
|
||||
* @copyright Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
import TestRegister from "../../TestRegister.js";
|
||||
|
||||
TestRegister.addTests([
|
||||
{
|
||||
name: "SeqUtils - Numeric sort photos",
|
||||
input: "Photo-1.jpg\nPhoto-4.jpg\nPhoto-2.jpg\nPhoto-3.jpg\n",
|
||||
expectedOutput: "Photo-1.jpg\nPhoto-2.jpg\nPhoto-3.jpg\nPhoto-4.jpg\n",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Sort",
|
||||
"args": ["Line feed", false, "Numeric"]
|
||||
}
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "SeqUtils - Numeric sort CVE IDs",
|
||||
input: "CVE-2017-1234,CVE-2017-9999,CVE-2017-10000,CVE-2017-10001,CVE-2017-12345,CVE-2016-1234,CVE-2016-4321,CVE-2016-10000,CVE-2016-9999,CVE-2016-10001",
|
||||
expectedOutput: "CVE-2017-12345,CVE-2017-10001,CVE-2017-10000,CVE-2017-9999,CVE-2017-1234,CVE-2016-10001,CVE-2016-10000,CVE-2016-9999,CVE-2016-4321,CVE-2016-1234",
|
||||
recipeConfig: [
|
||||
{
|
||||
"op": "Sort",
|
||||
"args": ["Comma", true, "Numeric"]
|
||||
}
|
||||
],
|
||||
},
|
||||
]);
|
||||
Reference in New Issue
Block a user