Merge remote-tracking branch 'upstream/master' into dish-fix

This commit is contained in:
n1073645 2019-12-13 16:11:48 +00:00
commit 6e411c9dd9
10 changed files with 2085 additions and 1298 deletions

3163
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
{
"name": "cyberchef",
"version": "9.11.11",
"version": "9.11.14",
"description": "The Cyber Swiss Army Knife for encryption, encoding, compression and data analysis.",
"author": "n1474335 <n1474335@gmail.com>",
"homepage": "https://gchq.github.io/CyberChef",
@ -36,20 +36,20 @@
"node >= 10"
],
"devDependencies": {
"@babel/core": "^7.7.2",
"@babel/plugin-transform-runtime": "^7.6.2",
"@babel/preset-env": "^7.7.1",
"autoprefixer": "^9.7.2",
"@babel/core": "^7.7.5",
"@babel/plugin-transform-runtime": "^7.7.6",
"@babel/preset-env": "^7.7.6",
"autoprefixer": "^9.7.3",
"babel-eslint": "^10.0.3",
"babel-loader": "^8.0.6",
"babel-plugin-dynamic-import-node": "^2.3.0",
"chromedriver": "^78.0.1",
"colors": "^1.4.0",
"copy-webpack-plugin": "^5.0.5",
"css-loader": "^3.2.0",
"eslint": "^6.6.0",
"css-loader": "^3.2.1",
"eslint": "^6.7.2",
"exports-loader": "^0.7.0",
"file-loader": "^4.2.0",
"file-loader": "^5.0.2",
"grunt": "^1.0.4",
"grunt-accessibility": "~6.0.0",
"grunt-chmod": "~1.1.1",
@ -65,17 +65,17 @@
"html-webpack-plugin": "^3.2.0",
"imports-loader": "^0.8.0",
"mini-css-extract-plugin": "^0.8.0",
"nightwatch": "^1.2.4",
"nightwatch": "^1.3.2",
"node-sass": "^4.13.0",
"postcss-css-variables": "^0.13.0",
"postcss-css-variables": "^0.14.0",
"postcss-import": "^12.0.1",
"postcss-loader": "^3.0.0",
"prompt": "^1.0.0",
"sass-loader": "^8.0.0",
"sitemap": "^5.1.0",
"style-loader": "^1.0.0",
"svg-url-loader": "^3.0.2",
"url-loader": "^2.2.0",
"style-loader": "^1.0.1",
"svg-url-loader": "^3.0.3",
"url-loader": "^3.0.0",
"webpack": "^4.41.2",
"webpack-bundle-analyzer": "^3.6.0",
"webpack-dev-server": "^3.9.0",
@ -84,20 +84,20 @@
},
"dependencies": {
"@babel/polyfill": "^7.7.0",
"@babel/runtime": "^7.7.2",
"@babel/runtime": "^7.7.6",
"arrive": "^2.4.1",
"avsc": "^5.4.16",
"babel-plugin-transform-builtin-extend": "1.1.2",
"bcryptjs": "^2.4.3",
"bignumber.js": "^9.0.0",
"blakejs": "^1.1.0",
"bootstrap": "4.3.1",
"bootstrap-colorpicker": "^3.1.2",
"bootstrap": "4.4.1",
"bootstrap-colorpicker": "^3.2.0",
"bootstrap-material-design": "^4.1.2",
"bson": "^4.0.2",
"chi-squared": "^1.1.0",
"codepage": "^1.14.0",
"core-js": "^3.4.1",
"core-js": "^3.4.8",
"crypto-api": "^0.8.5",
"crypto-js": "^3.1.9-1",
"ctph.js": "0.0.5",
@ -113,7 +113,7 @@
"file-saver": "^2.0.2",
"geodesy": "^1.1.3",
"highlight.js": "^9.16.2",
"jimp": "^0.8.5",
"jimp": "^0.9.3",
"jquery": "3.4.1",
"js-crc": "^0.2.0",
"js-sha3": "^0.8.0",

View File

@ -73,10 +73,10 @@ class Chef {
// The threshold is specified in KiB.
const threshold = (options.ioDisplayThreshold || 1024) * 1024;
const returnType =
this.dish.size > threshold ?
Dish.ARRAY_BUFFER :
this.dish.type === Dish.HTML ?
Dish.HTML :
this.dish.type === Dish.HTML ?
Dish.HTML :
this.dish.size > threshold ?
Dish.ARRAY_BUFFER :
Dish.STRING;
return {

View File

@ -591,6 +591,44 @@ class Utils {
return utf8 ? Utils.byteArrayToUtf8(arr) : Utils.byteArrayToChars(arr);
}
/**
* Calculates the Shannon entropy for a given set of data.
*
* @param {Uint8Array|ArrayBuffer} input
* @returns {number}
*/
static calculateShannonEntropy(data) {
if (data instanceof ArrayBuffer) {
data = new Uint8Array(data);
}
const prob = [],
occurrences = new Array(256).fill(0);
// Count occurrences of each byte in the input
let i;
for (i = 0; i < data.length; i++) {
occurrences[data[i]]++;
}
// Store probability list
for (i = 0; i < occurrences.length; i++) {
if (occurrences[i] > 0) {
prob.push(occurrences[i] / data.length);
}
}
// Calculate Shannon entropy
let entropy = 0,
p;
for (i = 0; i < prob.length; i++) {
p = prob[i];
entropy += p * Math.log(p) / Math.log(2);
}
return -entropy;
}
/**
* Parses CSV data and returns it as a two dimensional array or strings.

View File

@ -197,6 +197,7 @@ class Manager {
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("#output-file-download", "click", this.output.downloadFile, this.output);
this.addDynamicListener("#output-file-show-all", "click", this.output.showAllFile, this.output);
this.addDynamicListener("#output-file-slice i", "click", this.output.displayFileSlice, this.output);
document.getElementById("show-file-overlay").addEventListener("click", this.output.showFileOverlayClick.bind(this.output));
this.addDynamicListener(".extract-file,.extract-file i", "click", this.output.extractFileClick, this.output);

View File

@ -29,7 +29,7 @@
<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') %>" />
<link rel="icon" type="image/ico" href="<%- require('../static/images/favicon.ico').default %>" />
<script type="application/javascript">
"use strict";
@ -197,7 +197,7 @@
</button>
<button type="button" class="mx-2 btn btn-lg btn-success btn-raised btn-block" id="bake">
<img aria-hidden="true" src="<%- require('../static/images/cook_male-32x32.png') %>" alt="Chef Icon"/>
<img aria-hidden="true" src="<%- require('../static/images/cook_male-32x32.png').default %>" alt="Chef Icon"/>
<span>Bake!</span>
</button>
@ -271,7 +271,7 @@
<div class="file-overlay" id="file-overlay"></div>
<div style="position: relative; height: 100%;">
<div class="io-card card">
<img aria-hidden="true" src="<%- require('../static/images/file-128x128.png') %>" alt="File icon" id="input-file-thumbnail"/>
<img aria-hidden="true" src="<%- require('../static/images/file-128x128.png').default %>" alt="File icon" id="input-file-thumbnail"/>
<div class="card-body">
<button type="button" class="close" id="input-file-close">&times;</button>
Name: <span id="input-file-name"></span><br>
@ -346,24 +346,26 @@
<div id="output-highlighter" class="no-select"></div>
<div id="output-html"></div>
<textarea id="output-text" readonly="readonly" spellcheck="false"></textarea>
<img id="show-file-overlay" aria-hidden="true" src="<%- require('../static/images/file-32x32.png') %>" alt="Show file overlay" title="Show file overlay"/>
<img id="show-file-overlay" aria-hidden="true" src="<%- require('../static/images/file-32x32.png').default %>" alt="Show file overlay" title="Show file overlay"/>
<div id="output-file">
<div class="file-overlay"></div>
<div style="position: relative; height: 100%;">
<div class="io-card card">
<img aria-hidden="true" src="<%- require('../static/images/file-128x128.png') %>" alt="File icon"/>
<img aria-hidden="true" src="<%- require('../static/images/file-128x128.png').default %>" alt="File icon"/>
<div class="card-body">
Size: <span id="output-file-size"></span><br>
<button id="output-file-download" type="button" class="btn btn-primary btn-outline">Download</button>
<button id="output-file-show-all" type="button" class="btn btn-warning btn-outline" data-toggle="tooltip" title="Warning: This could crash your browser. Use at your own risk.">Show all</button>
<div class="input-group">
<span class="input-group-btn">
<button id="output-file-slice" type="button" class="btn btn-secondary bmd-btn-icon" title="View slice">
<span class="input-group-prepend">
<button id="output-file-slice" type="button" class="btn btn-secondary bmd-btn-icon" data-toggle="tooltip" title="View slice">
<i class="material-icons">search</i>
</button>
</span>
<input type="number" class="form-control" id="output-file-slice-from" placeholder="From" value="0" step="1024" min="0">
<input type="number" class="form-control" id="output-file-slice-from" placeholder="From" value="0" step="128" min="0">
<div class="input-group-addon">to</div>
<input type="number" class="form-control" id="output-file-slice-to" placeholder="To" value="2048" step="1024" min="0">
<input type="number" class="form-control" id="output-file-slice-to" placeholder="To" value="256" step="128" min="0">
<div class="input-group-addon">KiB</div>
</div>
</div>
</div>
@ -489,6 +491,15 @@
</select>
</div>
<div class="form-group option-item">
<label for="preserveCR" class="bmd-label-floating"> Preserve carriage returns (0x0d)</label>
<select class="form-control" option="preserveCR" id="preserveCR" data-toggle="tooltip" data-placement="bottom" data-offset="-10%" data-html="true" title="HTML textareas don't support carriage returns, so if we want to preserve them in our input, we have to disable editing.<br><br>The default option is to only do this for high-entropy inputs, but you can force the choice using this dropdown.">
<option value="entropy">For high-entropy inputs</option>
<option value="always">Always</option>
<option value="never">Never</option>
</select>
</div>
<div class="form-group option-item">
<label for="errorTimeout" class="bmd-label-floating">Operation error timeout in ms (0 for never)</label>
<input type="number" class="form-control" option="errorTimeout" id="errorTimeout">
@ -573,13 +584,6 @@
Keep the current tab in sync between the input and output
</label>
</div>
<div class="checkbox option-item">
<label for="preserveCR" data-toggle="tooltip" data-placement="right" data-html="true" title="As HTML textareas don't support carriage returns, editing input must be turned off to preserve them.<br><br>When this option is enabled, editing is disabled for pasted text that contains carriage returns. Otherwise, editing will remain enabled but carriage returns will not be preserved.">
<input type="checkbox" option="preserveCR" id="preserveCR">
Preserve carriage returns when pasting an input
</label>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" id="reset-options">Reset options to default</button>
@ -622,7 +626,7 @@
<h5 class="modal-title">CyberChef - The Cyber Swiss Army Knife</h5>
</div>
<div class="modal-body">
<img aria-hidden="true" class="about-img-left" src="<%- require('../static/images/cyberchef-128x128.png') %>" alt="CyberChef Logo"/>
<img aria-hidden="true" class="about-img-left" src="<%- require('../static/images/cyberchef-128x128.png').default %>" alt="CyberChef Logo"/>
<p class="subtext">
Version <%= htmlWebpackPlugin.options.version %><br>
Compile time: <%= htmlWebpackPlugin.options.compileTime %>
@ -745,7 +749,7 @@
<button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
</div>
<a href="https://github.com/gchq/CyberChef">
<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">
<img aria-hidden="true" style="position: absolute; top: 0; right: 0; border: 0;" src="<%- require('../static/images/fork_me.png').default %>" alt="Fork me on GitHub">
</a>
</div>
</div>

View File

@ -49,13 +49,12 @@ function main() {
attemptHighlight: true,
theme: "classic",
useMetaKey: false,
ioDisplayThreshold: 512,
ioDisplayThreshold: 2048,
logLevel: "info",
autoMagic: true,
imagePreview: true,
syncTabs: true,
preserveCR: true,
userSetCR: false
preserveCR: "entropy"
};
document.removeEventListener("DOMContentLoaded", main, false);

View File

@ -98,6 +98,11 @@
.io-card.card input[type=number] {
padding-right: 6px;
padding-left: 6px;
height: unset;
}
.io-card.card .input-group {
padding-top: 5px;
}
#files .card-header .float-right a:hover {

View File

@ -476,7 +476,7 @@ class InputWaiter {
*/
resetFileThumb() {
const fileThumb = document.getElementById("input-file-thumbnail");
fileThumb.src = require("../static/images/file-128x128.png");
fileThumb.src = require("../static/images/file-128x128.png").default;
}
/**
@ -767,7 +767,9 @@ class InputWaiter {
// and manually fire inputChange()
inputText.value = val;
inputText.setSelectionRange(selStart + pastedData.length, selStart + pastedData.length);
this.debounceInputChange(e);
// Don't debounce here otherwise the keyup event for the Ctrl key will cancel an autobake
// (at least for large inputs)
this.inputChange(e, true);
}
}
@ -858,31 +860,29 @@ class InputWaiter {
if (input.indexOf("\r") < 0) return false;
const optionsStr = "This behaviour can be changed in the <a href='#' onclick='document.getElementById(\"options\").click()'>Options pane</a>";
if (!this.app.options.userSetCR) {
// User has not set a CR preference yet
let preserve = await new Promise(function(resolve, reject) {
this.app.confirm(
"Carriage Return Detected",
"A <a href='https://wikipedia.org/wiki/Carriage_return'>carriage return</a> (<code>\\r</code>, <code>0x0d</code>) was detected in your input. As HTML textareas <a href='https://html.spec.whatwg.org/multipage/form-elements.html#the-textarea-element'>can't display carriage returns</a>, editing must be turned off to preserve them. <br>Alternatively, you can enable editing but your carriage returns will not be preserved.<br><br>This preference will be saved but can be toggled in the options pane.",
"Preserve Carriage Returns",
"Enable Editing", resolve, this);
}.bind(this));
if (preserve === undefined) {
// The confirm pane was closed without picking a specific choice
this.app.alert(`Not preserving carriage returns.\n${optionsStr}`, 5000);
preserve = false;
}
this.manager.options.updateOption("preserveCR", preserve);
this.manager.options.updateOption("userSetCR", true);
} else {
if (this.app.options.preserveCR) {
this.app.alert(`A carriage return (\\r, 0x0d) was detected in your input, so editing has been disabled to preserve it.<br>${optionsStr}`, 10000);
} else {
this.app.alert(`A carriage return (\\r, 0x0d) was detected in your input. Editing is remaining enabled, but carriage returns will not be preserved.<br>${optionsStr}`, 10000);
}
const preserveStr = `A carriage return (\\r, 0x0d) was detected in your input. To preserve it, editing has been disabled.<br>${optionsStr}`;
const dontPreserveStr = `A carriage return (\\r, 0x0d) was detected in your input. It has not been preserved.<br>${optionsStr}`;
switch (this.app.options.preserveCR) {
case "always":
this.app.alert(preserveStr, 6000);
return true;
case "never":
this.app.alert(dontPreserveStr, 6000);
return false;
}
return this.app.options.preserveCR;
// Only preserve for high-entropy inputs
const data = Utils.strToArrayBuffer(input);
const entropy = Utils.calculateShannonEntropy(data);
if (entropy > 6) {
this.app.alert(preserveStr, 6000);
return true;
}
this.app.alert(dontPreserveStr, 6000);
return false;
}
/**

View File

@ -1122,8 +1122,8 @@ class OutputWaiter {
showFileOverlay = document.getElementById("show-file-overlay"),
sliceFromEl = document.getElementById("output-file-slice-from"),
sliceToEl = document.getElementById("output-file-slice-to"),
sliceFrom = parseInt(sliceFromEl.value, 10),
sliceTo = parseInt(sliceToEl.value, 10),
sliceFrom = parseInt(sliceFromEl.value, 10) * 1024,
sliceTo = parseInt(sliceToEl.value, 10) * 1024,
output = this.outputs[this.manager.tabs.getActiveOutputTab()].data;
let str;
@ -1137,6 +1137,39 @@ class OutputWaiter {
showFileOverlay.style.display = "block";
outputText.value = Utils.printable(str, true);
outputText.style.display = "block";
outputHtml.style.display = "none";
outputFile.style.display = "none";
outputHighlighter.display = "block";
inputHighlighter.display = "block";
this.toggleLoader(false);
}
/**
* Handler for showing an entire file at user's discretion (even if it's way too big)
*/
async showAllFile() {
document.querySelector("#output-loader .loading-msg").textContent = "Loading entire file at user instruction. This may cause a crash...";
this.toggleLoader(true);
const outputText = document.getElementById("output-text"),
outputHtml = document.getElementById("output-html"),
outputFile = document.getElementById("output-file"),
outputHighlighter = document.getElementById("output-highlighter"),
inputHighlighter = document.getElementById("input-highlighter"),
showFileOverlay = document.getElementById("show-file-overlay"),
output = this.outputs[this.manager.tabs.getActiveOutputTab()].data;
let str;
if (output.type === "ArrayBuffer") {
str = Utils.arrayBufferToStr(output.result);
} else {
str = Utils.arrayBufferToStr(await this.getDishBuffer(output.dish));
}
outputText.classList.remove("blur");
showFileOverlay.style.display = "none";
outputText.value = Utils.printable(str, true);
outputText.style.display = "block";
outputHtml.style.display = "none";