ESM: Ported MS and Entropy operations
parent
ebcc5bd9c8
commit
84df055888
|
@ -60,6 +60,12 @@ class Chef {
|
|||
recipe.setBreakpoint(progress + 1, true);
|
||||
}
|
||||
|
||||
// If the previously run operation presented a different value to its
|
||||
// normal output, we need to recalculate it.
|
||||
if (recipe.lastOpPresented(progress)) {
|
||||
progress = 0;
|
||||
}
|
||||
|
||||
// If stepping with flow control, we have to start from the beginning
|
||||
// but still want to skip all previous breakpoints
|
||||
if (progress > 0 && containsFc) {
|
||||
|
|
|
@ -81,9 +81,10 @@ class Operation {
|
|||
* this behaviour.
|
||||
*
|
||||
* @param {*} data - The result of the run() function
|
||||
* @param {Object[]} args - The operation's arguments
|
||||
* @returns {*} - A human-readable version of the data
|
||||
*/
|
||||
present(data) {
|
||||
present(data, args) {
|
||||
return data;
|
||||
}
|
||||
|
||||
|
|
|
@ -212,7 +212,10 @@ class Recipe {
|
|||
async present(dish) {
|
||||
if (!this.lastRunOp) return;
|
||||
|
||||
const output = await this.lastRunOp.present(await dish.get(this.lastRunOp.outputType));
|
||||
const output = await this.lastRunOp.present(
|
||||
await dish.get(this.lastRunOp.outputType),
|
||||
this.lastRunOp.ingValues
|
||||
);
|
||||
dish.set(output, this.lastRunOp.presentType);
|
||||
}
|
||||
|
||||
|
@ -270,6 +273,18 @@ class Recipe {
|
|||
return highlights;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Determines whether the previous operation has a different presentation type to its normal output.
|
||||
*
|
||||
* @param {number} progress
|
||||
* @returns {boolean}
|
||||
*/
|
||||
lastOpPresented(progress) {
|
||||
if (progress < 1) return false;
|
||||
return this.opList[progress-1].presentType !== this.opList[progress-1].outputType;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Recipe;
|
||||
|
|
|
@ -0,0 +1,204 @@
|
|||
/**
|
||||
* Various components for drawing diagrams on an HTML5 canvas.
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* Draws a line from one point to another
|
||||
*
|
||||
* @param ctx
|
||||
* @param startX
|
||||
* @param startY
|
||||
* @param endX
|
||||
* @param endY
|
||||
*/
|
||||
export function drawLine(ctx, startX, startY, endX, endY) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(startX, startY);
|
||||
ctx.lineTo(endX, endY);
|
||||
ctx.closePath();
|
||||
ctx.stroke();
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a bar chart on the canvas.
|
||||
*
|
||||
* @param canvas
|
||||
* @param scores
|
||||
* @param xAxisLabel
|
||||
* @param yAxisLabel
|
||||
* @param numXLabels
|
||||
* @param numYLabels
|
||||
* @param fontSize
|
||||
*/
|
||||
export function drawBarChart(canvas, scores, xAxisLabel, yAxisLabel, numXLabels, numYLabels, fontSize) {
|
||||
fontSize = fontSize || 15;
|
||||
if (!numXLabels || numXLabels > Math.round(canvas.width / 50)) {
|
||||
numXLabels = Math.round(canvas.width / 50);
|
||||
}
|
||||
if (!numYLabels || numYLabels > Math.round(canvas.width / 50)) {
|
||||
numYLabels = Math.round(canvas.height / 50);
|
||||
}
|
||||
|
||||
// Graph properties
|
||||
const ctx = canvas.getContext("2d"),
|
||||
leftPadding = canvas.width * 0.08,
|
||||
rightPadding = canvas.width * 0.03,
|
||||
topPadding = canvas.height * 0.08,
|
||||
bottomPadding = canvas.height * 0.15,
|
||||
graphHeight = canvas.height - topPadding - bottomPadding,
|
||||
graphWidth = canvas.width - leftPadding - rightPadding,
|
||||
base = topPadding + graphHeight,
|
||||
ceil = topPadding;
|
||||
|
||||
ctx.font = fontSize + "px Arial";
|
||||
|
||||
// Draw axis
|
||||
ctx.lineWidth = "1.0";
|
||||
ctx.strokeStyle = "#444";
|
||||
drawLine(ctx, leftPadding, base, graphWidth + leftPadding, base); // x
|
||||
drawLine(ctx, leftPadding, base, leftPadding, ceil); // y
|
||||
|
||||
// Bar properties
|
||||
const barPadding = graphWidth * 0.003,
|
||||
barWidth = (graphWidth - (barPadding * scores.length)) / scores.length,
|
||||
max = Math.max.apply(Math, scores);
|
||||
let currX = leftPadding + barPadding;
|
||||
|
||||
// Draw bars
|
||||
ctx.fillStyle = "green";
|
||||
for (let i = 0; i < scores.length; i++) {
|
||||
const h = scores[i] / max * graphHeight;
|
||||
ctx.fillRect(currX, base - h, barWidth, h);
|
||||
currX += barWidth + barPadding;
|
||||
}
|
||||
|
||||
// Mark x axis
|
||||
ctx.fillStyle = "black";
|
||||
ctx.textAlign = "center";
|
||||
currX = leftPadding + barPadding;
|
||||
if (numXLabels >= scores.length) {
|
||||
// Mark every score
|
||||
for (let i = 0; i <= scores.length; i++) {
|
||||
ctx.fillText(i, currX, base + (bottomPadding * 0.3));
|
||||
currX += barWidth + barPadding;
|
||||
}
|
||||
} else {
|
||||
// Mark some scores
|
||||
for (let i = 0; i <= numXLabels; i++) {
|
||||
const val = Math.ceil((scores.length / numXLabels) * i);
|
||||
currX = (graphWidth / numXLabels) * i + leftPadding;
|
||||
ctx.fillText(val, currX, base + (bottomPadding * 0.3));
|
||||
}
|
||||
}
|
||||
|
||||
// Mark y axis
|
||||
ctx.textAlign = "right";
|
||||
let currY;
|
||||
if (numYLabels >= max) {
|
||||
// Mark every increment
|
||||
for (let i = 0; i <= max; i++) {
|
||||
currY = base - (i / max * graphHeight) + fontSize / 3;
|
||||
ctx.fillText(i, leftPadding * 0.8, currY);
|
||||
}
|
||||
} else {
|
||||
// Mark some increments
|
||||
for (let i = 0; i <= numYLabels; i++) {
|
||||
const val = Math.ceil((max / numYLabels) * i);
|
||||
currY = base - (val / max * graphHeight) + fontSize / 3;
|
||||
ctx.fillText(val, leftPadding * 0.8, currY);
|
||||
}
|
||||
}
|
||||
|
||||
// Label x axis
|
||||
if (xAxisLabel) {
|
||||
ctx.textAlign = "center";
|
||||
ctx.fillText(xAxisLabel, graphWidth / 2 + leftPadding, base + bottomPadding * 0.8);
|
||||
}
|
||||
|
||||
// Label y axis
|
||||
if (yAxisLabel) {
|
||||
ctx.save();
|
||||
const x = leftPadding * 0.3,
|
||||
y = graphHeight / 2 + topPadding;
|
||||
ctx.translate(x, y);
|
||||
ctx.rotate(-Math.PI / 2);
|
||||
ctx.textAlign = "center";
|
||||
ctx.fillText(yAxisLabel, 0, 0);
|
||||
ctx.restore();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Draws a scale bar on the canvas.
|
||||
*
|
||||
* @param canvas
|
||||
* @param score
|
||||
* @param max
|
||||
* @param markings
|
||||
*/
|
||||
export function drawScaleBar(canvas, score, max, markings) {
|
||||
// Bar properties
|
||||
const ctx = canvas.getContext("2d"),
|
||||
leftPadding = canvas.width * 0.01,
|
||||
rightPadding = canvas.width * 0.01,
|
||||
topPadding = canvas.height * 0.1,
|
||||
bottomPadding = canvas.height * 0.3,
|
||||
barHeight = canvas.height - topPadding - bottomPadding,
|
||||
barWidth = canvas.width - leftPadding - rightPadding;
|
||||
|
||||
// Scale properties
|
||||
const proportion = score / max;
|
||||
|
||||
// Draw bar outline
|
||||
ctx.strokeRect(leftPadding, topPadding, barWidth, barHeight);
|
||||
|
||||
// Shade in up to proportion
|
||||
const grad = ctx.createLinearGradient(leftPadding, 0, barWidth + leftPadding, 0);
|
||||
grad.addColorStop(0, "green");
|
||||
grad.addColorStop(0.5, "gold");
|
||||
grad.addColorStop(1, "red");
|
||||
ctx.fillStyle = grad;
|
||||
ctx.fillRect(leftPadding, topPadding, barWidth * proportion, barHeight);
|
||||
|
||||
// Add markings
|
||||
let x0, y0, x1, y1;
|
||||
ctx.fillStyle = "black";
|
||||
ctx.textAlign = "center";
|
||||
ctx.font = "13px Arial";
|
||||
for (let i = 0; i < markings.length; i++) {
|
||||
// Draw min line down
|
||||
x0 = barWidth / max * markings[i].min + leftPadding;
|
||||
y0 = topPadding + barHeight + (bottomPadding * 0.1);
|
||||
x1 = x0;
|
||||
y1 = topPadding + barHeight + (bottomPadding * 0.3);
|
||||
drawLine(ctx, x0, y0, x1, y1);
|
||||
|
||||
// Draw max line down
|
||||
x0 = barWidth / max * markings[i].max + leftPadding;
|
||||
x1 = x0;
|
||||
drawLine(ctx, x0, y0, x1, y1);
|
||||
|
||||
// Join min and max lines
|
||||
x0 = barWidth / max * markings[i].min + leftPadding;
|
||||
y0 = topPadding + barHeight + (bottomPadding * 0.3);
|
||||
x1 = barWidth / max * markings[i].max + leftPadding;
|
||||
y1 = y0;
|
||||
drawLine(ctx, x0, y0, x1, y1);
|
||||
|
||||
// Add label
|
||||
if (markings[i].max >= max * 0.9) {
|
||||
ctx.textAlign = "right";
|
||||
x0 = x1;
|
||||
} else if (markings[i].max <= max * 0.1) {
|
||||
ctx.textAlign = "left";
|
||||
} else {
|
||||
x0 = x0 + (x1 - x0) / 2;
|
||||
}
|
||||
y0 = topPadding + barHeight + (bottomPadding * 0.8);
|
||||
ctx.fillText(markings[i].label, x0, y0);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
|
||||
/**
|
||||
* Chi Square operation
|
||||
*/
|
||||
class ChiSquare extends Operation {
|
||||
|
||||
/**
|
||||
* ChiSquare constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Chi Square";
|
||||
this.module = "Default";
|
||||
this.description = "Calculates the Chi Square distribution of values.";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "number";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {number}
|
||||
*/
|
||||
run(input, args) {
|
||||
const data = new Uint8Array(input);
|
||||
const distArray = new Array(256).fill(0);
|
||||
let total = 0;
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
distArray[data[i]]++;
|
||||
}
|
||||
|
||||
for (let i = 0; i < distArray.length; i++) {
|
||||
if (distArray[i] > 0) {
|
||||
total += Math.pow(distArray[i] - data.length / 256, 2) / (data.length / 256);
|
||||
}
|
||||
}
|
||||
|
||||
return total;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default ChiSquare;
|
|
@ -0,0 +1,96 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
|
||||
/**
|
||||
* Entropy operation
|
||||
*/
|
||||
class Entropy extends Operation {
|
||||
|
||||
/**
|
||||
* Entropy constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Entropy";
|
||||
this.module = "Default";
|
||||
this.description = "Calculates the Shannon entropy of the input data which gives an idea of its randomness. 8 is the maximum.";
|
||||
this.inputType = "byteArray";
|
||||
this.outputType = "number";
|
||||
this.presentType = "html";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {byteArray} input
|
||||
* @param {Object[]} args
|
||||
* @returns {number}
|
||||
*/
|
||||
run(input, args) {
|
||||
const prob = [],
|
||||
uniques = input.unique(),
|
||||
str = Utils.byteArrayToChars(input);
|
||||
let i;
|
||||
|
||||
for (i = 0; i < uniques.length; i++) {
|
||||
prob.push(str.count(Utils.chr(uniques[i])) / input.length);
|
||||
}
|
||||
|
||||
let entropy = 0,
|
||||
p;
|
||||
|
||||
for (i = 0; i < prob.length; i++) {
|
||||
p = prob[i];
|
||||
entropy += p * Math.log(p) / Math.log(2);
|
||||
}
|
||||
|
||||
return -entropy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the entropy as a scale bar for web apps.
|
||||
*
|
||||
* @param {number} entropy
|
||||
* @returns {html}
|
||||
*/
|
||||
present(entropy) {
|
||||
return `Shannon entropy: ${entropy}
|
||||
<br><canvas id='chart-area'></canvas><br>
|
||||
- 0 represents no randomness (i.e. all the bytes in the data have the same value) whereas 8, the maximum, represents a completely random string.
|
||||
- Standard English text usually falls somewhere between 3.5 and 5.
|
||||
- Properly encrypted or compressed data of a reasonable length should have an entropy of over 7.5.
|
||||
|
||||
The following results show the entropy of chunks of the input data. Chunks with particularly high entropy could suggest encrypted or compressed sections.
|
||||
|
||||
<br><script>
|
||||
var canvas = document.getElementById("chart-area"),
|
||||
parentRect = canvas.parentNode.getBoundingClientRect(),
|
||||
entropy = ${entropy},
|
||||
height = parentRect.height * 0.25;
|
||||
|
||||
canvas.width = parentRect.width * 0.95;
|
||||
canvas.height = height > 150 ? 150 : height;
|
||||
|
||||
CanvasComponents.drawScaleBar(canvas, entropy, 8, [
|
||||
{
|
||||
label: "English text",
|
||||
min: 3.5,
|
||||
max: 5
|
||||
},{
|
||||
label: "Encrypted/compressed",
|
||||
min: 7.5,
|
||||
max: 8
|
||||
}
|
||||
]);
|
||||
</script>`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default Entropy;
|
|
@ -0,0 +1,110 @@
|
|||
/**
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
import Utils from "../Utils";
|
||||
import OperationError from "../errors/OperationError";
|
||||
|
||||
/**
|
||||
* Frequency distribution operation
|
||||
*/
|
||||
class FrequencyDistribution extends Operation {
|
||||
|
||||
/**
|
||||
* FrequencyDistribution constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Frequency distribution";
|
||||
this.module = "Default";
|
||||
this.description = "Displays the distribution of bytes in the data as a graph.";
|
||||
this.inputType = "ArrayBuffer";
|
||||
this.outputType = "json";
|
||||
this.presentType = "html";
|
||||
this.args = [
|
||||
{
|
||||
"name": "Show 0%s",
|
||||
"type": "boolean",
|
||||
"value": "Entropy.FREQ_ZEROS"
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {ArrayBuffer} input
|
||||
* @param {Object[]} args
|
||||
* @returns {json}
|
||||
*/
|
||||
run(input, args) {
|
||||
const data = new Uint8Array(input);
|
||||
if (!data.length) throw new OperationError("No data");
|
||||
|
||||
const distrib = new Array(256).fill(0),
|
||||
percentages = new Array(256),
|
||||
len = data.length;
|
||||
let i;
|
||||
|
||||
// Count bytes
|
||||
for (i = 0; i < len; i++) {
|
||||
distrib[data[i]]++;
|
||||
}
|
||||
|
||||
// Calculate percentages
|
||||
let repr = 0;
|
||||
for (i = 0; i < 256; i++) {
|
||||
if (distrib[i] > 0) repr++;
|
||||
percentages[i] = distrib[i] / len * 100;
|
||||
}
|
||||
|
||||
return {
|
||||
"dataLength": len,
|
||||
"percentages": percentages,
|
||||
"distribution": distrib,
|
||||
"bytesRepresented": repr
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the frequency distribution as a bar chart for web apps.
|
||||
*
|
||||
* @param {json} freq
|
||||
* @returns {html}
|
||||
*/
|
||||
present(freq, args) {
|
||||
const showZeroes = args[0];
|
||||
// Print
|
||||
let output = `<canvas id='chart-area'></canvas><br>
|
||||
Total data length: ${freq.dataLength}
|
||||
Number of bytes represented: ${freq.bytesRepresented}
|
||||
Number of bytes not represented: ${256 - freq.bytesRepresented}
|
||||
|
||||
Byte Percentage
|
||||
<script>
|
||||
var canvas = document.getElementById("chart-area"),
|
||||
parentRect = canvas.parentNode.getBoundingClientRect(),
|
||||
scores = ${JSON.stringify(freq.percentages)};
|
||||
|
||||
canvas.width = parentRect.width * 0.95;
|
||||
canvas.height = parentRect.height * 0.9;
|
||||
|
||||
CanvasComponents.drawBarChart(canvas, scores, "Byte", "Frequency %", 16, 6);
|
||||
</script>`;
|
||||
|
||||
for (let i = 0; i < 256; i++) {
|
||||
if (freq.distribution[i] || showZeroes) {
|
||||
output += " " + Utils.hex(i, 2) + " (" +
|
||||
(freq.percentages[i].toFixed(2).replace(".00", "") + "%)").padEnd(8, " ") +
|
||||
Array(Math.ceil(freq.percentages[i])+1).join("|") + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default FrequencyDistribution;
|
|
@ -0,0 +1,217 @@
|
|||
/**
|
||||
* @author bmwhitn [brian.m.whitney@outlook.com]
|
||||
* @copyright Crown Copyright 2017
|
||||
* @license Apache-2.0
|
||||
*/
|
||||
|
||||
import Operation from "../Operation";
|
||||
|
||||
/**
|
||||
* Microsoft Script Decoder operation
|
||||
*/
|
||||
class MicrosoftScriptDecoder extends Operation {
|
||||
|
||||
/**
|
||||
* MicrosoftScriptDecoder constructor
|
||||
*/
|
||||
constructor() {
|
||||
super();
|
||||
|
||||
this.name = "Microsoft Script Decoder";
|
||||
this.module = "Default";
|
||||
this.description = "Decodes Microsoft Encoded Script files that have been encoded with Microsoft's custom encoding. These are often VBS (Visual Basic Script) files that are encoded and renamed with a '.vbe' extention or JS (JScript) files renamed with a '.jse' extention.<br><br><b>Sample</b><br><br>Encoded:<br><code>#@~^RQAAAA==-mD~sX|:/TP{~J:+dYbxL~@!F@*@!+@*@!&@*eEI@#@&@#@&.jm.raY 214Wv:zms/obI0xEAAA==^#~@</code><br><br>Decoded:<br><code>var my_msg = "Testing <1><2><3>!";\n\nVScript.Echo(my_msg);</code>";
|
||||
this.inputType = "string";
|
||||
this.outputType = "string";
|
||||
this.args = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} input
|
||||
* @param {Object[]} args
|
||||
* @returns {string}
|
||||
*/
|
||||
run(input, args) {
|
||||
const matcher = /#@~\^.{6}==(.+).{6}==\^#~@/;
|
||||
const encodedData = matcher.exec(input);
|
||||
if (encodedData){
|
||||
return MicrosoftScriptDecoder._decode(encodedData[1]);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes Microsoft Encoded Script files that can be read and executed by cscript.exe/wscript.exe.
|
||||
* This is a conversion of a Python script that was originally created by Didier Stevens
|
||||
* (https://DidierStevens.com).
|
||||
*
|
||||
* @private
|
||||
* @param {string} data
|
||||
* @returns {string}
|
||||
*/
|
||||
static _decode(data) {
|
||||
const result = [];
|
||||
let index = -1;
|
||||
data = data.replace(/@&/g, String.fromCharCode(10))
|
||||
.replace(/@#/g, String.fromCharCode(13))
|
||||
.replace(/@\*/g, ">")
|
||||
.replace(/@!/g, "<")
|
||||
.replace(/@\$/g, "@");
|
||||
|
||||
for (let i = 0; i < data.length; i++) {
|
||||
const byte = data.charCodeAt(i);
|
||||
let char = data.charAt(i);
|
||||
if (byte < 128) {
|
||||
index++;
|
||||
}
|
||||
|
||||
if ((byte === 9 || byte > 31 && byte < 128) &&
|
||||
byte !== 60 &&
|
||||
byte !== 62 &&
|
||||
byte !== 64) {
|
||||
char = D_DECODE[byte].charAt(D_COMBINATION[index % 64]);
|
||||
}
|
||||
result.push(char);
|
||||
}
|
||||
return result.join("");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const D_DECODE = [
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"\x57\x6E\x7B",
|
||||
"\x4A\x4C\x41",
|
||||
"\x0B\x0B\x0B",
|
||||
"\x0C\x0C\x0C",
|
||||
"\x4A\x4C\x41",
|
||||
"\x0E\x0E\x0E",
|
||||
"\x0F\x0F\x0F",
|
||||
"\x10\x10\x10",
|
||||
"\x11\x11\x11",
|
||||
"\x12\x12\x12",
|
||||
"\x13\x13\x13",
|
||||
"\x14\x14\x14",
|
||||
"\x15\x15\x15",
|
||||
"\x16\x16\x16",
|
||||
"\x17\x17\x17",
|
||||
"\x18\x18\x18",
|
||||
"\x19\x19\x19",
|
||||
"\x1A\x1A\x1A",
|
||||
"\x1B\x1B\x1B",
|
||||
"\x1C\x1C\x1C",
|
||||
"\x1D\x1D\x1D",
|
||||
"\x1E\x1E\x1E",
|
||||
"\x1F\x1F\x1F",
|
||||
"\x2E\x2D\x32",
|
||||
"\x47\x75\x30",
|
||||
"\x7A\x52\x21",
|
||||
"\x56\x60\x29",
|
||||
"\x42\x71\x5B",
|
||||
"\x6A\x5E\x38",
|
||||
"\x2F\x49\x33",
|
||||
"\x26\x5C\x3D",
|
||||
"\x49\x62\x58",
|
||||
"\x41\x7D\x3A",
|
||||
"\x34\x29\x35",
|
||||
"\x32\x36\x65",
|
||||
"\x5B\x20\x39",
|
||||
"\x76\x7C\x5C",
|
||||
"\x72\x7A\x56",
|
||||
"\x43\x7F\x73",
|
||||
"\x38\x6B\x66",
|
||||
"\x39\x63\x4E",
|
||||
"\x70\x33\x45",
|
||||
"\x45\x2B\x6B",
|
||||
"\x68\x68\x62",
|
||||
"\x71\x51\x59",
|
||||
"\x4F\x66\x78",
|
||||
"\x09\x76\x5E",
|
||||
"\x62\x31\x7D",
|
||||
"\x44\x64\x4A",
|
||||
"\x23\x54\x6D",
|
||||
"\x75\x43\x71",
|
||||
"\x4A\x4C\x41",
|
||||
"\x7E\x3A\x60",
|
||||
"\x4A\x4C\x41",
|
||||
"\x5E\x7E\x53",
|
||||
"\x40\x4C\x40",
|
||||
"\x77\x45\x42",
|
||||
"\x4A\x2C\x27",
|
||||
"\x61\x2A\x48",
|
||||
"\x5D\x74\x72",
|
||||
"\x22\x27\x75",
|
||||
"\x4B\x37\x31",
|
||||
"\x6F\x44\x37",
|
||||
"\x4E\x79\x4D",
|
||||
"\x3B\x59\x52",
|
||||
"\x4C\x2F\x22",
|
||||
"\x50\x6F\x54",
|
||||
"\x67\x26\x6A",
|
||||
"\x2A\x72\x47",
|
||||
"\x7D\x6A\x64",
|
||||
"\x74\x39\x2D",
|
||||
"\x54\x7B\x20",
|
||||
"\x2B\x3F\x7F",
|
||||
"\x2D\x38\x2E",
|
||||
"\x2C\x77\x4C",
|
||||
"\x30\x67\x5D",
|
||||
"\x6E\x53\x7E",
|
||||
"\x6B\x47\x6C",
|
||||
"\x66\x34\x6F",
|
||||
"\x35\x78\x79",
|
||||
"\x25\x5D\x74",
|
||||
"\x21\x30\x43",
|
||||
"\x64\x23\x26",
|
||||
"\x4D\x5A\x76",
|
||||
"\x52\x5B\x25",
|
||||
"\x63\x6C\x24",
|
||||
"\x3F\x48\x2B",
|
||||
"\x7B\x55\x28",
|
||||
"\x78\x70\x23",
|
||||
"\x29\x69\x41",
|
||||
"\x28\x2E\x34",
|
||||
"\x73\x4C\x09",
|
||||
"\x59\x21\x2A",
|
||||
"\x33\x24\x44",
|
||||
"\x7F\x4E\x3F",
|
||||
"\x6D\x50\x77",
|
||||
"\x55\x09\x3B",
|
||||
"\x53\x56\x55",
|
||||
"\x7C\x73\x69",
|
||||
"\x3A\x35\x61",
|
||||
"\x5F\x61\x63",
|
||||
"\x65\x4B\x50",
|
||||
"\x46\x58\x67",
|
||||
"\x58\x3B\x51",
|
||||
"\x31\x57\x49",
|
||||
"\x69\x22\x4F",
|
||||
"\x6C\x6D\x46",
|
||||
"\x5A\x4D\x68",
|
||||
"\x48\x25\x7C",
|
||||
"\x27\x28\x36",
|
||||
"\x5C\x46\x70",
|
||||
"\x3D\x4A\x6E",
|
||||
"\x24\x32\x7A",
|
||||
"\x79\x41\x2F",
|
||||
"\x37\x3D\x5F",
|
||||
"\x60\x5F\x4B",
|
||||
"\x51\x4F\x5A",
|
||||
"\x20\x42\x2C",
|
||||
"\x36\x65\x57"
|
||||
];
|
||||
|
||||
const D_COMBINATION = [
|
||||
0, 1, 2, 0, 1, 2, 1, 2, 2, 1, 2, 1, 0, 2, 1, 2, 0, 2, 1, 2, 0, 0, 1, 2, 2, 1, 0, 2, 1, 2, 2, 1,
|
||||
0, 0, 2, 1, 2, 1, 2, 0, 2, 0, 0, 1, 2, 0, 2, 1, 0, 2, 1, 2, 0, 0, 1, 2, 2, 0, 0, 1, 2, 0, 2, 1
|
||||
];
|
||||
|
||||
export default MicrosoftScriptDecoder;
|
|
@ -1,186 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
/**
|
||||
* Various components for drawing diagrams on an HTML5 canvas.
|
||||
*
|
||||
* @author n1474335 [n1474335@gmail.com]
|
||||
* @copyright Crown Copyright 2016
|
||||
* @license Apache-2.0
|
||||
*
|
||||
* @constant
|
||||
* @namespace
|
||||
*/
|
||||
const CanvasComponents = {
|
||||
|
||||
drawLine: function(ctx, startX, startY, endX, endY) {
|
||||
ctx.beginPath();
|
||||
ctx.moveTo(startX, startY);
|
||||
ctx.lineTo(endX, endY);
|
||||
ctx.closePath();
|
||||
ctx.stroke();
|
||||
},
|
||||
|
||||
drawBarChart: function(canvas, scores, xAxisLabel, yAxisLabel, numXLabels, numYLabels, fontSize) {
|
||||
fontSize = fontSize || 15;
|
||||
if (!numXLabels || numXLabels > Math.round(canvas.width / 50)) {
|
||||
numXLabels = Math.round(canvas.width / 50);
|
||||
}
|
||||
if (!numYLabels || numYLabels > Math.round(canvas.width / 50)) {
|
||||
numYLabels = Math.round(canvas.height / 50);
|
||||
}
|
||||
|
||||
// Graph properties
|
||||
var ctx = canvas.getContext("2d"),
|
||||
leftPadding = canvas.width * 0.08,
|
||||
rightPadding = canvas.width * 0.03,
|
||||
topPadding = canvas.height * 0.08,
|
||||
bottomPadding = canvas.height * 0.15,
|
||||
graphHeight = canvas.height - topPadding - bottomPadding,
|
||||
graphWidth = canvas.width - leftPadding - rightPadding,
|
||||
base = topPadding + graphHeight,
|
||||
ceil = topPadding;
|
||||
|
||||
ctx.font = fontSize + "px Arial";
|
||||
|
||||
// Draw axis
|
||||
ctx.lineWidth = "1.0";
|
||||
ctx.strokeStyle = "#444";
|
||||
CanvasComponents.drawLine(ctx, leftPadding, base, graphWidth + leftPadding, base); // x
|
||||
CanvasComponents.drawLine(ctx, leftPadding, base, leftPadding, ceil); // y
|
||||
|
||||
// Bar properties
|
||||
var barPadding = graphWidth * 0.003,
|
||||
barWidth = (graphWidth - (barPadding * scores.length)) / scores.length,
|
||||
currX = leftPadding + barPadding,
|
||||
max = Math.max.apply(Math, scores);
|
||||
|
||||
// Draw bars
|
||||
ctx.fillStyle = "green";
|
||||
for (var i = 0; i < scores.length; i++) {
|
||||
var h = scores[i] / max * graphHeight;
|
||||
ctx.fillRect(currX, base - h, barWidth, h);
|
||||
currX += barWidth + barPadding;
|
||||
}
|
||||
|
||||
// Mark x axis
|
||||
ctx.fillStyle = "black";
|
||||
ctx.textAlign = "center";
|
||||
currX = leftPadding + barPadding;
|
||||
if (numXLabels >= scores.length) {
|
||||
// Mark every score
|
||||
for (i = 0; i <= scores.length; i++) {
|
||||
ctx.fillText(i, currX, base + (bottomPadding * 0.3));
|
||||
currX += barWidth + barPadding;
|
||||
}
|
||||
} else {
|
||||
// Mark some scores
|
||||
for (i = 0; i <= numXLabels; i++) {
|
||||
var val = Math.ceil((scores.length / numXLabels) * i);
|
||||
currX = (graphWidth / numXLabels) * i + leftPadding;
|
||||
ctx.fillText(val, currX, base + (bottomPadding * 0.3));
|
||||
}
|
||||
}
|
||||
|
||||
// Mark y axis
|
||||
ctx.textAlign = "right";
|
||||
var currY;
|
||||
if (numYLabels >= max) {
|
||||
// Mark every increment
|
||||
for (i = 0; i <= max; i++) {
|
||||
currY = base - (i / max * graphHeight) + fontSize / 3;
|
||||
ctx.fillText(i, leftPadding * 0.8, currY);
|
||||
}
|
||||
} else {
|
||||
// Mark some increments
|
||||
for (i = 0; i <= numYLabels; i++) {
|
||||
val = Math.ceil((max / numYLabels) * i);
|
||||
currY = base - (val / max * graphHeight) + fontSize / 3;
|
||||
ctx.fillText(val, leftPadding * 0.8, currY);
|
||||
}
|
||||
}
|
||||
|
||||
// Label x axis
|
||||
if (xAxisLabel) {
|
||||
ctx.textAlign = "center";
|
||||
ctx.fillText(xAxisLabel, graphWidth / 2 + leftPadding, base + bottomPadding * 0.8);
|
||||
}
|
||||
|
||||
// Label y axis
|
||||
if (yAxisLabel) {
|
||||
ctx.save();
|
||||
var x = leftPadding * 0.3,
|
||||
y = graphHeight / 2 + topPadding;
|
||||
ctx.translate(x, y);
|
||||
ctx.rotate(-Math.PI / 2);
|
||||
ctx.textAlign = "center";
|
||||
ctx.fillText(yAxisLabel, 0, 0);
|
||||
ctx.restore();
|
||||
}
|
||||
},
|
||||
|
||||
drawScaleBar: function(canvas, score, max, markings) {
|
||||
// Bar properties
|
||||
var ctx = canvas.getContext("2d"),
|
||||
leftPadding = canvas.width * 0.01,
|
||||
rightPadding = canvas.width * 0.01,
|
||||
topPadding = canvas.height * 0.1,
|
||||
bottomPadding = canvas.height * 0.3,
|
||||
barHeight = canvas.height - topPadding - bottomPadding,
|
||||
barWidth = canvas.width - leftPadding - rightPadding;
|
||||
|
||||
// Scale properties
|
||||
var proportion = score / max;
|
||||
|
||||
// Draw bar outline
|
||||
ctx.strokeRect(leftPadding, topPadding, barWidth, barHeight);
|
||||
|
||||
// Shade in up to proportion
|
||||
var grad = ctx.createLinearGradient(leftPadding, 0, barWidth + leftPadding, 0);
|
||||
grad.addColorStop(0, "green");
|
||||
grad.addColorStop(0.5, "gold");
|
||||
grad.addColorStop(1, "red");
|
||||
ctx.fillStyle = grad;
|
||||
ctx.fillRect(leftPadding, topPadding, barWidth * proportion, barHeight);
|
||||
|
||||
// Add markings
|
||||
var x0, y0, x1, y1;
|
||||
ctx.fillStyle = "black";
|
||||
ctx.textAlign = "center";
|
||||
ctx.font = "13px Arial";
|
||||
for (var i = 0; i < markings.length; i++) {
|
||||
// Draw min line down
|
||||
x0 = barWidth / max * markings[i].min + leftPadding;
|
||||
y0 = topPadding + barHeight + (bottomPadding * 0.1);
|
||||
x1 = x0;
|
||||
y1 = topPadding + barHeight + (bottomPadding * 0.3);
|
||||
CanvasComponents.drawLine(ctx, x0, y0, x1, y1);
|
||||
|
||||
// Draw max line down
|
||||
x0 = barWidth / max * markings[i].max + leftPadding;
|
||||
x1 = x0;
|
||||
CanvasComponents.drawLine(ctx, x0, y0, x1, y1);
|
||||
|
||||
// Join min and max lines
|
||||
x0 = barWidth / max * markings[i].min + leftPadding;
|
||||
y0 = topPadding + barHeight + (bottomPadding * 0.3);
|
||||
x1 = barWidth / max * markings[i].max + leftPadding;
|
||||
y1 = y0;
|
||||
CanvasComponents.drawLine(ctx, x0, y0, x1, y1);
|
||||
|
||||
// Add label
|
||||
if (markings[i].max >= max * 0.9) {
|
||||
ctx.textAlign = "right";
|
||||
x0 = x1;
|
||||
} else if (markings[i].max <= max * 0.1) {
|
||||
ctx.textAlign = "left";
|
||||
} else {
|
||||
x0 = x0 + (x1 - x0) / 2;
|
||||
}
|
||||
y0 = topPadding + barHeight + (bottomPadding * 0.8);
|
||||
ctx.fillText(markings[i].label, x0, y0);
|
||||
}
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
export default CanvasComponents;
|
|
@ -13,7 +13,7 @@ import "bootstrap";
|
|||
import "bootstrap-switch";
|
||||
import "bootstrap-colorpicker";
|
||||
import moment from "moment-timezone";
|
||||
import CanvasComponents from "../core/vendor/canvascomponents.js";
|
||||
import * as CanvasComponents from "../core/lib/CanvasComponents";
|
||||
|
||||
// CyberChef
|
||||
import App from "./App";
|
||||
|
|
Loading…
Reference in New Issue