浏览代码

ESM: Ported MS and Entropy operations

n1474335 7 年之前
父节点
当前提交
84df055888

+ 6 - 0
src/core/Chef.mjs

@@ -60,6 +60,12 @@ class Chef {
             recipe.setBreakpoint(progress + 1, true);
             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
         // If stepping with flow control, we have to start from the beginning
         // but still want to skip all previous breakpoints
         // but still want to skip all previous breakpoints
         if (progress > 0 && containsFc) {
         if (progress > 0 && containsFc) {

+ 2 - 1
src/core/Operation.mjs

@@ -81,9 +81,10 @@ class Operation {
      * this behaviour.
      * this behaviour.
      *
      *
      * @param {*} data - The result of the run() function
      * @param {*} data - The result of the run() function
+     * @param {Object[]} args - The operation's arguments
      * @returns {*} - A human-readable version of the data
      * @returns {*} - A human-readable version of the data
      */
      */
-    present(data) {
+    present(data, args) {
         return data;
         return data;
     }
     }
 
 

+ 16 - 1
src/core/Recipe.mjs

@@ -212,7 +212,10 @@ class Recipe  {
     async present(dish) {
     async present(dish) {
         if (!this.lastRunOp) return;
         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);
         dish.set(output, this.lastRunOp.presentType);
     }
     }
 
 
@@ -270,6 +273,18 @@ class Recipe  {
         return highlights;
         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;
 export default Recipe;

+ 204 - 0
src/core/lib/CanvasComponents.mjs

@@ -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);
+    }
+}

+ 53 - 0
src/core/operations/ChiSquare.mjs

@@ -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;

+ 96 - 0
src/core/operations/Entropy.mjs

@@ -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;

+ 110 - 0
src/core/operations/FrequencyDistribution.mjs

@@ -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;

+ 217 - 0
src/core/operations/MicrosoftScriptDecoder.mjs

@@ -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@*@!+@*@!&amp;@*eEI@#@&amp;@#@&amp;.jm.raY 214Wv:zms/obI0xEAAA==^#~@</code><br><br>Decoded:<br><code>var my_msg = &#34;Testing <1><2><3>!&#34;;\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;

+ 0 - 186
src/core/vendor/canvascomponents.js

@@ -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;

+ 1 - 1
src/web/index.js

@@ -13,7 +13,7 @@ import "bootstrap";
 import "bootstrap-switch";
 import "bootstrap-switch";
 import "bootstrap-colorpicker";
 import "bootstrap-colorpicker";
 import moment from "moment-timezone";
 import moment from "moment-timezone";
-import CanvasComponents from "../core/vendor/canvascomponents.js";
+import * as CanvasComponents from "../core/lib/CanvasComponents";
 
 
 // CyberChef
 // CyberChef
 import App from "./App";
 import App from "./App";