浏览代码

Magic rebuild

n1073645 5 年之前
父节点
当前提交
728f8e65d6
共有 38 个文件被更改,包括 742 次插入344 次删除
  1. 23 4
      src/core/config/scripts/generateConfig.mjs
  2. 4 4
      src/core/lib/IP.mjs
  3. 103 29
      src/core/lib/Magic.mjs
  4. 12 0
      src/core/lib/MagicCriteria.mjs
  5. 36 0
      src/core/operations/A1Z26CipherDecode.mjs
  6. 46 0
      src/core/operations/BaconCipherDecode.mjs
  7. 10 6
      src/core/operations/Bzip2Decompress.mjs
  8. 11 0
      src/core/operations/DechunkHTTPResponse.mjs
  9. 11 0
      src/core/operations/DecodeNetBIOSName.mjs
  10. 21 1
      src/core/operations/DefangIPAddresses.mjs
  11. 11 7
      src/core/operations/FromBCD.mjs
  12. 11 6
      src/core/operations/FromBase32.mjs
  13. 16 11
      src/core/operations/FromBase58.mjs
  14. 71 67
      src/core/operations/FromBase64.mjs
  15. 36 32
      src/core/operations/FromDecimal.mjs
  16. 11 7
      src/core/operations/FromHTMLEntity.mjs
  17. 50 46
      src/core/operations/FromHex.mjs
  18. 11 0
      src/core/operations/FromHexContent.mjs
  19. 11 7
      src/core/operations/FromHexdump.mjs
  20. 11 7
      src/core/operations/FromMorseCode.mjs
  21. 36 32
      src/core/operations/FromOctal.mjs
  22. 11 7
      src/core/operations/FromQuotedPrintable.mjs
  23. 26 22
      src/core/operations/FromUNIXTimestamp.mjs
  24. 11 7
      src/core/operations/Gunzip.mjs
  25. 11 0
      src/core/operations/ObjectIdentifierToHex.mjs
  26. 11 0
      src/core/operations/ParseSSHHostKey.mjs
  27. 11 0
      src/core/operations/ParseUNIXFilePermissions.mjs
  28. 11 0
      src/core/operations/ParseUserAgent.mjs
  29. 9 7
      src/core/operations/ParseX509Certificate.mjs
  30. 9 0
      src/core/operations/RawInflate.mjs
  31. 1 1
      src/core/operations/RegularExpression.mjs
  32. 14 7
      src/core/operations/RenderImage.mjs
  33. 11 0
      src/core/operations/StripHTMLTags.mjs
  34. 11 0
      src/core/operations/StripHTTPHeaders.mjs
  35. 11 7
      src/core/operations/URLDecode.mjs
  36. 10 6
      src/core/operations/Untar.mjs
  37. 11 7
      src/core/operations/Unzip.mjs
  38. 11 7
      src/core/operations/ZlibInflate.mjs

+ 23 - 4
src/core/config/scripts/generateConfig.mjs

@@ -42,13 +42,32 @@ for (const opObj in Ops) {
         outputType:  op.presentType,
         outputType:  op.presentType,
         flowControl: op.flowControl,
         flowControl: op.flowControl,
         manualBake:  op.manualBake,
         manualBake:  op.manualBake,
-        args:        op.args
+        args:        op.args,
     };
     };
 
 
-    if ("patterns" in op) {
-        operationConfig[op.name].patterns = op.patterns;
+    if ("checks" in op) {
+        if ("input" in op.checks) {
+            operationConfig[op.name].input = {};
+            if ("regex" in op.checks.input) {
+                operationConfig[op.name].input.regex = op.checks.input.regex;
+            }
+            if ("entropy" in op.checks.input) {
+                operationConfig[op.name].input.entropy = op.checks.input.entropy;
+            }
+        }
+        if ("output" in op.checks) {
+            operationConfig[op.name].output = {};
+            if ("regex" in op.checks.output) {
+                operationConfig[op.name].output.regex = op.checks.output.regex;
+            }
+            if ("entropy" in op.checks.output) {
+                operationConfig[op.name].output.entropy = op.checks.output.entropy;
+            }
+            if ("mime" in op.checks.output) {
+                operationConfig[op.name].output.mime = op.checks.output.mime;
+            }
+        }
     }
     }
-
     if (!(op.module in modules))
     if (!(op.module in modules))
         modules[op.module] = {};
         modules[op.module] = {};
     modules[op.module][op.name] = opObj;
     modules[op.module][op.name] = opObj;

+ 4 - 4
src/core/lib/IP.mjs

@@ -26,7 +26,7 @@ export function ipv4CidrRange(cidr, includeNetworkInfo, enumerateAddresses, allo
     let output = "";
     let output = "";
 
 
     if (cidrRange < 0 || cidrRange > 31) {
     if (cidrRange < 0 || cidrRange > 31) {
-        return "IPv4 CIDR must be less than 32";
+        throw new OperationError("IPv4 CIDR must be less than 32");
     }
     }
 
 
     const mask = ~(0xFFFFFFFF >>> cidrRange),
     const mask = ~(0xFFFFFFFF >>> cidrRange),
@@ -64,7 +64,7 @@ export function ipv6CidrRange(cidr, includeNetworkInfo) {
         cidrRange = parseInt(cidr[cidr.length-1], 10);
         cidrRange = parseInt(cidr[cidr.length-1], 10);
 
 
     if (cidrRange < 0 || cidrRange > 127) {
     if (cidrRange < 0 || cidrRange > 127) {
-        return "IPv6 CIDR must be less than 128";
+        throw new OperationError("IPv6 CIDR must be less than 128");
     }
     }
 
 
     const ip1 = new Array(8),
     const ip1 = new Array(8),
@@ -211,7 +211,7 @@ export function ipv4ListedRange(match, includeNetworkInfo, enumerateAddresses, a
         const network = strToIpv4(ipv4CidrList[i].split("/")[0]);
         const network = strToIpv4(ipv4CidrList[i].split("/")[0]);
         const cidrRange = parseInt(ipv4CidrList[i].split("/")[1], 10);
         const cidrRange = parseInt(ipv4CidrList[i].split("/")[1], 10);
         if (cidrRange < 0 || cidrRange > 31) {
         if (cidrRange < 0 || cidrRange > 31) {
-            return "IPv4 CIDR must be less than 32";
+            throw new OperationError("IPv4 CIDR must be less than 32");
         }
         }
         const mask = ~(0xFFFFFFFF >>> cidrRange),
         const mask = ~(0xFFFFFFFF >>> cidrRange),
             cidrIp1 = network & mask,
             cidrIp1 = network & mask,
@@ -254,7 +254,7 @@ export function ipv6ListedRange(match, includeNetworkInfo) {
         const cidrRange = parseInt(ipv6CidrList[i].split("/")[1], 10);
         const cidrRange = parseInt(ipv6CidrList[i].split("/")[1], 10);
 
 
         if (cidrRange < 0 || cidrRange > 127) {
         if (cidrRange < 0 || cidrRange > 127) {
-            return "IPv6 CIDR must be less than 128";
+            throw new OperationError("IPv6 CIDR must be less than 128");
         }
         }
 
 
         const cidrIp1 = new Array(8),
         const cidrIp1 = new Array(8),

+ 103 - 29
src/core/lib/Magic.mjs

@@ -2,7 +2,7 @@ import OperationConfig from "../config/OperationConfig.json";
 import Utils, { isWorkerEnvironment } from "../Utils.mjs";
 import Utils, { isWorkerEnvironment } from "../Utils.mjs";
 import Recipe from "../Recipe.mjs";
 import Recipe from "../Recipe.mjs";
 import Dish from "../Dish.mjs";
 import Dish from "../Dish.mjs";
-import {detectFileType} from "./FileType.mjs";
+import {detectFileType, isType} from "./FileType.mjs";
 import chiSquared from "chi-squared";
 import chiSquared from "chi-squared";
 
 
 /**
 /**
@@ -19,25 +19,24 @@ class Magic {
      * Magic constructor.
      * Magic constructor.
      *
      *
      * @param {ArrayBuffer} buf
      * @param {ArrayBuffer} buf
-     * @param {Object[]} [opPatterns]
+     * @param {Object} prevOp
      */
      */
-    constructor(buf, opPatterns) {
+    constructor(buf, opPatterns, prevOp) {
         this.inputBuffer = new Uint8Array(buf);
         this.inputBuffer = new Uint8Array(buf);
         this.inputStr = Utils.arrayBufferToStr(buf);
         this.inputStr = Utils.arrayBufferToStr(buf);
-        this.opPatterns = opPatterns || Magic._generateOpPatterns();
+        this.opPatterns = opPatterns || Magic._generateOpCriteria();
+        this.prevOp = prevOp;
     }
     }
 
 
     /**
     /**
-     * Finds operations that claim to be able to decode the input based on regular
-     * expression matches.
      *
      *
-     * @returns {Object[]}
+     * @param opPatterns
      */
      */
-    findMatchingOps() {
+    inputRegexMatch(opPatterns) {
         const matches = [];
         const matches = [];
 
 
-        for (let i = 0; i < this.opPatterns.length; i++) {
-            const pattern = this.opPatterns[i],
+        for (let i = 0; i < opPatterns.length; i++) {
+            const pattern = opPatterns[i],
                 regex = new RegExp(pattern.match, pattern.flags);
                 regex = new RegExp(pattern.match, pattern.flags);
 
 
             if (regex.test(this.inputStr)) {
             if (regex.test(this.inputStr)) {
@@ -48,6 +47,34 @@ class Magic {
         return matches;
         return matches;
     }
     }
 
 
+    /**
+     *
+     */
+    entropyInputMatch(opPatterns) {
+        const matches = [];
+
+        const entropyOfInput = this.calcEntropy();
+
+        for (let i = 0; i < opPatterns.length; i++) {
+            const currOp = opPatterns[i];
+            if ((entropyOfInput > currOp.entropy[0]) && (entropyOfInput < currOp.entropy[1]))
+                matches.push(currOp);
+        }
+        return matches;
+    }
+
+    /**
+     * Finds operations that claim to be able to decode the input based on regular
+     * expression matches.
+     *
+     * @returns {Object[]}
+     */
+    findMatchingInputOps() {
+        let matches = this.inputRegexMatch(this.opPatterns.regex);
+        matches = matches.concat(this.entropyInputMatch(this.opPatterns.entropy));
+        return [...new Set(matches)];
+    }
+
     /**
     /**
      * Attempts to detect the language of the input by comparing its byte frequency
      * Attempts to detect the language of the input by comparing its byte frequency
      * to that of several known languages.
      * to that of several known languages.
@@ -264,6 +291,35 @@ class Magic {
         return results;
         return results;
     }
     }
 
 
+    /**
+     *
+     */
+    checkRegexes(regexes) {
+        for (const elem of regexes) {
+            const regex = new RegExp(elem.match, elem.flags);
+            if  (regex.test(this.inputStr))
+                return true;
+        }
+        return false;
+    }
+    /**
+     *
+     */
+    checkOutputFromPrevious() {
+        let score = 0;
+        if ("regex" in this.prevOp.output) {
+            if (this.checkRegexes(this.prevOp.output.regex)) score++;
+        }
+        if ("entropy" in this.prevOp.output) {
+            const inputEntropy = this.calcEntropy();
+            if ((inputEntropy > this.prevOp.output.entropy[0]) && (inputEntropy < this.prevOp.output.entropy[1])) score++;
+        }
+        if ("mime" in this.prevOp.output) {
+            if (isType(this.prevOp.output.mime, this.inputBuffer)) score++;
+        }
+        return score > 0;
+    }
+
     /**
     /**
      * Speculatively executes matching operations, recording metadata of each result.
      * Speculatively executes matching operations, recording metadata of each result.
      *
      *
@@ -281,8 +337,15 @@ class Magic {
         if (depth < 0) return [];
         if (depth < 0) return [];
 
 
         // Find any operations that can be run on this data
         // Find any operations that can be run on this data
-        const matchingOps = this.findMatchingOps();
 
 
+        if (this.prevOp) {
+            if ("output" in this.prevOp) {
+                if (!(this.checkOutputFromPrevious())) {
+                    return [];
+                }
+            }
+        }
+        const matchingOps = this.findMatchingInputOps();
         let results = [];
         let results = [];
 
 
         // Record the properties of the current data
         // Record the properties of the current data
@@ -305,8 +368,7 @@ class Magic {
             const opConfig = {
             const opConfig = {
                     op: op.op,
                     op: op.op,
                     args: op.args
                     args: op.args
-                },
-                output = await this._runRecipe([opConfig]);
+                }, output = await this._runRecipe([opConfig]);
 
 
             // If the recipe is repeating and returning the same data, do not continue
             // If the recipe is repeating and returning the same data, do not continue
             if (prevOp && op.op === prevOp.op && _buffersEqual(output, this.inputBuffer)) {
             if (prevOp && op.op === prevOp.op && _buffersEqual(output, this.inputBuffer)) {
@@ -318,7 +380,8 @@ class Magic {
                 return;
                 return;
             }
             }
 
 
-            const magic = new Magic(output, this.opPatterns),
+
+            const magic = new Magic(output, this.opPatterns, OperationConfig[op.op]),
                 speculativeResults = await magic.speculativeExecution(
                 speculativeResults = await magic.speculativeExecution(
                     depth-1, extLang, intensive, [...recipeConfig, opConfig], op.useful, crib);
                     depth-1, extLang, intensive, [...recipeConfig, opConfig], op.useful, crib);
 
 
@@ -330,7 +393,7 @@ class Magic {
             const bfEncodings = await this.bruteForce();
             const bfEncodings = await this.bruteForce();
 
 
             await Promise.all(bfEncodings.map(async enc => {
             await Promise.all(bfEncodings.map(async enc => {
-                const magic = new Magic(enc.data, this.opPatterns),
+                const magic = new Magic(enc.data, this.opPatterns, undefined),
                     bfResults = await magic.speculativeExecution(
                     bfResults = await magic.speculativeExecution(
                         depth-1, extLang, false, [...recipeConfig, enc.conf], false, crib);
                         depth-1, extLang, false, [...recipeConfig, enc.conf], false, crib);
 
 
@@ -447,24 +510,35 @@ class Magic {
      * @private
      * @private
      * @returns {Object[]}
      * @returns {Object[]}
      */
      */
-    static _generateOpPatterns() {
-        const opPatterns = [];
+    static _generateOpCriteria() {
+        const opCriteria = {
+            regex: [],
+            entropy: []
+        };
 
 
         for (const op in OperationConfig) {
         for (const op in OperationConfig) {
-            if (!("patterns" in OperationConfig[op])) continue;
-
-            OperationConfig[op].patterns.forEach(pattern => {
-                opPatterns.push({
-                    op: op,
-                    match: pattern.match,
-                    flags: pattern.flags,
-                    args: pattern.args,
-                    useful: pattern.useful || false
-                });
-            });
+            if ("input" in OperationConfig[op]) {
+                if ("regex" in OperationConfig[op].input)
+                    OperationConfig[op].input.regex.forEach(pattern => {
+                        opCriteria.regex.push({
+                            op: op,
+                            match: pattern.match,
+                            flags: pattern.flags,
+                            args: pattern.args,
+                            useful: pattern.useful || false
+                        });
+                    });
+                if ("entropy" in OperationConfig[op].input) {
+                    opCriteria.entropy.push({
+                        op: op,
+                        entropy: OperationConfig[op].input.entropy.input,
+                        args:  OperationConfig[op].input.entropy.args
+                    });
+                }
+            }
         }
         }
 
 
-        return opPatterns;
+        return opCriteria;
     }
     }
 
 
     /**
     /**

+ 12 - 0
src/core/lib/MagicCriteria.mjs

@@ -0,0 +1,12 @@
+/**
+ * Constants for the entropy of text.
+ *
+ * @author n1073645 [n1073645@gmail.com]
+ * @copyright Crown Copyright 2020
+ * @license Apache-2.0
+*/
+export const compressedToDecompressed = [6.5, 8];
+
+export const binary = [1, 1.5];
+
+export const entropyOfText = [3.5, 6];

+ 36 - 0
src/core/operations/A1Z26CipherDecode.mjs

@@ -33,6 +33,42 @@ class A1Z26CipherDecode extends Operation {
                 value: DELIM_OPTIONS
                 value: DELIM_OPTIONS
             }
             }
         ];
         ];
+        this.checks = {
+            input: {
+                regex: [
+                    {
+                        match:  "^\\s*([12]?[0-9] )+[12]?[0-9]\\s*$",
+                        flags:  "",
+                        args:   ["Space"]
+                    },
+                    {
+                        match:  "^\\s*([12]?[0-9],)+[12]?[0-9]\\s*$",
+                        flags:  "",
+                        args:   ["Comma"]
+                    },
+                    {
+                        match:  "^\\s*([12]?[0-9];)+[12]?[0-9]\\s*$",
+                        flags:  "",
+                        args:   ["Semi-colon"]
+                    },
+                    {
+                        match:  "^\\s*([12]?[0-9]:)+[12]?[0-9]\\s*$",
+                        flags:  "",
+                        args:   ["Colon"]
+                    },
+                    {
+                        match:  "^\\s*([12]?[0-9]\\n)+[12]?[0-9]\\s*$",
+                        flags:  "",
+                        args:   ["Line feed"]
+                    },
+                    {
+                        match:  "^\\s*([12]?[0-9]\\r\\n)+[12]?[0-9]\\s*$",
+                        flags:  "",
+                        args:   ["CRLF"]
+                    }
+                ]
+            }
+        };
     }
     }
 
 
     /**
     /**

+ 46 - 0
src/core/operations/BaconCipherDecode.mjs

@@ -44,6 +44,52 @@ class BaconCipherDecode extends Operation {
                 "value": false
                 "value": false
             }
             }
         ];
         ];
+        this.checks = {
+            input: {
+                regex: [
+                    {
+                        match:  "^\\s*([01]{5}\\s?)+$",
+                        flags:  "",
+                        args:   ["Standard (I=J and U=V)", "0/1", false]
+                    },
+                    {
+                        match:  "^\\s*([01]{5}\\s?)+$",
+                        flags:  "",
+                        args:   ["Standard (I=J and U=V)", "0/1", true]
+                    },
+                    {
+                        match:  "^\\s*([AB]{5}\\s?)+$",
+                        flags:  "",
+                        args:   ["Standard (I=J and U=V)", "A/B", false]
+                    },
+                    {
+                        match:  "^\\s*([AB]{5}\\s?)+$",
+                        flags:  "",
+                        args:   ["Standard (I=J and U=V)", "A/B", true]
+                    },
+                    {
+                        match:  "^\\s*([01]{5}\\s?)+$",
+                        flags:  "",
+                        args:   ["Complete", "0/1", false]
+                    },
+                    {
+                        match:  "^\\s*([01]{5}\\s?)+$",
+                        flags:  "",
+                        args:   ["Complete", "0/1", true]
+                    },
+                    {
+                        match:  "^\\s*([AB]{5}\\s?)+$",
+                        flags:  "",
+                        args:   ["Complete", "A/B", false]
+                    },
+                    {
+                        match:  "^\\s*([AB]{5}\\s?)+$",
+                        flags:  "",
+                        args:   ["Complete", "A/B", true]
+                    }
+                ]
+            }
+        };
     }
     }
 
 
     /**
     /**

+ 10 - 6
src/core/operations/Bzip2Decompress.mjs

@@ -33,13 +33,17 @@ class Bzip2Decompress extends Operation {
                 value: false
                 value: false
             }
             }
         ];
         ];
-        this.patterns = [
-            {
-                "match": "^\\x42\\x5a\\x68",
-                "flags": "",
-                "args": []
+        this.checks = {
+            input: {
+                regex: [
+                    {
+                        "match": "^\\x42\\x5a\\x68",
+                        "flags": "",
+                        "args": []
+                    }
+                ]
             }
             }
-        ];
+        };
     }
     }
 
 
     /**
     /**

+ 11 - 0
src/core/operations/DechunkHTTPResponse.mjs

@@ -24,6 +24,17 @@ class DechunkHTTPResponse extends Operation {
         this.inputType = "string";
         this.inputType = "string";
         this.outputType = "string";
         this.outputType = "string";
         this.args = [];
         this.args = [];
+        this.checks = {
+            input: {
+                regex: [
+                    {
+                        match:  "^\\s*[0-9A-F]+\r\n",
+                        flags:  "i",
+                        args:   []
+                    }
+                ]
+            }
+        };
     }
     }
 
 
     /**
     /**

+ 11 - 0
src/core/operations/DecodeNetBIOSName.mjs

@@ -30,6 +30,17 @@ class DecodeNetBIOSName extends Operation {
                 "value": 65
                 "value": 65
             }
             }
         ];
         ];
+        this.checks = {
+            input: {
+                regex: [
+                    {
+                        match:  "^\\s*\\S{32}$",
+                        flags:  "",
+                        args:   [65]
+                    }
+                ]
+            }
+        };
     }
     }
 
 
     /**
     /**

+ 21 - 1
src/core/operations/DefangIPAddresses.mjs

@@ -25,7 +25,27 @@ class DefangIPAddresses extends Operation {
         this.inputType = "string";
         this.inputType = "string";
         this.outputType = "string";
         this.outputType = "string";
         this.args = [];
         this.args = [];
-
+        this.checks = {
+            input: {
+                regex: [
+                    {
+                        match: "^\\s*(([0-9]{1,3}\\.){3}[0-9]{1,3}|([0-9a-f]{4}:){7}[0-9a-f]{4})\\s*$",
+                        flags: "i",
+                        args: [],
+                    }
+                ]
+            },
+            output: {
+                regex: [
+                    {
+                        match: "^\\s*(([0-9]{1,3}\\[\\.\\]){3}[0-9]{1,3}|([0-9a-f]{4}\\[\\:\\]){7}[0-9a-f]{4})\\s*$",
+                        flags: "i",
+                        shouldMatch: true,
+                        args: []
+                    }
+                ]
+            }
+        };
     }
     }
 
 
     /**
     /**

+ 11 - 7
src/core/operations/FromBCD.mjs

@@ -49,13 +49,17 @@ class FromBCD extends Operation {
                 "value": FORMAT
                 "value": FORMAT
             }
             }
         ];
         ];
-        this.patterns = [
-            {
-                match: "^(?:\\d{4} ){3,}\\d{4}$",
-                flags: "",
-                args: ["8 4 2 1", true, false, "Nibbles"]
-            },
-        ];
+        this.checks = {
+            input: {
+                regex: [
+                    {
+                        match: "^(?:\\d{4} ){3,}\\d{4}$",
+                        flags: "",
+                        args: ["8 4 2 1", true, false, "Nibbles"]
+                    },
+                ]
+            }
+        };
     }
     }
 
 
     /**
     /**

+ 11 - 6
src/core/operations/FromBase32.mjs

@@ -36,13 +36,18 @@ class FromBase32 extends Operation {
                 value: true
                 value: true
             }
             }
         ];
         ];
-        this.patterns = [
+        this.checks = {
+            input:
             {
             {
-                match: "^(?:[A-Z2-7]{8})+(?:[A-Z2-7]{2}={6}|[A-Z2-7]{4}={4}|[A-Z2-7]{5}={3}|[A-Z2-7]{7}={1})?$",
-                flags: "",
-                args: ["A-Z2-7=", false]
-            },
-        ];
+                regex: [
+                    {
+                        match: "^(?:[A-Z2-7]{8})+(?:[A-Z2-7]{2}={6}|[A-Z2-7]{4}={4}|[A-Z2-7]{5}={3}|[A-Z2-7]{7}={1})?$",
+                        flags: "",
+                        args: ["A-Z2-7=", false]
+                    }
+                ]
+            }
+        };
     }
     }
 
 
     /**
     /**

+ 16 - 11
src/core/operations/FromBase58.mjs

@@ -38,18 +38,23 @@ class FromBase58 extends Operation {
                 "value": true
                 "value": true
             }
             }
         ];
         ];
-        this.patterns = [
+        this.checks = {
+            input:
             {
             {
-                match: "^[1-9A-HJ-NP-Za-km-z]{20,}$",
-                flags: "",
-                args: ["123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz", false]
-            },
-            {
-                match: "^[1-9A-HJ-NP-Za-km-z]{20,}$",
-                flags: "",
-                args: ["rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz", false]
-            },
-        ];
+                regex: [
+                    {
+                        match: "^[1-9A-HJ-NP-Za-km-z]{20,}$",
+                        flags: "",
+                        args: ["123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz", false]
+                    },
+                    {
+                        match: "^[1-9A-HJ-NP-Za-km-z]{20,}$",
+                        flags: "",
+                        args: ["rpshnaf39wBUDNEGHJKLM4PQRST7VWXYZ2bcdeCg65jkm8oFqi1tuvAxyz", false]
+                    },
+                ]
+            }
+        };
     }
     }
 
 
     /**
     /**

+ 71 - 67
src/core/operations/FromBase64.mjs

@@ -36,73 +36,77 @@ class FromBase64 extends Operation {
                 value: true
                 value: true
             }
             }
         ];
         ];
-        this.patterns = [
-            {
-                match: "^\\s*(?:[A-Z\\d+/]{4})+(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
-                flags: "i",
-                args: ["A-Za-z0-9+/=", true]
-            },
-            {
-                match: "^\\s*[A-Z\\d\\-_]{20,}\\s*$",
-                flags: "i",
-                args: ["A-Za-z0-9-_", true]
-            },
-            {
-                match: "^\\s*(?:[A-Z\\d+\\-]{4}){5,}(?:[A-Z\\d+\\-]{2}==|[A-Z\\d+\\-]{3}=)?\\s*$",
-                flags: "i",
-                args: ["A-Za-z0-9+\\-=", true]
-            },
-            {
-                match: "^\\s*(?:[A-Z\\d./]{4}){5,}(?:[A-Z\\d./]{2}==|[A-Z\\d./]{3}=)?\\s*$",
-                flags: "i",
-                args: ["./0-9A-Za-z=", true]
-            },
-            {
-                match: "^\\s*[A-Z\\d_.]{20,}\\s*$",
-                flags: "i",
-                args: ["A-Za-z0-9_.", true]
-            },
-            {
-                match: "^\\s*(?:[A-Z\\d._]{4}){5,}(?:[A-Z\\d._]{2}--|[A-Z\\d._]{3}-)?\\s*$",
-                flags: "i",
-                args: ["A-Za-z0-9._-", true]
-            },
-            {
-                match: "^\\s*(?:[A-Z\\d+/]{4}){5,}(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
-                flags: "i",
-                args: ["0-9a-zA-Z+/=", true]
-            },
-            {
-                match: "^\\s*(?:[A-Z\\d+/]{4}){5,}(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
-                flags: "i",
-                args: ["0-9A-Za-z+/=", true]
-            },
-            {
-                match: "^[ !\"#$%&'()*+,\\-./\\d:;<=>?@A-Z[\\\\\\]^_]{20,}$",
-                flags: "",
-                args: [" -_", false]
-            },
-            {
-                match: "^\\s*[A-Z\\d+\\-]{20,}\\s*$",
-                flags: "i",
-                args: ["+\\-0-9A-Za-z", true]
-            },
-            {
-                match: "^\\s*[!\"#$%&'()*+,\\-0-689@A-NP-VX-Z[`a-fh-mp-r]{20,}\\s*$",
-                flags: "",
-                args: ["!-,-0-689@A-NP-VX-Z[`a-fh-mp-r", true]
-            },
-            {
-                match: "^\\s*(?:[N-ZA-M\\d+/]{4}){5,}(?:[N-ZA-M\\d+/]{2}==|[N-ZA-M\\d+/]{3}=)?\\s*$",
-                flags: "i",
-                args: ["N-ZA-Mn-za-m0-9+/=", true]
-            },
-            {
-                match: "^\\s*[A-Z\\d./]{20,}\\s*$",
-                flags: "i",
-                args: ["./0-9A-Za-z", true]
-            },
-        ];
+        this.checks = {
+            input: {
+                regex: [
+                    {
+                        match: "^\\s*(?:[A-Z\\d+/]{4})+(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
+                        flags: "i",
+                        args: ["A-Za-z0-9+/=", true]
+                    },
+                    {
+                        match: "^\\s*[A-Z\\d\\-_]{20,}\\s*$",
+                        flags: "i",
+                        args: ["A-Za-z0-9-_", true]
+                    },
+                    {
+                        match: "^\\s*(?:[A-Z\\d+\\-]{4}){5,}(?:[A-Z\\d+\\-]{2}==|[A-Z\\d+\\-]{3}=)?\\s*$",
+                        flags: "i",
+                        args: ["A-Za-z0-9+\\-=", true]
+                    },
+                    {
+                        match: "^\\s*(?:[A-Z\\d./]{4}){5,}(?:[A-Z\\d./]{2}==|[A-Z\\d./]{3}=)?\\s*$",
+                        flags: "i",
+                        args: ["./0-9A-Za-z=", true]
+                    },
+                    {
+                        match: "^\\s*[A-Z\\d_.]{20,}\\s*$",
+                        flags: "i",
+                        args: ["A-Za-z0-9_.", true]
+                    },
+                    {
+                        match: "^\\s*(?:[A-Z\\d._]{4}){5,}(?:[A-Z\\d._]{2}--|[A-Z\\d._]{3}-)?\\s*$",
+                        flags: "i",
+                        args: ["A-Za-z0-9._-", true]
+                    },
+                    {
+                        match: "^\\s*(?:[A-Z\\d+/]{4}){5,}(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
+                        flags: "i",
+                        args: ["0-9a-zA-Z+/=", true]
+                    },
+                    {
+                        match: "^\\s*(?:[A-Z\\d+/]{4}){5,}(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
+                        flags: "i",
+                        args: ["0-9A-Za-z+/=", true]
+                    },
+                    {
+                        match: "^[ !\"#$%&'()*+,\\-./\\d:;<=>?@A-Z[\\\\\\]^_]{20,}$",
+                        flags: "",
+                        args: [" -_", false]
+                    },
+                    {
+                        match: "^\\s*[A-Z\\d+\\-]{20,}\\s*$",
+                        flags: "i",
+                        args: ["+\\-0-9A-Za-z", true]
+                    },
+                    {
+                        match: "^\\s*[!\"#$%&'()*+,\\-0-689@A-NP-VX-Z[`a-fh-mp-r]{20,}\\s*$",
+                        flags: "",
+                        args: ["!-,-0-689@A-NP-VX-Z[`a-fh-mp-r", true]
+                    },
+                    {
+                        match: "^\\s*(?:[N-ZA-M\\d+/]{4}){5,}(?:[N-ZA-M\\d+/]{2}==|[N-ZA-M\\d+/]{3}=)?\\s*$",
+                        flags: "i",
+                        args: ["N-ZA-Mn-za-m0-9+/=", true]
+                    },
+                    {
+                        match: "^\\s*[A-Z\\d./]{20,}\\s*$",
+                        flags: "i",
+                        args: ["./0-9A-Za-z", true]
+                    },
+                ],
+            }
+        };
     }
     }
 
 
     /**
     /**

+ 36 - 32
src/core/operations/FromDecimal.mjs

@@ -36,38 +36,42 @@ class FromDecimal extends Operation {
                 "value": false
                 "value": false
             }
             }
         ];
         ];
-        this.patterns = [
-            {
-                match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?: (?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
-                flags: "",
-                args: ["Space", false]
-            },
-            {
-                match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:,(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
-                flags: "",
-                args: ["Comma", false]
-            },
-            {
-                match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:;(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
-                flags: "",
-                args: ["Semi-colon", false]
-            },
-            {
-                match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?::(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
-                flags: "",
-                args: ["Colon", false]
-            },
-            {
-                match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:\\n(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
-                flags: "",
-                args: ["Line feed", false]
-            },
-            {
-                match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:\\r\\n(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
-                flags: "",
-                args: ["CRLF", false]
-            },
-        ];
+        this.checks = {
+            input: {
+                regex: [
+                    {
+                        match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?: (?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
+                        flags: "",
+                        args: ["Space", false]
+                    },
+                    {
+                        match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:,(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
+                        flags: "",
+                        args: ["Comma", false]
+                    },
+                    {
+                        match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:;(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
+                        flags: "",
+                        args: ["Semi-colon", false]
+                    },
+                    {
+                        match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?::(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
+                        flags: "",
+                        args: ["Colon", false]
+                    },
+                    {
+                        match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:\\n(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
+                        flags: "",
+                        args: ["Line feed", false]
+                    },
+                    {
+                        match: "^(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5])(?:\\r\\n(?:\\d{1,2}|1\\d{2}|2[0-4]\\d|25[0-5]))*$",
+                        flags: "",
+                        args: ["CRLF", false]
+                    }
+                ]
+            }
+        };
     }
     }
 
 
     /**
     /**

+ 11 - 7
src/core/operations/FromHTMLEntity.mjs

@@ -25,13 +25,17 @@ class FromHTMLEntity extends Operation {
         this.inputType = "string";
         this.inputType = "string";
         this.outputType = "string";
         this.outputType = "string";
         this.args = [];
         this.args = [];
-        this.patterns = [
-            {
-                match: "&(?:#\\d{2,3}|#x[\\da-f]{2}|[a-z]{2,6});",
-                flags: "i",
-                args: []
-            },
-        ];
+        this.checks = {
+            input: {
+                regex: [
+                    {
+                        match: "&(?:#\\d{2,3}|#x[\\da-f]{2}|[a-z]{2,6});",
+                        flags: "i",
+                        args: []
+                    }
+                ]
+            }
+        };
     }
     }
 
 
     /**
     /**

+ 50 - 46
src/core/operations/FromHex.mjs

@@ -32,53 +32,57 @@ class FromHex extends Operation {
                 value: FROM_HEX_DELIM_OPTIONS
                 value: FROM_HEX_DELIM_OPTIONS
             }
             }
         ];
         ];
-        this.patterns = [
-            {
-                match: "^(?:[\\dA-F]{2})+$",
-                flags: "i",
-                args: ["None"]
-            },
-            {
-                match: "^[\\dA-F]{2}(?: [\\dA-F]{2})*$",
-                flags: "i",
-                args: ["Space"]
-            },
-            {
-                match: "^[\\dA-F]{2}(?:,[\\dA-F]{2})*$",
-                flags: "i",
-                args: ["Comma"]
-            },
-            {
-                match: "^[\\dA-F]{2}(?:;[\\dA-F]{2})*$",
-                flags: "i",
-                args: ["Semi-colon"]
-            },
-            {
-                match: "^[\\dA-F]{2}(?::[\\dA-F]{2})*$",
-                flags: "i",
-                args: ["Colon"]
-            },
-            {
-                match: "^[\\dA-F]{2}(?:\\n[\\dA-F]{2})*$",
-                flags: "i",
-                args: ["Line feed"]
-            },
-            {
-                match: "^[\\dA-F]{2}(?:\\r\\n[\\dA-F]{2})*$",
-                flags: "i",
-                args: ["CRLF"]
-            },
-            {
-                match: "^[\\dA-F]{2}(?:0x[\\dA-F]{2})*$",
-                flags: "i",
-                args: ["0x"]
-            },
-            {
-                match: "^[\\dA-F]{2}(?:\\\\x[\\dA-F]{2})*$",
-                flags: "i",
-                args: ["\\x"]
+        this.checks = {
+            input: {
+                regex: [
+                    {
+                        match: "^(?:[\\dA-F]{2})+$",
+                        flags: "i",
+                        args: ["None"]
+                    },
+                    {
+                        match: "^[\\dA-F]{2}(?: [\\dA-F]{2})*$",
+                        flags: "i",
+                        args: ["Space"]
+                    },
+                    {
+                        match: "^[\\dA-F]{2}(?:,[\\dA-F]{2})*$",
+                        flags: "i",
+                        args: ["Comma"]
+                    },
+                    {
+                        match: "^[\\dA-F]{2}(?:;[\\dA-F]{2})*$",
+                        flags: "i",
+                        args: ["Semi-colon"]
+                    },
+                    {
+                        match: "^[\\dA-F]{2}(?::[\\dA-F]{2})*$",
+                        flags: "i",
+                        args: ["Colon"]
+                    },
+                    {
+                        match: "^[\\dA-F]{2}(?:\\n[\\dA-F]{2})*$",
+                        flags: "i",
+                        args: ["Line feed"]
+                    },
+                    {
+                        match: "^[\\dA-F]{2}(?:\\r\\n[\\dA-F]{2})*$",
+                        flags: "i",
+                        args: ["CRLF"]
+                    },
+                    {
+                        match: "^[\\dA-F]{2}(?:0x[\\dA-F]{2})*$",
+                        flags: "i",
+                        args: ["0x"]
+                    },
+                    {
+                        match: "^[\\dA-F]{2}(?:\\\\x[\\dA-F]{2})*$",
+                        flags: "i",
+                        args: ["\\x"]
+                    }
+                ]
             }
             }
-        ];
+        };
     }
     }
 
 
     /**
     /**

+ 11 - 0
src/core/operations/FromHexContent.mjs

@@ -26,6 +26,17 @@ class FromHexContent extends Operation {
         this.inputType = "string";
         this.inputType = "string";
         this.outputType = "byteArray";
         this.outputType = "byteArray";
         this.args = [];
         this.args = [];
+        this.checks = {
+            input: {
+                regex: [
+                    {
+                        match:  "^\\s*.*?\\|([0-9a-f]{2})+\\|.*$",
+                        flags:  "i",
+                        args:   []
+                    }
+                ],
+            }
+        };
     }
     }
 
 
     /**
     /**

+ 11 - 7
src/core/operations/FromHexdump.mjs

@@ -27,13 +27,17 @@ class FromHexdump extends Operation {
         this.inputType = "string";
         this.inputType = "string";
         this.outputType = "byteArray";
         this.outputType = "byteArray";
         this.args = [];
         this.args = [];
-        this.patterns = [
-            {
-                match: "^(?:(?:[\\dA-F]{4,16}h?:?)?[ \\t]*((?:[\\dA-F]{2} ){1,8}(?:[ \\t]|[\\dA-F]{2}-)(?:[\\dA-F]{2} ){1,8}|(?:[\\dA-F]{4} )*[\\dA-F]{4}|(?:[\\dA-F]{2} )*[\\dA-F]{2})[^\\n]*\\n?){2,}$",
-                flags: "i",
-                args: []
-            },
-        ];
+        this.checks = {
+            input: {
+                regex: [
+                    {
+                        match: "^(?:(?:[\\dA-F]{4,16}h?:?)?[ \\t]*((?:[\\dA-F]{2} ){1,8}(?:[ \\t]|[\\dA-F]{2}-)(?:[\\dA-F]{2} ){1,8}|(?:[\\dA-F]{4} )*[\\dA-F]{4}|(?:[\\dA-F]{2} )*[\\dA-F]{2})[^\\n]*\\n?){2,}$",
+                        flags: "i",
+                        args: []
+                    },
+                ]
+            }
+        };
     }
     }
 
 
     /**
     /**

+ 11 - 7
src/core/operations/FromMorseCode.mjs

@@ -37,13 +37,17 @@ class FromMorseCode extends Operation {
                 "value": WORD_DELIM_OPTIONS
                 "value": WORD_DELIM_OPTIONS
             }
             }
         ];
         ];
-        this.patterns = [
-            {
-                match: "(?:^[-. \\n]{5,}$|^[_. \\n]{5,}$|^(?:dash|dot| |\\n){5,}$)",
-                flags: "i",
-                args: ["Space", "Line feed"]
-            },
-        ];
+        this.checks = {
+            input: {
+                regex: [
+                    {
+                        match: "(?:^[-. \\n]{5,}$|^[_. \\n]{5,}$|^(?:dash|dot| |\\n){5,}$)",
+                        flags: "i",
+                        args: ["Space", "Line feed"]
+                    }
+                ]
+            }
+        };
     }
     }
 
 
     /**
     /**

+ 36 - 32
src/core/operations/FromOctal.mjs

@@ -32,38 +32,42 @@ class FromOctal extends Operation {
                 "value": DELIM_OPTIONS
                 "value": DELIM_OPTIONS
             }
             }
         ];
         ];
-        this.patterns = [
-            {
-                match: "^(?:[0-7]{1,2}|[123][0-7]{2})(?: (?:[0-7]{1,2}|[123][0-7]{2}))*$",
-                flags: "",
-                args: ["Space"]
-            },
-            {
-                match: "^(?:[0-7]{1,2}|[123][0-7]{2})(?:,(?:[0-7]{1,2}|[123][0-7]{2}))*$",
-                flags: "",
-                args: ["Comma"]
-            },
-            {
-                match: "^(?:[0-7]{1,2}|[123][0-7]{2})(?:;(?:[0-7]{1,2}|[123][0-7]{2}))*$",
-                flags: "",
-                args: ["Semi-colon"]
-            },
-            {
-                match: "^(?:[0-7]{1,2}|[123][0-7]{2})(?::(?:[0-7]{1,2}|[123][0-7]{2}))*$",
-                flags: "",
-                args: ["Colon"]
-            },
-            {
-                match: "^(?:[0-7]{1,2}|[123][0-7]{2})(?:\\n(?:[0-7]{1,2}|[123][0-7]{2}))*$",
-                flags: "",
-                args: ["Line feed"]
-            },
-            {
-                match: "^(?:[0-7]{1,2}|[123][0-7]{2})(?:\\r\\n(?:[0-7]{1,2}|[123][0-7]{2}))*$",
-                flags: "",
-                args: ["CRLF"]
-            },
-        ];
+        this.checks = {
+            input: {
+                regex: [
+                    {
+                        match: "^(?:[0-7]{1,2}|[123][0-7]{2})(?: (?:[0-7]{1,2}|[123][0-7]{2}))*$",
+                        flags: "",
+                        args: ["Space"]
+                    },
+                    {
+                        match: "^(?:[0-7]{1,2}|[123][0-7]{2})(?:,(?:[0-7]{1,2}|[123][0-7]{2}))*$",
+                        flags: "",
+                        args: ["Comma"]
+                    },
+                    {
+                        match: "^(?:[0-7]{1,2}|[123][0-7]{2})(?:;(?:[0-7]{1,2}|[123][0-7]{2}))*$",
+                        flags: "",
+                        args: ["Semi-colon"]
+                    },
+                    {
+                        match: "^(?:[0-7]{1,2}|[123][0-7]{2})(?::(?:[0-7]{1,2}|[123][0-7]{2}))*$",
+                        flags: "",
+                        args: ["Colon"]
+                    },
+                    {
+                        match: "^(?:[0-7]{1,2}|[123][0-7]{2})(?:\\n(?:[0-7]{1,2}|[123][0-7]{2}))*$",
+                        flags: "",
+                        args: ["Line feed"]
+                    },
+                    {
+                        match: "^(?:[0-7]{1,2}|[123][0-7]{2})(?:\\r\\n(?:[0-7]{1,2}|[123][0-7]{2}))*$",
+                        flags: "",
+                        args: ["CRLF"]
+                    }
+                ]
+            }
+        };
     }
     }
 
 
     /**
     /**

+ 11 - 7
src/core/operations/FromQuotedPrintable.mjs

@@ -28,13 +28,17 @@ class FromQuotedPrintable extends Operation {
         this.inputType = "string";
         this.inputType = "string";
         this.outputType = "byteArray";
         this.outputType = "byteArray";
         this.args = [];
         this.args = [];
-        this.patterns = [
-            {
-                match: "^[\\x21-\\x3d\\x3f-\\x7e \\t]{0,76}(?:=[\\da-f]{2}|=\\r?\\n)(?:[\\x21-\\x3d\\x3f-\\x7e \\t]|=[\\da-f]{2}|=\\r?\\n)*$",
-                flags: "i",
-                args: []
-            },
-        ];
+        this.checks = {
+            input: {
+                regex: [
+                    {
+                        match: "^[\\x21-\\x3d\\x3f-\\x7e \\t]{0,76}(?:=[\\da-f]{2}|=\\r?\\n)(?:[\\x21-\\x3d\\x3f-\\x7e \\t]|=[\\da-f]{2}|=\\r?\\n)*$",
+                        flags: "i",
+                        args: []
+                    },
+                ]
+            }
+        };
     }
     }
 
 
     /**
     /**

+ 26 - 22
src/core/operations/FromUNIXTimestamp.mjs

@@ -33,28 +33,32 @@ class FromUNIXTimestamp extends Operation {
                 "value": UNITS
                 "value": UNITS
             }
             }
         ];
         ];
-        this.patterns = [
-            {
-                match: "^1?\\d{9}$",
-                flags: "",
-                args: ["Seconds (s)"]
-            },
-            {
-                match: "^1?\\d{12}$",
-                flags: "",
-                args: ["Milliseconds (ms)"]
-            },
-            {
-                match: "^1?\\d{15}$",
-                flags: "",
-                args: ["Microseconds (μs)"]
-            },
-            {
-                match: "^1?\\d{18}$",
-                flags: "",
-                args: ["Nanoseconds (ns)"]
-            },
-        ];
+        this.checks = {
+            input: {
+                regex: [
+                    {
+                        match: "^1?\\d{9}$",
+                        flags: "",
+                        args: ["Seconds (s)"]
+                    },
+                    {
+                        match: "^1?\\d{12}$",
+                        flags: "",
+                        args: ["Milliseconds (ms)"]
+                    },
+                    {
+                        match: "^1?\\d{15}$",
+                        flags: "",
+                        args: ["Microseconds (μs)"]
+                    },
+                    {
+                        match: "^1?\\d{18}$",
+                        flags: "",
+                        args: ["Nanoseconds (ns)"]
+                    }
+                ]
+            }
+        };
     }
     }
 
 
     /**
     /**

+ 11 - 7
src/core/operations/Gunzip.mjs

@@ -27,13 +27,17 @@ class Gunzip extends Operation {
         this.inputType = "ArrayBuffer";
         this.inputType = "ArrayBuffer";
         this.outputType = "ArrayBuffer";
         this.outputType = "ArrayBuffer";
         this.args = [];
         this.args = [];
-        this.patterns = [
-            {
-                match: "^\\x1f\\x8b\\x08",
-                flags: "",
-                args: []
-            },
-        ];
+        this.checks = {
+            input: {
+                regex: [
+                    {
+                        match: "^\\x1f\\x8b\\x08",
+                        flags: "",
+                        args: []
+                    }
+                ]
+            }
+        };
     }
     }
 
 
     /**
     /**

+ 11 - 0
src/core/operations/ObjectIdentifierToHex.mjs

@@ -25,6 +25,17 @@ class ObjectIdentifierToHex extends Operation {
         this.inputType = "string";
         this.inputType = "string";
         this.outputType = "string";
         this.outputType = "string";
         this.args = [];
         this.args = [];
+        this.checks = {
+            input: {
+                regex: [
+                    {
+                        match:  "^\\s*([0-9]{1,3}\\.)+[0-9]{1,3}\\s*$",
+                        flags:  "",
+                        args:   []
+                    }
+                ]
+            }
+        };
     }
     }
 
 
     /**
     /**

+ 11 - 0
src/core/operations/ParseSSHHostKey.mjs

@@ -38,6 +38,17 @@ class ParseSSHHostKey extends Operation {
                 ]
                 ]
             }
             }
         ];
         ];
+        this.checks = {
+            input: {
+                regex: [
+                    {
+                        match:  "^\\s*([A-F\\d]{2}[,;:]){15,}[A-F\\d]{2}\\s*$",
+                        flags:  "i",
+                        args:   ["Hex"]
+                    }
+                ]
+            }
+        };
     }
     }
 
 
     /**
     /**

+ 11 - 0
src/core/operations/ParseUNIXFilePermissions.mjs

@@ -25,6 +25,17 @@ class ParseUNIXFilePermissions extends Operation {
         this.inputType = "string";
         this.inputType = "string";
         this.outputType = "string";
         this.outputType = "string";
         this.args = [];
         this.args = [];
+        this.checks = {
+            input: {
+                regex: [
+                    {
+                        match:  "^\\s*d[rxw-]{9}\\s*$",
+                        flags:  "",
+                        args:   []
+                    }
+                ]
+            }
+        };
     }
     }
 
 
     /**
     /**

+ 11 - 0
src/core/operations/ParseUserAgent.mjs

@@ -25,6 +25,17 @@ class ParseUserAgent extends Operation {
         this.inputType = "string";
         this.inputType = "string";
         this.outputType = "string";
         this.outputType = "string";
         this.args = [];
         this.args = [];
+        this.checks = {
+            input: {
+                regex: [
+                    {
+                        match:  "^(User-Agent:|Mozilla\\/)[^\\n\\r]+\\s*$",
+                        flags:  "i",
+                        args:   []
+                    }
+                ]
+            }
+        };
     }
     }
 
 
     /**
     /**

+ 9 - 7
src/core/operations/ParseX509Certificate.mjs

@@ -35,15 +35,17 @@ class ParseX509Certificate extends Operation {
                 "value": ["PEM", "DER Hex", "Base64", "Raw"]
                 "value": ["PEM", "DER Hex", "Base64", "Raw"]
             }
             }
         ];
         ];
-        this.patterns = [
-            {
-                "match": "^-+BEGIN CERTIFICATE-+\\r?\\n[\\da-z+/\\n\\r]+-+END CERTIFICATE-+\\r?\\n?$",
-                "flags": "i",
-                "args": [
-                    "PEM"
+        this.checks = {
+            input: {
+                regex: [
+                    {
+                        "match": "^-+BEGIN CERTIFICATE-+\\r?\\n[\\da-z+/\\n\\r]+-+END CERTIFICATE-+\\r?\\n?$",
+                        "flags": "i",
+                        "args": ["PEM"]
+                    }
                 ]
                 ]
             }
             }
-        ];
+        };
     }
     }
 
 
     /**
     /**

+ 9 - 0
src/core/operations/RawInflate.mjs

@@ -8,6 +8,7 @@ import Operation from "../Operation.mjs";
 import {INFLATE_BUFFER_TYPE} from "../lib/Zlib.mjs";
 import {INFLATE_BUFFER_TYPE} from "../lib/Zlib.mjs";
 import rawinflate from "zlibjs/bin/rawinflate.min.js";
 import rawinflate from "zlibjs/bin/rawinflate.min.js";
 import OperationError from "../errors/OperationError.mjs";
 import OperationError from "../errors/OperationError.mjs";
+import * as criteria from "../lib/MagicCriteria.mjs";
 
 
 const Zlib = rawinflate.Zlib;
 const Zlib = rawinflate.Zlib;
 
 
@@ -60,6 +61,14 @@ class RawInflate extends Operation {
                 value: false
                 value: false
             }
             }
         ];
         ];
+        this.checks = {
+            input: {
+                entropy: {
+                    input: [7.5, 8],
+                    args: [0, 0, INFLATE_BUFFER_TYPE, false, false]
+                }
+            }
+        };
     }
     }
 
 
     /**
     /**

+ 1 - 1
src/core/operations/RegularExpression.mjs

@@ -163,7 +163,7 @@ class RegularExpression extends Operation {
                     case "List matches with capture groups":
                     case "List matches with capture groups":
                         return Utils.escapeHtml(regexList(input, regex, displayTotal, true, true));
                         return Utils.escapeHtml(regexList(input, regex, displayTotal, true, true));
                     default:
                     default:
-                        return "Error: Invalid output format";
+                        throw new OperationError("Error: Invalid output format");
                 }
                 }
             } catch (err) {
             } catch (err) {
                 throw new OperationError("Invalid regex. Details: " + err.message);
                 throw new OperationError("Invalid regex. Details: " + err.message);

+ 14 - 7
src/core/operations/RenderImage.mjs

@@ -35,14 +35,21 @@ class RenderImage extends Operation {
                 "value": ["Raw", "Base64", "Hex"]
                 "value": ["Raw", "Base64", "Hex"]
             }
             }
         ];
         ];
-        this.patterns = [
-            {
-                "match": "^(?:\\xff\\xd8\\xff|\\x89\\x50\\x4e\\x47|\\x47\\x49\\x46|.{8}\\x57\\x45\\x42\\x50|\\x42\\x4d)",
-                "flags": "",
-                "args": ["Raw"],
-                "useful": true
+        this.checks = {
+            input: {
+                regex: [
+                    {
+                        "match": "^(?:\\xff\\xd8\\xff|\\x89\\x50\\x4e\\x47|\\x47\\x49\\x46|.{8}\\x57\\x45\\x42\\x50|\\x42\\x4d)",
+                        "flags": "",
+                        "args": ["Raw"],
+                        "useful": true
+                    }
+                ]
+            },
+            output: {
+                mime: "image"
             }
             }
-        ];
+        };
     }
     }
 
 
     /**
     /**

+ 11 - 0
src/core/operations/StripHTMLTags.mjs

@@ -35,6 +35,17 @@ class StripHTMLTags extends Operation {
                 "value": true
                 "value": true
             }
             }
         ];
         ];
+        this.checks = {
+            input: {
+                regex: [
+                    {
+                        match:  "^<html>(\\S|\\s)*</html>$",
+                        flags:  "i",
+                        args:   [true, true]
+                    }
+                ]
+            }
+        };
     }
     }
 
 
     /**
     /**

+ 11 - 0
src/core/operations/StripHTTPHeaders.mjs

@@ -24,6 +24,17 @@ class StripHTTPHeaders extends Operation {
         this.inputType = "string";
         this.inputType = "string";
         this.outputType = "string";
         this.outputType = "string";
         this.args = [];
         this.args = [];
+        this.checks = {
+            input: {
+                regex: [
+                    {
+                        match:  "^\\s*HTTP(.|\\s)+?(\\r?\\n){2}",
+                        flags:  "",
+                        args:   []
+                    }
+                ]
+            }
+        };
     }
     }
 
 
     /**
     /**

+ 11 - 7
src/core/operations/URLDecode.mjs

@@ -24,13 +24,17 @@ class URLDecode extends Operation {
         this.inputType = "string";
         this.inputType = "string";
         this.outputType = "string";
         this.outputType = "string";
         this.args = [];
         this.args = [];
-        this.patterns = [
-            {
-                match: ".*(?:%[\\da-f]{2}.*){4}",
-                flags: "i",
-                args: []
-            },
-        ];
+        this.checks = {
+            input: {
+                regex: [
+                    {
+                        match: ".*(?:%[\\da-f]{2}.*){4}",
+                        flags: "i",
+                        args: []
+                    },
+                ]
+            }
+        };
     }
     }
 
 
     /**
     /**

+ 10 - 6
src/core/operations/Untar.mjs

@@ -27,13 +27,17 @@ class Untar extends Operation {
         this.outputType = "List<File>";
         this.outputType = "List<File>";
         this.presentType = "html";
         this.presentType = "html";
         this.args = [];
         this.args = [];
-        this.patterns = [
-            {
-                "match": "^.{257}\\x75\\x73\\x74\\x61\\x72",
-                "flags": "",
-                "args": []
+        this.checks = {
+            input: {
+                regex: [
+                    {
+                        "match": "^.{257}\\x75\\x73\\x74\\x61\\x72",
+                        "flags": "",
+                        "args": []
+                    }
+                ]
             }
             }
-        ];
+        };
     }
     }
 
 
     /**
     /**

+ 11 - 7
src/core/operations/Unzip.mjs

@@ -40,13 +40,17 @@ class Unzip extends Operation {
                 value: false
                 value: false
             }
             }
         ];
         ];
-        this.patterns = [
-            {
-                match: "^\\x50\\x4b(?:\\x03|\\x05|\\x07)(?:\\x04|\\x06|\\x08)",
-                flags: "",
-                args: ["", false]
-            },
-        ];
+        this.checks = {
+            input: {
+                regex: [
+                    {
+                        match: "^\\x50\\x4b(?:\\x03|\\x05|\\x07)(?:\\x04|\\x06|\\x08)",
+                        flags: "",
+                        args: ["", false]
+                    }
+                ]
+            }
+        };
     }
     }
 
 
     /**
     /**

+ 11 - 7
src/core/operations/ZlibInflate.mjs

@@ -59,13 +59,17 @@ class ZlibInflate extends Operation {
                 value: false
                 value: false
             }
             }
         ];
         ];
-        this.patterns = [
-            {
-                match: "^\\x78(\\x01|\\x9c|\\xda|\\x5e)",
-                flags: "",
-                args: [0, 0, "Adaptive", false, false]
-            },
-        ];
+        this.checks = {
+            input: {
+                regex: [
+                    {
+                        match: "^\\x78(\\x01|\\x9c|\\xda|\\x5e)",
+                        flags: "",
+                        args: [0, 0, "Adaptive", false, false]
+                    },
+                ]
+            }
+        };
     }
     }
 
 
     /**
     /**