mirror of
https://github.com/gchq/CyberChef.git
synced 2025-06-17 03:35:07 -04:00
Files are now uploaded in a worker and not displayed in the input by default. Added ArrayBuffer Dish type.
This commit is contained in:
parent
021cae1a95
commit
4e00ac9300
8 changed files with 232 additions and 67 deletions
|
@ -1,4 +1,5 @@
|
|||
import Utils from "../core/Utils.js";
|
||||
import LoaderWorker from "worker-loader?inline&fallback=false!./LoaderWorker.js";
|
||||
|
||||
|
||||
/**
|
||||
|
@ -33,6 +34,9 @@ const InputWaiter = function(app, manager) {
|
|||
144, //Num
|
||||
145, //Scroll
|
||||
];
|
||||
|
||||
this.loaderWorker = null;
|
||||
this.fileBuffer = null;
|
||||
};
|
||||
|
||||
|
||||
|
@ -42,23 +46,49 @@ const InputWaiter = function(app, manager) {
|
|||
* @returns {string}
|
||||
*/
|
||||
InputWaiter.prototype.get = function() {
|
||||
return document.getElementById("input-text").value;
|
||||
return this.fileBuffer || document.getElementById("input-text").value;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Sets the input in the input textarea.
|
||||
* Sets the input in the input area.
|
||||
*
|
||||
* @param {string} input
|
||||
* @param {string|File} input
|
||||
*
|
||||
* @fires Manager#statechange
|
||||
*/
|
||||
InputWaiter.prototype.set = function(input) {
|
||||
if (input instanceof File) {
|
||||
this.setFile(input);
|
||||
input = "";
|
||||
}
|
||||
|
||||
document.getElementById("input-text").value = input;
|
||||
window.dispatchEvent(this.manager.statechange);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Shows file details.
|
||||
*
|
||||
* @param {File} file
|
||||
*/
|
||||
InputWaiter.prototype.setFile = function(file) {
|
||||
// Display file overlay in input area with details
|
||||
const fileOverlay = document.getElementById("input-file"),
|
||||
fileName = document.getElementById("input-file-name"),
|
||||
fileSize = document.getElementById("input-file-size"),
|
||||
fileType = document.getElementById("input-file-type"),
|
||||
fileUploaded = document.getElementById("input-file-uploaded");
|
||||
|
||||
fileOverlay.style.display = "block";
|
||||
fileName.textContent = file.name;
|
||||
fileSize.textContent = file.size.toLocaleString() + " bytes";
|
||||
fileType.textContent = file.type;
|
||||
fileUploaded.textContent = "0%";
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Displays information about the input.
|
||||
*
|
||||
|
@ -118,7 +148,7 @@ InputWaiter.prototype.inputDragover = function(e) {
|
|||
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
e.target.classList.add("dropping-file");
|
||||
e.target.closest("#input-text,#input-file").classList.add("dropping-file");
|
||||
};
|
||||
|
||||
|
||||
|
@ -131,7 +161,8 @@ InputWaiter.prototype.inputDragover = function(e) {
|
|||
InputWaiter.prototype.inputDragleave = function(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
e.target.classList.remove("dropping-file");
|
||||
document.getElementById("input-text").classList.remove("dropping-file");
|
||||
document.getElementById("input-file").classList.remove("dropping-file");
|
||||
};
|
||||
|
||||
|
||||
|
@ -149,55 +180,57 @@ InputWaiter.prototype.inputDrop = function(e) {
|
|||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
|
||||
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
|
||||
|
||||
const setInput = function() {
|
||||
const recipeConfig = this.app.getRecipeConfig();
|
||||
if (!recipeConfig[0] || recipeConfig[0].op !== "From Hex") {
|
||||
recipeConfig.unshift({op: "From Hex", args: ["Space"]});
|
||||
this.app.setRecipeConfig(recipeConfig);
|
||||
}
|
||||
document.getElementById("input-text").classList.remove("dropping-file");
|
||||
document.getElementById("input-file").classList.remove("dropping-file");
|
||||
|
||||
this.set(inputCharcode);
|
||||
|
||||
el.classList.remove("loadingFile");
|
||||
}.bind(this);
|
||||
|
||||
const seek = function() {
|
||||
if (offset >= file.size) {
|
||||
setInput();
|
||||
return;
|
||||
}
|
||||
el.value = "Processing... " + Math.round(offset / file.size * 100) + "%";
|
||||
const slice = file.slice(offset, offset + CHUNK_SIZE);
|
||||
reader.readAsArrayBuffer(slice);
|
||||
};
|
||||
|
||||
reader.onload = function(e) {
|
||||
const data = new Uint8Array(reader.result);
|
||||
inputCharcode += Utils.toHexFast(data);
|
||||
offset += CHUNK_SIZE;
|
||||
seek();
|
||||
};
|
||||
|
||||
|
||||
el.classList.remove("dropping-file");
|
||||
if (text) {
|
||||
this.closeFile();
|
||||
this.set(text);
|
||||
return;
|
||||
}
|
||||
|
||||
if (file) {
|
||||
el.classList.add("loadingFile");
|
||||
seek();
|
||||
} else if (text) {
|
||||
this.set(text);
|
||||
this.closeFile();
|
||||
this.loaderWorker = new LoaderWorker();
|
||||
this.loaderWorker.addEventListener("message", this.handleLoaderMessage.bind(this));
|
||||
this.loaderWorker.postMessage({"file": file});
|
||||
this.set(file);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handler for messages sent back by the LoaderWorker.
|
||||
*
|
||||
* @param {MessageEvent} e
|
||||
*/
|
||||
InputWaiter.prototype.handleLoaderMessage = function(e) {
|
||||
const r = e.data;
|
||||
if (r.hasOwnProperty("progress")) {
|
||||
const fileUploaded = document.getElementById("input-file-uploaded");
|
||||
fileUploaded.textContent = r.progress + "%";
|
||||
}
|
||||
|
||||
if (r.hasOwnProperty("fileBuffer")) {
|
||||
this.fileBuffer = r.fileBuffer;
|
||||
window.dispatchEvent(this.manager.statechange);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handler for file close events.
|
||||
*/
|
||||
InputWaiter.prototype.closeFile = function() {
|
||||
if (this.loaderWorker) this.loaderWorker.terminate();
|
||||
this.fileBuffer = null;
|
||||
document.getElementById("input-file").style.display = "none";
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Handler for clear IO events.
|
||||
* Resets the input, output and info areas.
|
||||
|
@ -205,6 +238,7 @@ InputWaiter.prototype.inputDrop = function(e) {
|
|||
* @fires Manager#statechange
|
||||
*/
|
||||
InputWaiter.prototype.clearIoClick = function() {
|
||||
this.closeFile();
|
||||
this.manager.highlighter.removeHighlights();
|
||||
document.getElementById("input-text").value = "";
|
||||
document.getElementById("output-text").value = "";
|
||||
|
|
50
src/web/LoaderWorker.js
Normal file
50
src/web/LoaderWorker.js
Normal file
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
* Web Worker to load large amounts of data without locking up the UI.
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Respond to message from parent thread.
|
||||
*/
|
||||
self.addEventListener("message", function(e) {
|
||||
const r = e.data;
|
||||
if (r.hasOwnProperty("file")) {
|
||||
self.loadFile(r.file);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* Loads a file object into an ArrayBuffer, then transfers it back to the parent thread.
|
||||
*
|
||||
* @param {File} file
|
||||
*/
|
||||
self.loadFile = function(file) {
|
||||
const reader = new FileReader();
|
||||
let data = new Uint8Array(file.size);
|
||||
let offset = 0;
|
||||
const CHUNK_SIZE = 10485760; // 10MiB
|
||||
|
||||
const seek = function() {
|
||||
if (offset >= file.size) {
|
||||
self.postMessage({"progress": 100});
|
||||
self.postMessage({"fileBuffer": data.buffer}, [data.buffer]);
|
||||
return;
|
||||
}
|
||||
self.postMessage({"progress": Math.round(offset / file.size * 100)});
|
||||
const slice = file.slice(offset, offset + CHUNK_SIZE);
|
||||
reader.readAsArrayBuffer(slice);
|
||||
};
|
||||
|
||||
reader.onload = function(e) {
|
||||
data.set(new Uint8Array(reader.result), offset);
|
||||
offset += CHUNK_SIZE;
|
||||
seek();
|
||||
};
|
||||
|
||||
seek();
|
||||
};
|
|
@ -135,13 +135,14 @@ Manager.prototype.initialiseEventListeners = function() {
|
|||
this.addMultiEventListener("#input-text", "keyup paste", this.input.inputChange, this.input);
|
||||
document.getElementById("reset-layout").addEventListener("click", this.app.resetLayout.bind(this.app));
|
||||
document.getElementById("clr-io").addEventListener("click", this.input.clearIoClick.bind(this.input));
|
||||
document.getElementById("input-text").addEventListener("dragover", this.input.inputDragover.bind(this.input));
|
||||
document.getElementById("input-text").addEventListener("dragleave", this.input.inputDragleave.bind(this.input));
|
||||
document.getElementById("input-text").addEventListener("drop", this.input.inputDrop.bind(this.input));
|
||||
this.addListeners("#input-text,#input-file", "dragover", this.input.inputDragover, this.input);
|
||||
this.addListeners("#input-text,#input-file", "dragleave", this.input.inputDragleave, this.input);
|
||||
this.addListeners("#input-text,#input-file", "drop", this.input.inputDrop, this.input);
|
||||
document.getElementById("input-text").addEventListener("scroll", this.highlighter.inputScroll.bind(this.highlighter));
|
||||
document.getElementById("input-text").addEventListener("mouseup", this.highlighter.inputMouseup.bind(this.highlighter));
|
||||
document.getElementById("input-text").addEventListener("mousemove", this.highlighter.inputMousemove.bind(this.highlighter));
|
||||
this.addMultiEventListener("#input-text", "mousedown dblclick select", this.highlighter.inputMousedown, this.highlighter);
|
||||
document.querySelector("#input-file .close").addEventListener("click", this.input.closeFile.bind(this.input));
|
||||
|
||||
// Output
|
||||
document.getElementById("save-to-file").addEventListener("click", this.output.saveClick.bind(this.output));
|
||||
|
|
|
@ -181,6 +181,20 @@
|
|||
<div class="textarea-wrapper no-select">
|
||||
<div id="input-highlighter" class="no-select"></div>
|
||||
<textarea id="input-text"></textarea>
|
||||
<div id="input-file">
|
||||
<div style="position: relative; height: 100%;">
|
||||
<div class="card">
|
||||
<img aria-hidden="true" src="<%- require('../static/images/cyberchef-256x256.png') %>" alt="File icon"/>
|
||||
<div class="card-body">
|
||||
<button type="button" class="close" id="input-file-close">×</button>
|
||||
Name: <span id="input-file-name"></span><br>
|
||||
Size: <span id="input-file-size"></span><br>
|
||||
Type: <span id="input-file-type"></span><br>
|
||||
Uploaded: <span id="input-file-uploaded"></span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -28,3 +28,44 @@
|
|||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.card {
|
||||
box-shadow: 0 4px 8px 0 rgba(0,0,0,0.2);
|
||||
transition: 0.3s;
|
||||
width: 400px;
|
||||
height: 150px;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-family: var(--primary-font-family);
|
||||
color: var(--primary-font-colour);
|
||||
line-height: 30px;
|
||||
background-color: var(--primary-background-colour);
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
box-shadow: 0 8px 16px 0 rgba(0,0,0,0.2);
|
||||
}
|
||||
|
||||
.card>img {
|
||||
float: left;
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
}
|
||||
|
||||
.card-body .close {
|
||||
position: absolute;
|
||||
right: 10px;
|
||||
top: 10px;
|
||||
}
|
||||
|
||||
.card-body {
|
||||
float: left;
|
||||
padding: 16px;
|
||||
width: 250px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
user-select: text;
|
||||
}
|
|
@ -39,7 +39,7 @@
|
|||
}
|
||||
|
||||
.textarea-wrapper textarea,
|
||||
.textarea-wrapper div {
|
||||
.textarea-wrapper>div {
|
||||
font-family: var(--fixed-width-font-family);
|
||||
font-size: var(--fixed-width-font-size);
|
||||
color: var(--fixed-width-font-colour);
|
||||
|
@ -77,6 +77,16 @@
|
|||
transition: all 0.5s ease;
|
||||
}
|
||||
|
||||
#input-file {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: var(--title-background-colour);
|
||||
display: none;
|
||||
}
|
||||
|
||||
.io-btn-group {
|
||||
float: right;
|
||||
margin-top: -4px;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue