Quellcode durchsuchen

Tidied up the Magic operation

n1474335 vor 5 Jahren
Ursprung
Commit
b765534b8b
43 geänderte Dateien mit 632 neuen und 820 gelöschten Zeilen
  1. 1 23
      src/core/config/scripts/generateConfig.mjs
  2. 104 123
      src/core/lib/Magic.mjs
  3. 0 12
      src/core/lib/MagicCriteria.mjs
  4. 31 35
      src/core/operations/A1Z26CipherDecode.mjs
  5. 41 45
      src/core/operations/BaconCipherDecode.mjs
  6. 6 10
      src/core/operations/Bzip2Decompress.mjs
  7. 6 10
      src/core/operations/DechunkHTTPResponse.mjs
  8. 6 10
      src/core/operations/DecodeNetBIOSName.mjs
  9. 10 20
      src/core/operations/DefangIPAddresses.mjs
  10. 16 20
      src/core/operations/EscapeUnicodeCharacters.mjs
  11. 7 11
      src/core/operations/FromBCD.mjs
  12. 5 10
      src/core/operations/FromBase32.mjs
  13. 11 16
      src/core/operations/FromBase58.mjs
  14. 67 71
      src/core/operations/FromBase64.mjs
  15. 37 41
      src/core/operations/FromBinary.mjs
  16. 31 35
      src/core/operations/FromDecimal.mjs
  17. 6 10
      src/core/operations/FromHTMLEntity.mjs
  18. 51 55
      src/core/operations/FromHex.mjs
  19. 6 10
      src/core/operations/FromHexContent.mjs
  20. 7 11
      src/core/operations/FromHexdump.mjs
  21. 6 10
      src/core/operations/FromMorseCode.mjs
  22. 31 35
      src/core/operations/FromOctal.mjs
  23. 7 11
      src/core/operations/FromQuotedPrintable.mjs
  24. 21 25
      src/core/operations/FromUNIXTimestamp.mjs
  25. 6 10
      src/core/operations/Gunzip.mjs
  26. 0 11
      src/core/operations/ObjectIdentifierToHex.mjs
  27. 7 11
      src/core/operations/ParseQRCode.mjs
  28. 6 10
      src/core/operations/ParseSSHHostKey.mjs
  29. 6 10
      src/core/operations/ParseUNIXFilePermissions.mjs
  30. 6 10
      src/core/operations/ParseUserAgent.mjs
  31. 6 10
      src/core/operations/ParseX509Certificate.mjs
  32. 5 7
      src/core/operations/RawInflate.mjs
  33. 10 14
      src/core/operations/RenderImage.mjs
  34. 6 10
      src/core/operations/StripHTMLTags.mjs
  35. 6 10
      src/core/operations/StripHTTPHeaders.mjs
  36. 7 11
      src/core/operations/URLDecode.mjs
  37. 6 10
      src/core/operations/Untar.mjs
  38. 6 10
      src/core/operations/Unzip.mjs
  39. 7 11
      src/core/operations/ZlibInflate.mjs
  40. 5 1
      tests/lib/TestRegister.mjs
  41. 18 0
      tests/operations/samples/Images.mjs
  42. 2 1
      tests/operations/tests/Image.mjs
  43. 3 4
      tests/operations/tests/Magic.mjs

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

@@ -43,31 +43,9 @@ for (const opObj in Ops) {
         flowControl: op.flowControl,
         manualBake:  op.manualBake,
         args:        op.args,
+        checks:      op.checks
     };
 
-    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))
         modules[op.module] = {};
     modules[op.module][op.name] = opObj;

+ 104 - 123
src/core/lib/Magic.mjs

@@ -19,68 +19,42 @@ class Magic {
      * Magic constructor.
      *
      * @param {ArrayBuffer} buf
-     * @param {Object} prevOp
+     * @param {Object[]} [opCriteria]
+     * @param {Object} [prevOp]
      */
-    constructor(buf, opPatterns, prevOp) {
+    constructor(buf, opCriteria=Magic._generateOpCriteria(), prevOp=null) {
         this.inputBuffer = new Uint8Array(buf);
         this.inputStr = Utils.arrayBufferToStr(buf);
-        this.opPatterns = opPatterns || Magic._generateOpCriteria();
+        this.opCriteria = opCriteria;
         this.prevOp = prevOp;
     }
 
     /**
-     * Finds operations that claim to be able to decode the input based on
-     * regular expression matches.
+     * Finds operations that claim to be able to decode the input based on various criteria.
      *
-     * @param {[Object]} opPatterns
-     * @returns {Array}
-     */
-    inputRegexMatch(opPatterns) {
-        const matches = [];
-
-        for (let i = 0; i < opPatterns.length; i++) {
-            const pattern = opPatterns[i];
-
-
-            if (pattern.match.test(this.inputStr)) {
-                matches.push(pattern);
-            }
-        }
-
-        return matches;
-    }
-
-    /**
-     * Finds operations that claim to be able to decode the input based on entropy
-     * matches.
-     *
-     * @param {[Object]} opPatterns
-     * @returns {Array}
+     * @returns {Object[]}
      */
-    entropyInputMatch(opPatterns) {
-        const matches = [];
+    findMatchingInputOps() {
+        const matches = [],
+            inputEntropy = this.calcEntropy();
+
+        this.opCriteria.forEach(check => {
+            // If the input doesn't lie in the required entropy range, move on
+            if (check.entropyRange &&
+                (inputEntropy < check.entropyRange[0] ||
+                inputEntropy > check.entropyRange[1]))
+                return;
+            // If the input doesn't match the pattern, move on
+            if (check.pattern &&
+                !check.pattern.test(this.inputStr))
+                return;
 
-        const entropyOfInput = this.calcEntropy();
+            matches.push(check);
+        });
 
-        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 criteria.
-     *
-     * @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
      * to that of several known languages.
@@ -218,8 +192,10 @@ class Magic {
      *
      * @returns {number}
      */
-    calcEntropy() {
-        const prob = this._freqDist();
+    calcEntropy(data=this.inputBuffer, standalone=false) {
+        if (!standalone && this.inputEntropy) return this.inputEntropy;
+
+        const prob = this._freqDist(data, standalone);
         let entropy = 0,
             p;
 
@@ -228,6 +204,8 @@ class Magic {
             if (p === 0) continue;
             entropy += p * Math.log(p) / Math.log(2);
         }
+
+        if (!standalone) this.inputEntropy = -entropy;
         return -entropy;
     }
 
@@ -298,32 +276,29 @@ class Magic {
     }
 
     /**
+     * Checks whether the data passes output criteria for an operation check
      *
+     * @param {ArrayBuffer} data
+     * @param {Object} criteria
+     * @returns {boolean}
      */
-    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++;
+    outputCheckPasses(data, criteria) {
+        if (criteria.pattern) {
+            const dataStr = Utils.arrayBufferToStr(data),
+                regex = new RegExp(criteria.pattern, criteria.flags);
+            if (!regex.test(dataStr))
+                return false;
         }
-        if ("mime" in this.prevOp.output) {
-            if (isType(this.prevOp.output.mime, this.inputBuffer)) score++;
+        if (criteria.entropyRange) {
+            const dataEntropy = this.calcEntropy(data, true);
+            if (dataEntropy < criteria.entropyRange[0] || dataEntropy > criteria.entropyRange[1])
+                return false;
         }
-        return score > 0;
+        if (criteria.mime &&
+            !isType(criteria.mime, data))
+            return false;
+
+        return true;
     }
 
     /**
@@ -331,26 +306,27 @@ class Magic {
      *
      * @param {number} [depth=0] - How many levels to try to execute
      * @param {boolean} [extLang=false] - Extensive language support (false = only check the most
-     *                                    common Internet languages)
+     *     common Internet languages)
      * @param {boolean} [intensive=false] - Run brute-forcing on each branch (significantly affects
-     *                                      performance)
+     *     performance)
      * @param {Object[]} [recipeConfig=[]] - The recipe configuration up to this point
      * @param {boolean} [useful=false] - Whether the current recipe should be scored highly
-     * @param {string} [crib=null] - The regex crib provided by the user, for filtering the operation output
+     * @param {string} [crib=null] - The regex crib provided by the user, for filtering the operation
+     *     output
      * @returns {Object[]} - A sorted list of the recipes most likely to result in correct decoding
      */
-    async speculativeExecution(depth=0, extLang=false, intensive=false, recipeConfig=[], useful=false, crib=null) {
+    async speculativeExecution(
+        depth=0,
+        extLang=false,
+        intensive=false,
+        recipeConfig=[],
+        useful=false,
+        crib=null) {
+
+        // If we have reached the recursion depth, return
         if (depth < 0) return [];
 
         // Find any operations that can be run on this data
-
-        if (this.prevOp) {
-            if ("output" in this.prevOp) {
-                if (!(this.checkOutputFromPrevious())) {
-                    return [];
-                }
-            }
-        }
         const matchingOps = this.findMatchingInputOps();
         let results = [];
 
@@ -374,20 +350,24 @@ class Magic {
             const opConfig = {
                     op: op.op,
                     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 (prevOp && op.op === prevOp.op && _buffersEqual(output, this.inputBuffer)) {
+            // If the recipe returned an empty buffer, do not continue
+            if (_buffersEqual(output, new ArrayBuffer())) {
                 return;
             }
 
-            // If the recipe returned an empty buffer, do not continue
-            if (_buffersEqual(output, new ArrayBuffer())) {
+            // If the recipe is repeating and returning the same data, do not continue
+            if (prevOp && op.op === prevOp.op && _buffersEqual(output, this.inputBuffer)) {
                 return;
             }
 
+            // If the output criteria for this op doesn't match the output, do not continue
+            if (op.output && !this.outputCheckPasses(output, op.output))
+                return;
 
-            const magic = new Magic(output, this.opPatterns, OperationConfig[op.op]),
+            const magic = new Magic(output, this.opCriteria, OperationConfig[op.op]),
                 speculativeResults = await magic.speculativeExecution(
                     depth-1, extLang, intensive, [...recipeConfig, opConfig], op.useful, crib);
 
@@ -399,7 +379,7 @@ class Magic {
             const bfEncodings = await this.bruteForce();
 
             await Promise.all(bfEncodings.map(async enc => {
-                const magic = new Magic(enc.data, this.opPatterns, undefined),
+                const magic = new Magic(enc.data, this.opCriteria, undefined),
                     bfResults = await magic.speculativeExecution(
                         depth-1, extLang, false, [...recipeConfig, enc.conf], false, crib);
 
@@ -414,7 +394,8 @@ class Magic {
                 r.languageScores[0].probability > 0 ||    // Some kind of language was found
                 r.fileType ||                             // A file was found
                 r.isUTF8 ||                               // UTF-8 was found
-                r.matchingOps.length                      // A matching op was found
+                r.matchingOps.length ||                   // A matching op was found
+                r.matchesCrib                             // The crib matches
             )
         );
 
@@ -445,9 +426,10 @@ class Magic {
             bScore += b.entropy;
 
             // A result with no recipe but matching ops suggests there are better options
-            if ((!a.recipe.length && a.matchingOps.length) &&
-                b.recipe.length)
+            if ((!a.recipe.length && a.matchingOps.length) && b.recipe.length)
                 return 1;
+            if ((!b.recipe.length && b.matchingOps.length) && a.recipe.length)
+                return -1;
 
             return aScore - bScore;
         });
@@ -486,14 +468,16 @@ class Magic {
      * Calculates the number of times each byte appears in the input as a percentage
      *
      * @private
+     * @param {ArrayBuffer} [data]
+     * @param {boolean} [standalone]
      * @returns {number[]}
      */
-    _freqDist() {
-        if (this.freqDist) return this.freqDist;
+    _freqDist(data=this.inputBuffer, standalone=false) {
+        if (!standalone && this.freqDist) return this.freqDist;
 
-        const len = this.inputBuffer.length;
+        const len = data.length,
+            counts = new Array(256).fill(0);
         let i = len;
-        const counts = new Array(256).fill(0);
 
         if (!len) {
             this.freqDist = counts;
@@ -501,13 +485,15 @@ class Magic {
         }
 
         while (i--) {
-            counts[this.inputBuffer[i]]++;
+            counts[data[i]]++;
         }
 
-        this.freqDist = counts.map(c => {
+        const result = counts.map(c => {
             return c / len * 100;
         });
-        return this.freqDist;
+
+        if (!standalone) this.freqDist = result;
+        return result;
     }
 
     /**
@@ -517,30 +503,25 @@ class Magic {
      * @returns {Object[]}
      */
     static _generateOpCriteria() {
-        const opCriteria = {
-            regex: [],
-            entropy: []
-        };
+        const opCriteria = [];
 
         for (const op in OperationConfig) {
-            if ("input" in OperationConfig[op]) {
-                if ("regex" in OperationConfig[op].input)
-                    OperationConfig[op].input.regex.forEach(pattern => {
-                        opCriteria.regex.push({
-                            op: op,
-                            match: new RegExp(pattern.match, 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
-                    });
-                }
-            }
+            if (!("checks" in OperationConfig[op]))
+                continue;
+
+            OperationConfig[op].checks.forEach(check => {
+                // Add to the opCriteria list.
+                // Compile the regex here and cache the compiled version so we
+                // don't have to keep calculating it.
+                opCriteria.push({
+                    op: op,
+                    pattern: check.pattern ? new RegExp(check.pattern, check.flags) : null,
+                    args: check.args,
+                    useful: check.useful,
+                    entropyRange: check.entropyRange,
+                    output: check.output
+                });
+            });
         }
 
         return opCriteria;

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

@@ -1,12 +0,0 @@
-/**
- * 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];

+ 31 - 35
src/core/operations/A1Z26CipherDecode.mjs

@@ -33,42 +33,38 @@ class A1Z26CipherDecode extends Operation {
                 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"]
-                    }
-                ]
+        this.checks = [
+            {
+                pattern:  "^\\s*([12]?[0-9] )+[12]?[0-9]\\s*$",
+                flags:  "",
+                args:   ["Space"]
+            },
+            {
+                pattern:  "^\\s*([12]?[0-9],)+[12]?[0-9]\\s*$",
+                flags:  "",
+                args:   ["Comma"]
+            },
+            {
+                pattern:  "^\\s*([12]?[0-9];)+[12]?[0-9]\\s*$",
+                flags:  "",
+                args:   ["Semi-colon"]
+            },
+            {
+                pattern:  "^\\s*([12]?[0-9]:)+[12]?[0-9]\\s*$",
+                flags:  "",
+                args:   ["Colon"]
+            },
+            {
+                pattern:  "^\\s*([12]?[0-9]\\n)+[12]?[0-9]\\s*$",
+                flags:  "",
+                args:   ["Line feed"]
+            },
+            {
+                pattern:  "^\\s*([12]?[0-9]\\r\\n)+[12]?[0-9]\\s*$",
+                flags:  "",
+                args:   ["CRLF"]
             }
-        };
+        ];
     }
 
     /**

+ 41 - 45
src/core/operations/BaconCipherDecode.mjs

@@ -44,52 +44,48 @@ class BaconCipherDecode extends Operation {
                 "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]
-                    }
-                ]
+        this.checks = [
+            {
+                pattern:  "^\\s*([01]{5}\\s?)+$",
+                flags:  "",
+                args:   ["Standard (I=J and U=V)", "0/1", false]
+            },
+            {
+                pattern:  "^\\s*([01]{5}\\s?)+$",
+                flags:  "",
+                args:   ["Standard (I=J and U=V)", "0/1", true]
+            },
+            {
+                pattern:  "^\\s*([AB]{5}\\s?)+$",
+                flags:  "",
+                args:   ["Standard (I=J and U=V)", "A/B", false]
+            },
+            {
+                pattern:  "^\\s*([AB]{5}\\s?)+$",
+                flags:  "",
+                args:   ["Standard (I=J and U=V)", "A/B", true]
+            },
+            {
+                pattern:  "^\\s*([01]{5}\\s?)+$",
+                flags:  "",
+                args:   ["Complete", "0/1", false]
+            },
+            {
+                pattern:  "^\\s*([01]{5}\\s?)+$",
+                flags:  "",
+                args:   ["Complete", "0/1", true]
+            },
+            {
+                pattern:  "^\\s*([AB]{5}\\s?)+$",
+                flags:  "",
+                args:   ["Complete", "A/B", false]
+            },
+            {
+                pattern:  "^\\s*([AB]{5}\\s?)+$",
+                flags:  "",
+                args:   ["Complete", "A/B", true]
             }
-        };
+        ];
     }
 
     /**

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

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

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

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

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

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

+ 10 - 20
src/core/operations/DefangIPAddresses.mjs

@@ -25,27 +25,17 @@ class DefangIPAddresses extends Operation {
         this.inputType = "string";
         this.outputType = "string";
         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: []
-                    }
-                ]
+        this.checks = [
+            {
+                pattern: "^\\s*(([0-9]{1,3}\\.){3}[0-9]{1,3}|([0-9a-f]{4}:){7}[0-9a-f]{4})\\s*$",
+                flags: "i",
+                args: [],
+                output: {
+                    pattern: "^\\s*(([0-9]{1,3}\\[\\.\\]){3}[0-9]{1,3}|([0-9a-f]{4}\\[\\:\\]){7}[0-9a-f]{4})\\s*$",
+                    flags: "i"
+                }
             }
-        };
+        ];
     }
 
     /**

+ 16 - 20
src/core/operations/EscapeUnicodeCharacters.mjs

@@ -44,27 +44,23 @@ class EscapeUnicodeCharacters extends Operation {
                 "value": true
             }
         ];
-        this.checks = {
-            input: {
-                regex: [
-                    {
-                        match: "\\\\u(?:[\\da-f]{4,6})",
-                        flags: "i",
-                        args: ["\\u"]
-                    },
-                    {
-                        match: "%u(?:[\\da-f]{4,6})",
-                        flags: "i",
-                        args: ["%u"]
-                    },
-                    {
-                        match: "U\\+(?:[\\da-f]{4,6})",
-                        flags: "i",
-                        args: ["U+"]
-                    }
-                ]
+        this.checks = [
+            {
+                pattern: "\\\\u(?:[\\da-f]{4,6})",
+                flags: "i",
+                args: ["\\u"]
+            },
+            {
+                pattern: "%u(?:[\\da-f]{4,6})",
+                flags: "i",
+                args: ["%u"]
+            },
+            {
+                pattern: "U\\+(?:[\\da-f]{4,6})",
+                flags: "i",
+                args: ["U+"]
             }
-        };
+        ];
     }
 
     /**

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

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

+ 5 - 10
src/core/operations/FromBase32.mjs

@@ -36,18 +36,13 @@ class FromBase32 extends Operation {
                 value: true
             }
         ];
-        this.checks = {
-            input:
+        this.checks = [
             {
-                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]
-                    }
-                ]
+                pattern: "^(?:[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]
             }
-        };
+        ];
     }
 
     /**

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

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

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

@@ -36,77 +36,73 @@ class FromBase64 extends Operation {
                 value: 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]
-                    },
-                ],
-            }
-        };
+        this.checks = [
+            {
+                pattern: "^\\s*(?:[A-Z\\d+/]{4})+(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
+                flags: "i",
+                args: ["A-Za-z0-9+/=", true]
+            },
+            {
+                pattern: "^\\s*[A-Z\\d\\-_]{20,}\\s*$",
+                flags: "i",
+                args: ["A-Za-z0-9-_", true]
+            },
+            {
+                pattern: "^\\s*(?:[A-Z\\d+\\-]{4}){5,}(?:[A-Z\\d+\\-]{2}==|[A-Z\\d+\\-]{3}=)?\\s*$",
+                flags: "i",
+                args: ["A-Za-z0-9+\\-=", true]
+            },
+            {
+                pattern: "^\\s*(?:[A-Z\\d./]{4}){5,}(?:[A-Z\\d./]{2}==|[A-Z\\d./]{3}=)?\\s*$",
+                flags: "i",
+                args: ["./0-9A-Za-z=", true]
+            },
+            {
+                pattern: "^\\s*[A-Z\\d_.]{20,}\\s*$",
+                flags: "i",
+                args: ["A-Za-z0-9_.", true]
+            },
+            {
+                pattern: "^\\s*(?:[A-Z\\d._]{4}){5,}(?:[A-Z\\d._]{2}--|[A-Z\\d._]{3}-)?\\s*$",
+                flags: "i",
+                args: ["A-Za-z0-9._-", true]
+            },
+            {
+                pattern: "^\\s*(?:[A-Z\\d+/]{4}){5,}(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
+                flags: "i",
+                args: ["0-9a-zA-Z+/=", true]
+            },
+            {
+                pattern: "^\\s*(?:[A-Z\\d+/]{4}){5,}(?:[A-Z\\d+/]{2}==|[A-Z\\d+/]{3}=)?\\s*$",
+                flags: "i",
+                args: ["0-9A-Za-z+/=", true]
+            },
+            {
+                pattern: "^[ !\"#$%&'()*+,\\-./\\d:;<=>?@A-Z[\\\\\\]^_]{20,}$",
+                flags: "",
+                args: [" -_", false]
+            },
+            {
+                pattern: "^\\s*[A-Z\\d+\\-]{20,}\\s*$",
+                flags: "i",
+                args: ["+\\-0-9A-Za-z", true]
+            },
+            {
+                pattern: "^\\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]
+            },
+            {
+                pattern: "^\\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]
+            },
+            {
+                pattern: "^\\s*[A-Z\\d./]{20,}\\s*$",
+                flags: "i",
+                args: ["./0-9A-Za-z", true]
+            },
+        ];
     }
 
     /**

+ 37 - 41
src/core/operations/FromBinary.mjs

@@ -33,47 +33,43 @@ class FromBinary extends Operation {
                 "value": BIN_DELIM_OPTIONS
             }
         ];
-        this.checks = {
-            input: {
-                regex: [
-                    {
-                        match: "^(?:[01]{8})+$",
-                        flags: "",
-                        args: ["None"]
-                    },
-                    {
-                        match: "^(?:[01]{8})(?: [01]{8})*$",
-                        flags: "",
-                        args: ["Space"]
-                    },
-                    {
-                        match: "^(?:[01]{8})(?:,[01]{8})*$",
-                        flags: "",
-                        args: ["Comma"]
-                    },
-                    {
-                        match: "^(?:[01]{8})(?:;[01]{8})*$",
-                        flags: "",
-                        args: ["Semi-colon"]
-                    },
-                    {
-                        match: "^(?:[01]{8})(?::[01]{8})*$",
-                        flags: "",
-                        args: ["Colon"]
-                    },
-                    {
-                        match: "^(?:[01]{8})(?:\\n[01]{8})*$",
-                        flags: "",
-                        args: ["Line feed"]
-                    },
-                    {
-                        match: "^(?:[01]{8})(?:\\r\\n[01]{8})*$",
-                        flags: "",
-                        args: ["CRLF"]
-                    },
-                ]
-            }
-        };
+        this.checks = [
+            {
+                pattern: "^(?:[01]{8})+$",
+                flags: "",
+                args: ["None"]
+            },
+            {
+                pattern: "^(?:[01]{8})(?: [01]{8})*$",
+                flags: "",
+                args: ["Space"]
+            },
+            {
+                pattern: "^(?:[01]{8})(?:,[01]{8})*$",
+                flags: "",
+                args: ["Comma"]
+            },
+            {
+                pattern: "^(?:[01]{8})(?:;[01]{8})*$",
+                flags: "",
+                args: ["Semi-colon"]
+            },
+            {
+                pattern: "^(?:[01]{8})(?::[01]{8})*$",
+                flags: "",
+                args: ["Colon"]
+            },
+            {
+                pattern: "^(?:[01]{8})(?:\\n[01]{8})*$",
+                flags: "",
+                args: ["Line feed"]
+            },
+            {
+                pattern: "^(?:[01]{8})(?:\\r\\n[01]{8})*$",
+                flags: "",
+                args: ["CRLF"]
+            },
+        ];
     }
 
     /**

+ 31 - 35
src/core/operations/FromDecimal.mjs

@@ -36,42 +36,38 @@ class FromDecimal extends Operation {
                 "value": 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]
-                    }
-                ]
+        this.checks = [
+            {
+                pattern: "^(?:\\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]
+            },
+            {
+                pattern: "^(?:\\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]
+            },
+            {
+                pattern: "^(?:\\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]
+            },
+            {
+                pattern: "^(?:\\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]
+            },
+            {
+                pattern: "^(?:\\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]
+            },
+            {
+                pattern: "^(?:\\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]
             }
-        };
+        ];
     }
 
     /**

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

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

+ 51 - 55
src/core/operations/FromHex.mjs

@@ -32,62 +32,58 @@ class FromHex extends Operation {
                 value: FROM_HEX_DELIM_OPTIONS
             }
         ];
-        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: "^(?:0x[\\dA-F]{2})+$",
-                        flags: "i",
-                        args: ["0x"]
-                    },
-                    {
-                        match: "^0x[\\dA-F]{2}(?:,0x[\\dA-F]{2})*$",
-                        flags: "i",
-                        args: ["0x with comma"]
-                    },
-                    {
-                        match: "^(?:\\\\x[\\dA-F]{2})+$",
-                        flags: "i",
-                        args: ["\\x"]
-                    }
-                ]
+        this.checks = [
+            {
+                pattern: "^(?:[\\dA-F]{2})+$",
+                flags: "i",
+                args: ["None"]
+            },
+            {
+                pattern: "^[\\dA-F]{2}(?: [\\dA-F]{2})*$",
+                flags: "i",
+                args: ["Space"]
+            },
+            {
+                pattern: "^[\\dA-F]{2}(?:,[\\dA-F]{2})*$",
+                flags: "i",
+                args: ["Comma"]
+            },
+            {
+                pattern: "^[\\dA-F]{2}(?:;[\\dA-F]{2})*$",
+                flags: "i",
+                args: ["Semi-colon"]
+            },
+            {
+                pattern: "^[\\dA-F]{2}(?::[\\dA-F]{2})*$",
+                flags: "i",
+                args: ["Colon"]
+            },
+            {
+                pattern: "^[\\dA-F]{2}(?:\\n[\\dA-F]{2})*$",
+                flags: "i",
+                args: ["Line feed"]
+            },
+            {
+                pattern: "^[\\dA-F]{2}(?:\\r\\n[\\dA-F]{2})*$",
+                flags: "i",
+                args: ["CRLF"]
+            },
+            {
+                pattern: "^(?:0x[\\dA-F]{2})+$",
+                flags: "i",
+                args: ["0x"]
+            },
+            {
+                pattern: "^0x[\\dA-F]{2}(?:,0x[\\dA-F]{2})*$",
+                flags: "i",
+                args: ["0x with comma"]
+            },
+            {
+                pattern: "^(?:\\\\x[\\dA-F]{2})+$",
+                flags: "i",
+                args: ["\\x"]
             }
-        };
+        ];
     }
 
     /**

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

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

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

@@ -27,17 +27,13 @@ class FromHexdump extends Operation {
         this.inputType = "string";
         this.outputType = "byteArray";
         this.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: []
-                    },
-                ]
-            }
-        };
+        this.checks = [
+            {
+                pattern: "^(?:(?:[\\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: []
+            },
+        ];
     }
 
     /**

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

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

+ 31 - 35
src/core/operations/FromOctal.mjs

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

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

@@ -28,17 +28,13 @@ class FromQuotedPrintable extends Operation {
         this.inputType = "string";
         this.outputType = "byteArray";
         this.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: []
-                    },
-                ]
-            }
-        };
+        this.checks = [
+            {
+                pattern: "^[\\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: []
+            },
+        ];
     }
 
     /**

+ 21 - 25
src/core/operations/FromUNIXTimestamp.mjs

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

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

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

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

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

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

@@ -33,18 +33,14 @@ class ParseQRCode extends Operation {
                 "value": false
             }
         ];
-        this.checks = {
-            input: {
-                regex: [
-                    {
-                        "match": "^(?:\\xff\\xd8\\xff|\\x89\\x50\\x4e\\x47|\\x47\\x49\\x46|.{8}\\x57\\x45\\x42\\x50|\\x42\\x4d)",
-                        "flags": "",
-                        "args": [false],
-                        "useful": true
-                    }
-                ]
+        this.checks = [
+            {
+                "pattern": "^(?:\\xff\\xd8\\xff|\\x89\\x50\\x4e\\x47|\\x47\\x49\\x46|.{8}\\x57\\x45\\x42\\x50|\\x42\\x4d)",
+                "flags": "",
+                "args": [false],
+                "useful": true
             }
-        };
+        ];
     }
 
     /**

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

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

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

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

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

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

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

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

+ 5 - 7
src/core/operations/RawInflate.mjs

@@ -60,14 +60,12 @@ class RawInflate extends Operation {
                 value: false
             }
         ];
-        this.checks = {
-            input: {
-                entropy: {
-                    input: [7.5, 8],
-                    args: [0, 0, INFLATE_BUFFER_TYPE, false, false]
-                }
+        this.checks = [
+            {
+                entropyRange: [7.5, 8],
+                args: [0, 0, INFLATE_BUFFER_TYPE, false, false]
             }
-        };
+        ];
     }
 
     /**

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

@@ -35,21 +35,17 @@ class RenderImage extends Operation {
                 "value": ["Raw", "Base64", "Hex"]
             }
         ];
-        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"
+        this.checks = [
+            {
+                pattern: "^(?:\\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"
+                }
             }
-        };
+        ];
     }
 
     /**

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

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

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

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

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

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

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

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

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

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

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

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

+ 5 - 1
tests/lib/TestRegister.mjs

@@ -97,10 +97,14 @@ class TestRegister {
                     ret.status = "passing";
                 } else if ("expectedMatch" in test && test.expectedMatch.test(result.result)) {
                     ret.status = "passing";
+                } else if ("unexpectedMatch" in test && !test.unexpectedMatch.test(result.result)) {
+                    ret.status = "passing";
                 } else {
                     ret.status = "failing";
                     const expected = test.expectedOutput ? test.expectedOutput :
-                        test.expectedMatch ? test.expectedMatch.toString() : "unknown";
+                        test.expectedMatch ? test.expectedMatch.toString() :
+                            test.unexpectedMatch ? "to not find " + test.unexpectedMatch.toString() :
+                                "unknown";
                     ret.output = [
                         "Expected",
                         "\t" + expected.replace(/\n/g, "\n\t"),

Datei-Diff unterdrückt, da er zu groß ist
+ 18 - 0
tests/operations/samples/Images.mjs


Datei-Diff unterdrückt, da er zu groß ist
+ 2 - 1
tests/operations/tests/Image.mjs


Datei-Diff unterdrückt, da er zu groß ist
+ 3 - 4
tests/operations/tests/Magic.mjs


Einige Dateien werden nicht angezeigt, da zu viele Dateien in diesem Diff geändert wurden.