From edd22372d80663bf91f70b42ea95421b45328104 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C4=B0lteri=C5=9F=20Ya=C4=9F=C4=B1ztegin=20Ero=C4=9Flu?= Date: Mon, 17 Jun 2024 23:55:59 +0000 Subject: [PATCH 01/18] feat(Modhex): Introduce basic Modhex conversion MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: İlteriş Yağıztegin Eroğlu --- src/core/config/Categories.json | 4 +- src/core/lib/Modhex.mjs | 165 +++++++++++++++++++++++++++++ src/core/operations/FromModhex.mjs | 84 +++++++++++++++ src/core/operations/ToModhex.mjs | 55 ++++++++++ tests/operations/index.mjs | 1 + tests/operations/tests/Modhex.mjs | 150 ++++++++++++++++++++++++++ 6 files changed, 458 insertions(+), 1 deletion(-) create mode 100644 src/core/lib/Modhex.mjs create mode 100644 src/core/operations/FromModhex.mjs create mode 100644 src/core/operations/ToModhex.mjs create mode 100644 tests/operations/tests/Modhex.mjs diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index bebdd6a5..34d3bfc8 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -74,7 +74,9 @@ "CBOR Decode", "Caret/M-decode", "Rison Encode", - "Rison Decode" + "Rison Decode", + "To Modhex", + "From Modhex" ] }, { diff --git a/src/core/lib/Modhex.mjs b/src/core/lib/Modhex.mjs new file mode 100644 index 00000000..4f28e9a1 --- /dev/null +++ b/src/core/lib/Modhex.mjs @@ -0,0 +1,165 @@ +/** + * @author linuxgemini [ilteris@asenkron.com.tr] + * @copyright Crown Copyright 2024 + * @license Apache-2.0 + */ + +import Utils from "../Utils.mjs"; +import OperationError from "../errors/OperationError.mjs"; +import { fromHex, toHex } from "./Hex.mjs"; + +/** + * Modhex alphabet. + */ +const MODHEX_ALPHABET = "cbdefghijklnrtuv"; + + +/** + * Modhex alphabet map. + */ +const MODHEX_ALPHABET_MAP = MODHEX_ALPHABET.split(""); + + +/** + * Hex alphabet to substitute Modhex. + */ +const HEX_ALPHABET = "0123456789abcdef"; + + +/** + * Hex alphabet map to substitute Modhex. + */ +const HEX_ALPHABET_MAP = HEX_ALPHABET.split(""); + + +/** + * Convert a byte array into a modhex string. + * + * @param {byteArray|Uint8Array|ArrayBuffer} data + * @param {string} [delim=" "] + * @param {number} [padding=2] + * @returns {string} + * + * @example + * // returns "cl bf bu" + * toModhex([10,20,30]); + * + * // returns "cl:bf:bu" + * toModhex([10,20,30], ":"); + */ +export function toModhex(data, delim=" ", padding=2, extraDelim="", lineSize=0) { + if (!data) return ""; + if (data instanceof ArrayBuffer) data = new Uint8Array(data); + + const regularHexString = toHex(data, "", padding, "", 0); + + let modhexString = ""; + for (const letter of regularHexString.split("")) { + modhexString += MODHEX_ALPHABET_MAP[HEX_ALPHABET_MAP.indexOf(letter)]; + } + + let output = ""; + const groupingRegexp = new RegExp(`.{1,${padding}}`, "g"); + const groupedModhex = modhexString.match(groupingRegexp); + + for (let i = 0; i < groupedModhex.length; i++) { + const group = groupedModhex[i]; + output += group + delim; + + if (extraDelim) { + output += extraDelim; + } + // Add LF after each lineSize amount of bytes but not at the end + if ((i !== groupedModhex.length - 1) && ((i + 1) % lineSize === 0)) { + output += "\n"; + } + } + + // Remove the extraDelim at the end (if there is one) + // and remove the delim at the end, but if it's prepended there's nothing to remove + const rTruncLen = extraDelim.length + delim.length; + if (rTruncLen) { + // If rTruncLen === 0 then output.slice(0,0) will be returned, which is nothing + return output.slice(0, -rTruncLen); + } else { + return output; + } +} + + +/** + * Convert a byte array into a modhex string as efficiently as possible with no options. + * + * @param {byteArray|Uint8Array|ArrayBuffer} data + * @returns {string} + * + * @example + * // returns "clbfbu" + * toModhexFast([10,20,30]); + */ +export function toModhexFast(data) { + if (!data) return ""; + if (data instanceof ArrayBuffer) data = new Uint8Array(data); + + const output = []; + + for (let i = 0; i < data.length; i++) { + output.push(MODHEX_ALPHABET_MAP[(data[i] >> 4) & 0xf]); + output.push(MODHEX_ALPHABET_MAP[data[i] & 0xf]); + } + return output.join(""); +} + + +/** + * Convert a modhex string into a byte array. + * + * @param {string} data + * @param {string} [delim] + * @param {number} [byteLen=2] + * @returns {byteArray} + * + * @example + * // returns [10,20,30] + * fromModhex("cl bf bu"); + * + * // returns [10,20,30] + * fromModhex("cl:bf:bu", "Colon"); + */ +export function fromModhex(data, delim="Auto", byteLen=2) { + if (byteLen < 1 || Math.round(byteLen) !== byteLen) + throw new OperationError("Byte length must be a positive integer"); + + // The `.replace(/\s/g, "")` an interesting workaround: Hex "multiline" tests aren't actually + // multiline. Tests for Modhex fixes that, thus exposing the issue. + data = data.toLowerCase().replace(/\s/g, ""); + + if (delim !== "None") { + const delimRegex = delim === "Auto" ? /[^cbdefghijklnrtuv]/gi : Utils.regexRep(delim); + data = data.split(delimRegex); + } else { + data = [data]; + } + + let regularHexString = ""; + for (let i = 0; i < data.length; i++) { + for (const letter of data[i].split("")) { + regularHexString += HEX_ALPHABET_MAP[MODHEX_ALPHABET_MAP.indexOf(letter)]; + } + } + + const output = fromHex(regularHexString, "None", byteLen); + return output; +} + + +/** + * To Modhex delimiters. + */ +export const TO_MODHEX_DELIM_OPTIONS = ["Space", "Percent", "Comma", "Semi-colon", "Colon", "Line feed", "CRLF", "None"]; + + +/** + * From Modhex delimiters. + */ +export const FROM_MODHEX_DELIM_OPTIONS = ["Auto"].concat(TO_MODHEX_DELIM_OPTIONS); diff --git a/src/core/operations/FromModhex.mjs b/src/core/operations/FromModhex.mjs new file mode 100644 index 00000000..029d95d8 --- /dev/null +++ b/src/core/operations/FromModhex.mjs @@ -0,0 +1,84 @@ +/** + * @author linuxgemini [ilteris@asenkron.com.tr] + * @copyright Crown Copyright 2024 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import { FROM_MODHEX_DELIM_OPTIONS, fromModhex } from "../lib/Modhex.mjs"; + +/** + * From Modhex operation + */ +class FromModhex extends Operation { + + /** + * FromModhex constructor + */ + constructor() { + super(); + + this.name = "From Modhex"; + this.module = "Default"; + this.description = "Converts a modhex byte string back into its raw value."; + this.infoURL = "https://en.wikipedia.org/wiki/YubiKey#ModHex"; + this.inputType = "string"; + this.outputType = "byteArray"; + this.args = [ + { + name: "Delimiter", + type: "option", + value: FROM_MODHEX_DELIM_OPTIONS + } + ]; + this.checks = [ + { + pattern: "^(?:[cbdefghijklnrtuv]{2})+$", + flags: "i", + args: ["None"] + }, + { + pattern: "^[cbdefghijklnrtuv]{2}(?: [cbdefghijklnrtuv]{2})*$", + flags: "i", + args: ["Space"] + }, + { + pattern: "^[cbdefghijklnrtuv]{2}(?:,[cbdefghijklnrtuv]{2})*$", + flags: "i", + args: ["Comma"] + }, + { + pattern: "^[cbdefghijklnrtuv]{2}(?:;[cbdefghijklnrtuv]{2})*$", + flags: "i", + args: ["Semi-colon"] + }, + { + pattern: "^[cbdefghijklnrtuv]{2}(?::[cbdefghijklnrtuv]{2})*$", + flags: "i", + args: ["Colon"] + }, + { + pattern: "^[cbdefghijklnrtuv]{2}(?:\\n[cbdefghijklnrtuv]{2})*$", + flags: "i", + args: ["Line feed"] + }, + { + pattern: "^[cbdefghijklnrtuv]{2}(?:\\r\\n[cbdefghijklnrtuv]{2})*$", + flags: "i", + args: ["CRLF"] + } + ]; + } + + /** + * @param {string} input + * @param {Object[]} args + * @returns {byteArray} + */ + run(input, args) { + const delim = args[0] || "Auto"; + return fromModhex(input, delim, 2); + } +} + +export default FromModhex; diff --git a/src/core/operations/ToModhex.mjs b/src/core/operations/ToModhex.mjs new file mode 100644 index 00000000..6d91fb5d --- /dev/null +++ b/src/core/operations/ToModhex.mjs @@ -0,0 +1,55 @@ +/** + * @author linuxgemini [ilteris@asenkron.com.tr] + * @copyright Crown Copyright 2024 + * @license Apache-2.0 + */ + +import Operation from "../Operation.mjs"; +import { TO_MODHEX_DELIM_OPTIONS, toModhex } from "../lib/Modhex.mjs"; +import Utils from "../Utils.mjs"; + +/** + * To Modhex operation + */ +class ToModhex extends Operation { + + /** + * ToModhex constructor + */ + constructor() { + super(); + + this.name = "To Modhex"; + this.module = "Default"; + this.description = "Converts the input string to modhex bytes separated by the specified delimiter."; + this.infoURL = "https://en.wikipedia.org/wiki/YubiKey#ModHex"; + this.inputType = "ArrayBuffer"; + this.outputType = "string"; + this.args = [ + { + name: "Delimiter", + type: "option", + value: TO_MODHEX_DELIM_OPTIONS + }, + { + name: "Bytes per line", + type: "number", + value: 0 + } + ]; + } + + /** + * @param {ArrayBuffer} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + const delim = Utils.charRep(args[0]); + const lineSize = args[1]; + + return toModhex(new Uint8Array(input), delim, 2, "", lineSize); + } +} + +export default ToModhex; diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs index 40ce7a2e..11e65e66 100644 --- a/tests/operations/index.mjs +++ b/tests/operations/index.mjs @@ -102,6 +102,7 @@ import "./tests/LZNT1Decompress.mjs"; import "./tests/LZString.mjs"; import "./tests/Magic.mjs"; import "./tests/Media.mjs"; +import "./tests/Modhex.mjs"; import "./tests/MorseCode.mjs"; import "./tests/MS.mjs"; import "./tests/MultipleBombe.mjs"; diff --git a/tests/operations/tests/Modhex.mjs b/tests/operations/tests/Modhex.mjs new file mode 100644 index 00000000..1e0f2791 --- /dev/null +++ b/tests/operations/tests/Modhex.mjs @@ -0,0 +1,150 @@ +/** + * Modhex operation tests. + * @author linuxgemini [ilteris@asenkron.com.tr] + * @copyright Crown Copyright 2024 + * @license Apache-2.0 + */ + +import TestRegister from "../../lib/TestRegister.mjs"; + +TestRegister.addTests([ + { + name: "ASCII to Modhex stream", + input: "aberystwyth", + expectedOutput: "hbhdhgidikieifiiikifhj", + recipeConfig: [ + { + "op": "To Modhex", + "args": [ + "None", + 0 + ] + }, + ] + }, + { + name: "ASCII to Modhex with colon deliminator", + input: "aberystwyth", + expectedOutput: "hb:hd:hg:id:ik:ie:if:ii:ik:if:hj", + recipeConfig: [ + { + "op": "To Modhex", + "args": [ + "Colon", + 0 + ] + } + ] + }, + { + name: "Modhex stream to UTF-8", + input: "uhkgkbuhkgkbugltlkugltkc", + expectedOutput: "救救孩子", + recipeConfig: [ + { + "op": "From Modhex", + "args": [ + "Auto" + ] + } + ] + + }, + { + name: "Mixed case Modhex stream to UTF-8", + input: "uhKGkbUHkgkBUGltlkugltkc", + expectedOutput: "救救孩子", + recipeConfig: [ + { + "op": "From Modhex", + "args": [ + "Auto" + ] + } + ] + + }, + { + name: "Mutiline Modhex with comma to ASCII (Auto Mode)", + input: "fk,dc,ie,hb,ii,dc,ht,ik,ie,hg,hr,hh,dc,ie,hk,\n\ +if,if,hk,hu,hi,dc,hk,hu,dc,if,hj,hg,dc,he,id,\n\ +hv,if,he,hj,dc,hv,hh,dc,if,hj,hg,dc,if,hj,hk,\n\ +ie,dc,hh,hk,hi,dc,if,id,hg,hg,dr,dc,ie,if,hb,\n\ +id,ih,hk,hu,hi,dc,if,hv,dc,hf,hg,hb,if,hj,dr,\n\ +dc,hl,ig,ie,if,dc,hd,hg,he,hb,ig,ie,hg,dc,fk,\n\ +dc,he,hv,ig,hr,hf,hu,di,if,dc,ht,hb,hn,hg,dc,\n\ +ig,ic,dc,ht,ik,dc,ht,hk,hu,hf,dc,ii,hj,hk,he,\n\ +hj,dc,hv,hh,dc,if,hj,hg,dc,hh,hk,hi,ie,dc,fk,\n\ +dc,ii,hv,ig,hr,hf,dc,he,hj,hv,hv,ie,hg,du", + expectedOutput: "I saw myself sitting in the crotch of the this fig tree, starving to death, just because I couldn't make up my mind which of the figs I would choose.", + recipeConfig: [ + { + "op": "From Modhex", + "args": [ + "Auto" + ] + } + ] + + }, + { + name: "Mutiline Modhex with percent to ASCII (Percent Mode)", + input: "fk%dc%ie%hb%ii%dc%ht%ik%ie%hg%hr%hh%dc%ie%hk%\n\ +if%if%hk%hu%hi%dc%hk%hu%dc%if%hj%hg%dc%he%id%\n\ +hv%if%he%hj%dc%hv%hh%dc%if%hj%hg%dc%if%hj%hk%\n\ +ie%dc%hh%hk%hi%dc%if%id%hg%hg%dr%dc%ie%if%hb%\n\ +id%ih%hk%hu%hi%dc%if%hv%dc%hf%hg%hb%if%hj%dr%\n\ +dc%hl%ig%ie%if%dc%hd%hg%he%hb%ig%ie%hg%dc%fk%\n\ +dc%he%hv%ig%hr%hf%hu%di%if%dc%ht%hb%hn%hg%dc%\n\ +ig%ic%dc%ht%ik%dc%ht%hk%hu%hf%dc%ii%hj%hk%he%\n\ +hj%dc%hv%hh%dc%if%hj%hg%dc%hh%hk%hi%ie%dc%fk%\n\ +dc%ii%hv%ig%hr%hf%dc%he%hj%hv%hv%ie%hg%du", + expectedOutput: "I saw myself sitting in the crotch of the this fig tree, starving to death, just because I couldn't make up my mind which of the figs I would choose.", + recipeConfig: [ + { + "op": "From Modhex", + "args": [ + "Percent" + ] + } + ] + + }, + { + name: "Mutiline Modhex with semicolon to ASCII (Semi-colon Mode)", + input: "fk;dc;ie;hb;ii;dc;ht;ik;ie;hg;hr;hh;dc;ie;hk;\n\ +if;if;hk;hu;hi;dc;hk;hu;dc;if;hj;hg;dc;he;id;\n\ +hv;if;he;hj;dc;hv;hh;dc;if;hj;hg;dc;if;hj;hk;\n\ +ie;dc;hh;hk;hi;dc;if;id;hg;hg;dr;dc;ie;if;hb;\n\ +id;ih;hk;hu;hi;dc;if;hv;dc;hf;hg;hb;if;hj;dr;\n\ +dc;hl;ig;ie;if;dc;hd;hg;he;hb;ig;ie;hg;dc;fk;\n\ +dc;he;hv;ig;hr;hf;hu;di;if;dc;ht;hb;hn;hg;dc;\n\ +ig;ic;dc;ht;ik;dc;ht;hk;hu;hf;dc;ii;hj;hk;he;\n\ +hj;dc;hv;hh;dc;if;hj;hg;dc;hh;hk;hi;ie;dc;fk;\n\ +dc;ii;hv;ig;hr;hf;dc;he;hj;hv;hv;ie;hg;du", + expectedOutput: "I saw myself sitting in the crotch of the this fig tree, starving to death, just because I couldn't make up my mind which of the figs I would choose.", + recipeConfig: [ + { + "op": "From Modhex", + "args": [ + "Semi-colon" + ] + } + ] + + }, + { + name: "ASCII to Modhex with comma and line breaks", + input: "aberystwyth", + expectedOutput: "hb,hd,hg,id,\nik,ie,if,ii,\nik,if,hj", + recipeConfig: [ + { + "op": "To Modhex", + "args": [ + "Comma", + 4 + ] + } + ] + }, +]); From 7e5eb01a5e09a5bc7f55dff9f6d22f1793635a6c Mon Sep 17 00:00:00 2001 From: Francisco Pombal Date: Sun, 15 Sep 2024 23:51:48 +0100 Subject: [PATCH 02/18] fix: ROT13 - shifting numbers by negative amounts Fixes https://github.com/gchq/CyberChef/issues/1886. --- src/core/operations/ROT13.mjs | 7 ++- tests/operations/tests/Rotate.mjs | 93 ++++++++++++++++++++++++++++--- 2 files changed, 89 insertions(+), 11 deletions(-) diff --git a/src/core/operations/ROT13.mjs b/src/core/operations/ROT13.mjs index 1d059565..beec94a4 100644 --- a/src/core/operations/ROT13.mjs +++ b/src/core/operations/ROT13.mjs @@ -59,15 +59,16 @@ class ROT13 extends Operation { rot13Upperacse = args[1], rotNumbers = args[2]; let amount = args[3], - chr; + amountNumbers = args[3]; if (amount) { if (amount < 0) { amount = 26 - (Math.abs(amount) % 26); + amountNumbers = 10 - (Math.abs(amountNumbers) % 10); } for (let i = 0; i < input.length; i++) { - chr = input[i]; + let chr = input[i]; if (rot13Upperacse && chr >= 65 && chr <= 90) { // Upper case chr = (chr - 65 + amount) % 26; output[i] = chr + 65; @@ -75,7 +76,7 @@ class ROT13 extends Operation { chr = (chr - 97 + amount) % 26; output[i] = chr + 97; } else if (rotNumbers && chr >= 48 && chr <= 57) { // Numbers - chr = (chr - 48 + amount) % 10; + chr = (chr - 48 + amountNumbers) % 10; output[i] = chr + 48; } } diff --git a/tests/operations/tests/Rotate.mjs b/tests/operations/tests/Rotate.mjs index c12fa377..a69e20fd 100644 --- a/tests/operations/tests/Rotate.mjs +++ b/tests/operations/tests/Rotate.mjs @@ -135,10 +135,21 @@ TestRegister.addTests([ }, ], }, + { + name: "ROT13: no shift amount", + input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789", + expectedOutput: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789", + recipeConfig: [ + { + op: "ROT13", + args: [true, true, true, 0] + }, + ], + }, { name: "ROT13: normal", - input: "The Quick Brown Fox Jumped Over The Lazy Dog.", - expectedOutput: "Gur Dhvpx Oebja Sbk Whzcrq Bire Gur Ynml Qbt.", + input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789", + expectedOutput: "Gur Dhvpx Oebja Sbk Whzcrq Bire Gur Ynml Qbt. 3456789012", recipeConfig: [ { op: "ROT13", @@ -146,10 +157,21 @@ TestRegister.addTests([ }, ], }, + { + name: "ROT13: negative shift amount", + input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789", + expectedOutput: "Gur Dhvpx Oebja Sbk Whzcrq Bire Gur Ynml Qbt. 7890123456", + recipeConfig: [ + { + op: "ROT13", + args: [true, true, true, -13] + }, + ], + }, { name: "ROT13: full loop", - input: "The Quick Brown Fox Jumped Over The Lazy Dog.", - expectedOutput: "The Quick Brown Fox Jumped Over The Lazy Dog.", + input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789", + expectedOutput: "The Quick Brown Fox Jumped Over The Lazy Dog. 6789012345", recipeConfig: [ { op: "ROT13", @@ -157,10 +179,21 @@ TestRegister.addTests([ }, ], }, + { + name: "ROT13: full loop (negative shift amount)", + input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789", + expectedOutput: "The Quick Brown Fox Jumped Over The Lazy Dog. 4567890123", + recipeConfig: [ + { + op: "ROT13", + args: [true, true, true, -26] + }, + ], + }, { name: "ROT13: lowercase only", - input: "The Quick Brown Fox Jumped Over The Lazy Dog.", - expectedOutput: "Tur Qhvpx Bebja Fbk Jhzcrq Oire Tur Lnml Dbt.", + input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789", + expectedOutput: "Tur Qhvpx Bebja Fbk Jhzcrq Oire Tur Lnml Dbt. 0123456789", recipeConfig: [ { op: "ROT13", @@ -170,8 +203,8 @@ TestRegister.addTests([ }, { name: "ROT13: uppercase only", - input: "The Quick Brown Fox Jumped Over The Lazy Dog.", - expectedOutput: "Ghe Duick Orown Sox Wumped Bver Ghe Yazy Qog.", + input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789", + expectedOutput: "Ghe Duick Orown Sox Wumped Bver Ghe Yazy Qog. 0123456789", recipeConfig: [ { op: "ROT13", @@ -179,6 +212,50 @@ TestRegister.addTests([ }, ], }, + { + name: "ROT13: numbers only", + input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789", + expectedOutput: "The Quick Brown Fox Jumped Over The Lazy Dog. 5678901234", + recipeConfig: [ + { + op: "ROT13", + args: [false, false, true, 5] + }, + ], + }, + { + name: "ROT13: numbers only (negative shift amount)", + input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789", + expectedOutput: "The Quick Brown Fox Jumped Over The Lazy Dog. 5678901234", + recipeConfig: [ + { + op: "ROT13", + args: [false, false, true, 5] + }, + ], + }, + { + name: "ROT13: numbers only loop", + input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789", + expectedOutput: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789", + recipeConfig: [ + { + op: "ROT13", + args: [false, false, true, 10] + }, + ], + }, + { + name: "ROT13: numbers only loop (negative shift amount)", + input: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789", + expectedOutput: "The Quick Brown Fox Jumped Over The Lazy Dog. 0123456789", + recipeConfig: [ + { + op: "ROT13", + args: [false, false, true, -10] + }, + ], + }, { name: "ROT47: nothing", input: "", From 3eb1af0278706d4b016d58d21e1f3f8e4bac03ff Mon Sep 17 00:00:00 2001 From: Francisco Pombal Date: Mon, 16 Sep 2024 15:36:57 +0100 Subject: [PATCH 03/18] fix: DES/Triple DES - misleading error messages Fixes https://github.com/gchq/CyberChef/issues/1843. --- src/core/operations/DESDecrypt.mjs | 5 ++--- src/core/operations/DESEncrypt.mjs | 5 ++--- src/core/operations/TripleDESDecrypt.mjs | 5 ++--- src/core/operations/TripleDESEncrypt.mjs | 5 ++--- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/src/core/operations/DESDecrypt.mjs b/src/core/operations/DESDecrypt.mjs index 856aa065..4b1ab40e 100644 --- a/src/core/operations/DESDecrypt.mjs +++ b/src/core/operations/DESDecrypt.mjs @@ -22,7 +22,7 @@ class DESDecrypt extends Operation { this.name = "DES Decrypt"; this.module = "Ciphers"; - this.description = "DES is a previously dominant algorithm for encryption, and was published as an official U.S. Federal Information Processing Standard (FIPS). It is now considered to be insecure due to its small key size.

Key: DES uses a key length of 8 bytes (64 bits).
Triple DES uses a key length of 24 bytes (192 bits).

IV: The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.

Padding: In CBC and ECB mode, PKCS#7 padding will be used as a default."; + this.description = "DES is a previously dominant algorithm for encryption, and was published as an official U.S. Federal Information Processing Standard (FIPS). It is now considered to be insecure due to its small key size.

Key: DES uses a key length of 8 bytes (64 bits).

IV: The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.

Padding: In CBC and ECB mode, PKCS#7 padding will be used as a default."; this.infoURL = "https://wikipedia.org/wiki/Data_Encryption_Standard"; this.inputType = "string"; this.outputType = "string"; @@ -72,8 +72,7 @@ class DESDecrypt extends Operation { if (key.length !== 8) { throw new OperationError(`Invalid key length: ${key.length} bytes -DES uses a key length of 8 bytes (64 bits). -Triple DES uses a key length of 24 bytes (192 bits).`); +DES uses a key length of 8 bytes (64 bits).`); } if (iv.length !== 8 && mode !== "ECB") { throw new OperationError(`Invalid IV length: ${iv.length} bytes diff --git a/src/core/operations/DESEncrypt.mjs b/src/core/operations/DESEncrypt.mjs index 9472abe8..28d6202a 100644 --- a/src/core/operations/DESEncrypt.mjs +++ b/src/core/operations/DESEncrypt.mjs @@ -22,7 +22,7 @@ class DESEncrypt extends Operation { this.name = "DES Encrypt"; this.module = "Ciphers"; - this.description = "DES is a previously dominant algorithm for encryption, and was published as an official U.S. Federal Information Processing Standard (FIPS). It is now considered to be insecure due to its small key size.

Key: DES uses a key length of 8 bytes (64 bits).
Triple DES uses a key length of 24 bytes (192 bits).

You can generate a password-based key using one of the KDF operations.

IV: The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.

Padding: In CBC and ECB mode, PKCS#7 padding will be used."; + this.description = "DES is a previously dominant algorithm for encryption, and was published as an official U.S. Federal Information Processing Standard (FIPS). It is now considered to be insecure due to its small key size.

Key: DES uses a key length of 8 bytes (64 bits).

You can generate a password-based key using one of the KDF operations.

IV: The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.

Padding: In CBC and ECB mode, PKCS#7 padding will be used."; this.infoURL = "https://wikipedia.org/wiki/Data_Encryption_Standard"; this.inputType = "string"; this.outputType = "string"; @@ -70,8 +70,7 @@ class DESEncrypt extends Operation { if (key.length !== 8) { throw new OperationError(`Invalid key length: ${key.length} bytes -DES uses a key length of 8 bytes (64 bits). -Triple DES uses a key length of 24 bytes (192 bits).`); +DES uses a key length of 8 bytes (64 bits).`); } if (iv.length !== 8 && mode !== "ECB") { throw new OperationError(`Invalid IV length: ${iv.length} bytes diff --git a/src/core/operations/TripleDESDecrypt.mjs b/src/core/operations/TripleDESDecrypt.mjs index 8487509f..927600de 100644 --- a/src/core/operations/TripleDESDecrypt.mjs +++ b/src/core/operations/TripleDESDecrypt.mjs @@ -22,7 +22,7 @@ class TripleDESDecrypt extends Operation { this.name = "Triple DES Decrypt"; this.module = "Ciphers"; - this.description = "Triple DES applies DES three times to each block to increase key size.

Key: Triple DES uses a key length of 24 bytes (192 bits).
DES uses a key length of 8 bytes (64 bits).

IV: The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.

Padding: In CBC and ECB mode, PKCS#7 padding will be used as a default."; + this.description = "Triple DES applies DES three times to each block to increase key size.

Key: Triple DES uses a key length of 24 bytes (192 bits).

IV: The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.

Padding: In CBC and ECB mode, PKCS#7 padding will be used as a default."; this.infoURL = "https://wikipedia.org/wiki/Triple_DES"; this.inputType = "string"; this.outputType = "string"; @@ -73,8 +73,7 @@ class TripleDESDecrypt extends Operation { if (key.length !== 24 && key.length !== 16) { throw new OperationError(`Invalid key length: ${key.length} bytes -Triple DES uses a key length of 24 bytes (192 bits). -DES uses a key length of 8 bytes (64 bits).`); +Triple DES uses a key length of 24 bytes (192 bits).`); } if (iv.length !== 8 && mode !== "ECB") { throw new OperationError(`Invalid IV length: ${iv.length} bytes diff --git a/src/core/operations/TripleDESEncrypt.mjs b/src/core/operations/TripleDESEncrypt.mjs index 720d155d..b4a218d0 100644 --- a/src/core/operations/TripleDESEncrypt.mjs +++ b/src/core/operations/TripleDESEncrypt.mjs @@ -22,7 +22,7 @@ class TripleDESEncrypt extends Operation { this.name = "Triple DES Encrypt"; this.module = "Ciphers"; - this.description = "Triple DES applies DES three times to each block to increase key size.

Key: Triple DES uses a key length of 24 bytes (192 bits).
DES uses a key length of 8 bytes (64 bits).

You can generate a password-based key using one of the KDF operations.

IV: The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.

Padding: In CBC and ECB mode, PKCS#7 padding will be used."; + this.description = "Triple DES applies DES three times to each block to increase key size.

Key: Triple DES uses a key length of 24 bytes (192 bits).

You can generate a password-based key using one of the KDF operations.

IV: The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.

Padding: In CBC and ECB mode, PKCS#7 padding will be used."; this.infoURL = "https://wikipedia.org/wiki/Triple_DES"; this.inputType = "string"; this.outputType = "string"; @@ -72,8 +72,7 @@ class TripleDESEncrypt extends Operation { if (key.length !== 24 && key.length !== 16) { throw new OperationError(`Invalid key length: ${key.length} bytes -Triple DES uses a key length of 24 bytes (192 bits). -DES uses a key length of 8 bytes (64 bits).`); +Triple DES uses a key length of 24 bytes (192 bits).`); } if (iv.length !== 8 && mode !== "ECB") { throw new OperationError(`Invalid IV length: ${iv.length} bytes From 784b2631a83a6a543c2c70aa18bde016f7bcab5e Mon Sep 17 00:00:00 2001 From: Francisco Pombal Date: Mon, 16 Sep 2024 15:44:28 +0100 Subject: [PATCH 04/18] fix: DES/Triple DES - failing tests --- tests/node/tests/nodeApi.mjs | 2 +- tests/operations/tests/Crypt.mjs | 12 ++++-------- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/tests/node/tests/nodeApi.mjs b/tests/node/tests/nodeApi.mjs index 8992ed36..29a47ffc 100644 --- a/tests/node/tests/nodeApi.mjs +++ b/tests/node/tests/nodeApi.mjs @@ -119,7 +119,7 @@ TestRegister.addApiTests([ assert.strictEqual(result[0].module, "Ciphers"); assert.strictEqual(result[0].inputType, "string"); assert.strictEqual(result[0].outputType, "string"); - assert.strictEqual(result[0].description, "Triple DES applies DES three times to each block to increase key size.

Key: Triple DES uses a key length of 24 bytes (192 bits).
DES uses a key length of 8 bytes (64 bits).

IV: The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.

Padding: In CBC and ECB mode, PKCS#7 padding will be used as a default."); + assert.strictEqual(result[0].description, "Triple DES applies DES three times to each block to increase key size.

Key: Triple DES uses a key length of 24 bytes (192 bits).

IV: The Initialization Vector should be 8 bytes long. If not entered, it will default to 8 null bytes.

Padding: In CBC and ECB mode, PKCS#7 padding will be used as a default."); assert.strictEqual(result[0].args.length, 5); }), diff --git a/tests/operations/tests/Crypt.mjs b/tests/operations/tests/Crypt.mjs index 69123d66..5f5ec24d 100644 --- a/tests/operations/tests/Crypt.mjs +++ b/tests/operations/tests/Crypt.mjs @@ -580,8 +580,7 @@ Tag: a8f04c4d93bbef82bef61a103371aef9`, input: "", expectedOutput: `Invalid key length: 0 bytes -DES uses a key length of 8 bytes (64 bits). -Triple DES uses a key length of 24 bytes (192 bits).`, +DES uses a key length of 8 bytes (64 bits).`, recipeConfig: [ { "op": "DES Encrypt", @@ -674,8 +673,7 @@ Triple DES uses a key length of 24 bytes (192 bits).`, input: "", expectedOutput: `Invalid key length: 0 bytes -Triple DES uses a key length of 24 bytes (192 bits). -DES uses a key length of 8 bytes (64 bits).`, +Triple DES uses a key length of 24 bytes (192 bits).`, recipeConfig: [ { "op": "Triple DES Encrypt", @@ -1300,8 +1298,7 @@ The following algorithms will be used based on the size of the key: input: "", expectedOutput: `Invalid key length: 0 bytes -DES uses a key length of 8 bytes (64 bits). -Triple DES uses a key length of 24 bytes (192 bits).`, +DES uses a key length of 8 bytes (64 bits).`, recipeConfig: [ { "op": "DES Decrypt", @@ -1394,8 +1391,7 @@ Triple DES uses a key length of 24 bytes (192 bits).`, input: "", expectedOutput: `Invalid key length: 0 bytes -Triple DES uses a key length of 24 bytes (192 bits). -DES uses a key length of 8 bytes (64 bits).`, +Triple DES uses a key length of 24 bytes (192 bits).`, recipeConfig: [ { "op": "Triple DES Decrypt", From e484d426fe81c11218601262036efa9abf119759 Mon Sep 17 00:00:00 2001 From: Vijay Soni Date: Mon, 7 Oct 2024 01:28:46 +0530 Subject: [PATCH 05/18] automatically theme mode based on user preference Related to #1901 Implemented automatic dark theme change based on user preference using the `prefers-color-scheme` media query. --- src/web/App.mjs | 3 +++ src/web/waiters/OptionsWaiter.mjs | 8 ++++++++ 2 files changed, 11 insertions(+) mode change 100755 => 100644 src/web/App.mjs mode change 100755 => 100644 src/web/waiters/OptionsWaiter.mjs diff --git a/src/web/App.mjs b/src/web/App.mjs old mode 100755 new mode 100644 index 3ebfe1be..7071854a --- a/src/web/App.mjs +++ b/src/web/App.mjs @@ -60,6 +60,7 @@ class App { this.initialiseSplitter(); this.loadLocalStorage(); + this.manager.options.applyPreferredColorScheme(); this.populateOperationsList(); this.manager.setup(); this.manager.output.saveBombe(); @@ -536,6 +537,8 @@ class App { // Read in theme from URI params if (this.uriParams.theme) { this.manager.options.changeTheme(Utils.escapeHtml(this.uriParams.theme)); + } else { + this.manager.options.applyPreferredColorScheme(); } window.dispatchEvent(this.manager.statechange); diff --git a/src/web/waiters/OptionsWaiter.mjs b/src/web/waiters/OptionsWaiter.mjs old mode 100755 new mode 100644 index f5134133..4f4eda89 --- a/src/web/waiters/OptionsWaiter.mjs +++ b/src/web/waiters/OptionsWaiter.mjs @@ -163,6 +163,14 @@ class OptionsWaiter { themeSelect.selectedIndex = themeSelect.querySelector(`option[value="${theme}"`).index; } + /** + * Applies the user's preferred color scheme using the `prefers-color-scheme` media query. + */ + applyPreferredColorScheme() { + const prefersDarkScheme = window.matchMedia("(prefers-color-scheme: dark)").matches; + const theme = prefersDarkScheme ? "dark" : "classic"; + this.changeTheme(theme); + } /** * Changes the console logging level. From 802c576c60d1cf728522788439a152cbc6a4ab5d Mon Sep 17 00:00:00 2001 From: Pascal Burri Date: Sat, 26 Oct 2024 15:49:24 +0200 Subject: [PATCH 06/18] Updated luhn checksum to to work with base 2-36 --- src/core/operations/LuhnChecksum.mjs | 53 +++++++++++++++++++--------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/src/core/operations/LuhnChecksum.mjs b/src/core/operations/LuhnChecksum.mjs index cb3a7c24..8bf3465f 100644 --- a/src/core/operations/LuhnChecksum.mjs +++ b/src/core/operations/LuhnChecksum.mjs @@ -1,5 +1,6 @@ /** - * @author n1073645 [n1073645@gmail.com] + * @author n1073645 [n1073645@gmail.com] + * @author k3ach [k3ach@proton.me] * @copyright Crown Copyright 2020 * @license Apache-2.0 */ @@ -20,11 +21,17 @@ class LuhnChecksum extends Operation { this.name = "Luhn Checksum"; this.module = "Default"; - this.description = "The Luhn algorithm, also known as the modulus 10 or mod 10 algorithm, is a simple checksum formula used to validate a variety of identification numbers, such as credit card numbers, IMEI numbers and Canadian Social Insurance Numbers."; - this.infoURL = "https://wikipedia.org/wiki/Luhn_algorithm"; + this.description = "The Luhn mod N algorithm is an extension to the Luhn algorithm (also known as mod 10 algorithm) that allows it to work with sequences of values in any even-numbered base. This can be useful when a check digit is required to validate an identification string composed of letters, a combination of letters and digits or any arbitrary set of N characters where N is divisible by 2."; + this.infoURL = "https://en.wikipedia.org/wiki/Luhn_mod_N_algorithm"; this.inputType = "string"; this.outputType = "string"; - this.args = []; + this.args = [ + { + "name": "Radix", + "type": "number", + "value": 10 + } + ]; } /** @@ -33,26 +40,27 @@ class LuhnChecksum extends Operation { * @param {string} inputStr * @returns {number} */ - checksum(inputStr) { + checksum(inputStr, radix = 10) { let even = false; return inputStr.split("").reverse().reduce((acc, elem) => { - // Convert element to integer. - let temp = parseInt(elem, 10); + // Convert element to an integer based on the provided radix. + let temp = parseInt(elem, radix); - // If element is not an integer. - if (isNaN(temp)) - throw new OperationError("Character: " + elem + " is not a digit."); + // If element is not a valid number in the given radix. + if (isNaN(temp)) { + throw new Error("Character: " + elem + " is not valid in radix " + radix + "."); + } // If element is in an even position if (even) { - // Double the element and add the quotient and remainder together. - temp = 2 * elem; - temp = Math.floor(temp/10) + (temp % 10); + // Double the element and sum the quotient and remainder. + temp = 2 * temp; + temp = Math.floor(temp / radix) + (temp % radix); } even = !even; return acc + temp; - }, 0) % 10; + }, 0) % radix; // Use radix as the modulus base } /** @@ -63,9 +71,20 @@ class LuhnChecksum extends Operation { run(input, args) { if (!input) return ""; - const checkSum = this.checksum(input); - let checkDigit = this.checksum(input + "0"); - checkDigit = checkDigit === 0 ? 0 : (10-checkDigit); + let radix = args[0]; + + if (radix < 2 || radix > 36) { + throw new OperationError("Error: Radix argument must be between 2 and 36"); + } + + if (radix % 2 != 0) { + throw new OperationError("Error: Radix argument must be divisible by 2"); + } + + const checkSum = this.checksum(input, radix).toString(radix); + let checkDigit = this.checksum(input + "0", radix); + checkDigit = checkDigit === 0 ? 0 : (radix - checkDigit); + checkDigit = checkDigit.toString(radix) return `Checksum: ${checkSum} Checkdigit: ${checkDigit} From b92c1e7da04fcd244f85be229441725a8475a7db Mon Sep 17 00:00:00 2001 From: Pascal Burri Date: Sun, 27 Oct 2024 22:36:53 +0100 Subject: [PATCH 07/18] fixed code format, added tests --- src/core/operations/LuhnChecksum.mjs | 10 +- tests/operations/tests/LuhnChecksum.mjs | 402 +++++++++++++++++++++++- 2 files changed, 391 insertions(+), 21 deletions(-) diff --git a/src/core/operations/LuhnChecksum.mjs b/src/core/operations/LuhnChecksum.mjs index 8bf3465f..db7a6cd2 100644 --- a/src/core/operations/LuhnChecksum.mjs +++ b/src/core/operations/LuhnChecksum.mjs @@ -1,5 +1,5 @@ /** - * @author n1073645 [n1073645@gmail.com] + * @author n1073645 [n1073645@gmail.com] * @author k3ach [k3ach@proton.me] * @copyright Crown Copyright 2020 * @license Apache-2.0 @@ -21,7 +21,7 @@ class LuhnChecksum extends Operation { this.name = "Luhn Checksum"; this.module = "Default"; - this.description = "The Luhn mod N algorithm is an extension to the Luhn algorithm (also known as mod 10 algorithm) that allows it to work with sequences of values in any even-numbered base. This can be useful when a check digit is required to validate an identification string composed of letters, a combination of letters and digits or any arbitrary set of N characters where N is divisible by 2."; + this.description = "The Luhn mod N algorithm using the english alphabet. The Luhn mod N algorithm is an extension to the Luhn algorithm (also known as mod 10 algorithm) that allows it to work with sequences of values in any even-numbered base. This can be useful when a check digit is required to validate an identification string composed of letters, a combination of letters and digits or any arbitrary set of N characters where N is divisible by 2."; this.infoURL = "https://en.wikipedia.org/wiki/Luhn_mod_N_algorithm"; this.inputType = "string"; this.outputType = "string"; @@ -71,20 +71,20 @@ class LuhnChecksum extends Operation { run(input, args) { if (!input) return ""; - let radix = args[0]; + const radix = args[0]; if (radix < 2 || radix > 36) { throw new OperationError("Error: Radix argument must be between 2 and 36"); } - if (radix % 2 != 0) { + if (radix % 2 !== 0) { throw new OperationError("Error: Radix argument must be divisible by 2"); } const checkSum = this.checksum(input, radix).toString(radix); let checkDigit = this.checksum(input + "0", radix); checkDigit = checkDigit === 0 ? 0 : (radix - checkDigit); - checkDigit = checkDigit.toString(radix) + checkDigit = checkDigit.toString(radix); return `Checksum: ${checkSum} Checkdigit: ${checkDigit} diff --git a/tests/operations/tests/LuhnChecksum.mjs b/tests/operations/tests/LuhnChecksum.mjs index 498a1542..33d7372e 100644 --- a/tests/operations/tests/LuhnChecksum.mjs +++ b/tests/operations/tests/LuhnChecksum.mjs @@ -2,11 +2,392 @@ * From Decimal tests * * @author n1073645 [n1073645@gmail.com] + * @author k3ach [k3ach@proton.me] * @copyright Crown Copyright 2020 * @licence Apache-2.0 */ import TestRegister from "../../lib/TestRegister.mjs"; +const testCases = [ + { + radix: 2, + input: "01", + checksum: "1", + checkdigit: "1", + }, { + radix: 2, + input: "001111", + checksum: "0", + checkdigit: "0", + }, { + radix: 2, + input: "00011101", + checksum: "0", + checkdigit: "0", + }, { + radix: 2, + input: "0100101101", + checksum: "1", + checkdigit: "1", + }, { + radix: 4, + input: "0123", + checksum: "1", + checkdigit: "1", + }, { + radix: 4, + input: "130100", + checksum: "2", + checkdigit: "2", + }, { + radix: 4, + input: "32020313", + checksum: "3", + checkdigit: "0", + }, { + radix: 4, + input: "302233210112", + checksum: "3", + checkdigit: "0", + }, { + radix: 6, + input: "012345", + checksum: "4", + checkdigit: "4", + }, { + radix: 6, + input: "134255", + checksum: "2", + checkdigit: "4", + }, { + radix: 6, + input: "15021453", + checksum: "5", + checkdigit: "4", + }, { + radix: 6, + input: "211450230513", + checksum: "3", + checkdigit: "1", + }, { + radix: 8, + input: "01234567", + checksum: "2", + checkdigit: "2", + }, { + radix: 8, + input: "340624", + checksum: "0", + checkdigit: "4", + }, { + radix: 8, + input: "07260247", + checksum: "3", + checkdigit: "3", + }, { + radix: 8, + input: "026742114675", + checksum: "7", + checkdigit: "1", + }, { + radix: 10, + input: "0123456789", + checksum: "7", + checkdigit: "7", + }, { + radix: 10, + input: "468543", + checksum: "7", + checkdigit: "4", + }, { + radix: 10, + input: "59377601", + checksum: "5", + checkdigit: "6", + }, { + radix: 10, + input: "013909981254", + checksum: "1", + checkdigit: "3", + }, { + radix: 12, + input: "0123456789ab", + checksum: "3", + checkdigit: "3", + }, { + radix: 12, + input: "284685", + checksum: "0", + checkdigit: "6", + }, { + radix: 12, + input: "951a2661", + checksum: "0", + checkdigit: "8", + }, { + radix: 12, + input: "898202676387", + checksum: "b", + checkdigit: "9", + }, { + radix: 14, + input: "0123456789abcd", + checksum: "a", + checkdigit: "a", + }, { + radix: 14, + input: "33db25", + checksum: "0", + checkdigit: "d", + }, { + radix: 14, + input: "0b4ac128", + checksum: "b", + checkdigit: "3", + }, { + radix: 14, + input: "3d1c6d16160d", + checksum: "3", + checkdigit: "c", + }, { + radix: 16, + input: "0123456789abcdef", + checksum: "4", + checkdigit: "4", + }, { + radix: 16, + input: "e1fe64", + checksum: "b", + checkdigit: "6", + }, { + radix: 16, + input: "241a5dcd", + checksum: "1", + checkdigit: "9", + }, { + radix: 16, + input: "1fea740e0e1f", + checksum: "7", + checkdigit: "4", + }, { + radix: 18, + input: "0123456789abcdefgh", + checksum: "d", + checkdigit: "d", + }, { + radix: 18, + input: "995dgf", + checksum: "9", + checkdigit: "1", + }, { + radix: 18, + input: "9f80h32h", + checksum: "1", + checkdigit: "0", + }, { + radix: 18, + input: "5f9428e493g4", + checksum: "8", + checkdigit: "c", + }, { + radix: 20, + input: "0123456789abcdefghij", + checksum: "5", + checkdigit: "5", + }, { + radix: 20, + input: "918jci", + checksum: "h", + checkdigit: "d", + }, { + radix: 20, + input: "jab7j50d", + checksum: "g", + checkdigit: "j", + }, { + radix: 20, + input: "c56fe85eb6gg", + checksum: "g", + checkdigit: "5", + }, { + radix: 22, + input: "0123456789abcdefghijkl", + checksum: "g", + checkdigit: "g", + }, { + radix: 22, + input: "de57le", + checksum: "5", + checkdigit: "l", + }, { + radix: 22, + input: "e3fg6dfc", + checksum: "f", + checkdigit: "d", + }, { + radix: 22, + input: "1f8l80ai4kbg", + checksum: "l", + checkdigit: "f", + }, { + radix: 24, + input: "0123456789abcdefghijklmn", + checksum: "6", + checkdigit: "6", + }, { + radix: 24, + input: "agne7d", + checksum: "4", + checkdigit: "f", + }, { + radix: 24, + input: "1l4d9cf4", + checksum: "d", + checkdigit: "c", + }, { + radix: 24, + input: "blc1j09i3296", + checksum: "8", + checkdigit: "7", + }, { + radix: 26, + input: "0123456789abcdefghijklmnop", + checksum: "j", + checkdigit: "j", + }, { + radix: 26, + input: "82n9op", + checksum: "i", + checkdigit: "2", + }, { + radix: 26, + input: "e9cddn70", + checksum: "9", + checkdigit: "i", + }, { + radix: 26, + input: "ck0ep419knom", + checksum: "p", + checkdigit: "g", + }, { + radix: 28, + input: "0123456789abcdefghijklmnopqr", + checksum: "7", + checkdigit: "7", + }, { + radix: 28, + input: "a6hnoo", + checksum: "h", + checkdigit: "9", + }, { + radix: 28, + input: "lblc7kh0", + checksum: "a", + checkdigit: "f", + }, { + radix: 28, + input: "64k5piod3lmf", + checksum: "0", + checkdigit: "p", + }, { + radix: 30, + input: "0123456789abcdefghijklmnopqrst", + checksum: "m", + checkdigit: "m", + }, { + radix: 30, + input: "t69j7d", + checksum: "9", + checkdigit: "s", + }, { + radix: 30, + input: "p54o9ig3", + checksum: "a", + checkdigit: "o", + }, { + radix: 30, + input: "gc1njrt55030", + checksum: "6", + checkdigit: "1", + }, { + radix: 32, + input: "0123456789abcdefghijklmnopqrstuv", + checksum: "8", + checkdigit: "8", + }, { + radix: 32, + input: "rdou19", + checksum: "u", + checkdigit: "3", + }, { + radix: 32, + input: "ighj0pc7", + checksum: "3", + checkdigit: "8", + }, { + radix: 32, + input: "op4nn5fvjsrs", + checksum: "g", + checkdigit: "j", + }, { + radix: 34, + input: "0123456789abcdefghijklmnopqrstuvwx", + checksum: "p", + checkdigit: "p", + }, { + radix: 34, + input: "nvftj5", + checksum: "b", + checkdigit: "f", + }, { + radix: 34, + input: "u9v9g162", + checksum: "j", + checkdigit: "b", + }, { + radix: 34, + input: "o5gqg5d7gjh9", + checksum: "5", + checkdigit: "q", + }, { + radix: 36, + input: "0123456789abcdefghijklmnopqrstuvwxyz", + checksum: "9", + checkdigit: "9", + }, { + radix: 36, + input: "29zehu", + checksum: "i", + checkdigit: "j", + }, { + radix: 36, + input: "1snmikbu", + checksum: "s", + checkdigit: "v", + }, { + radix: 36, + input: "jpkar545q7gb", + checksum: "3", + checkdigit: "d", + }, +]; + +testCases.forEach(element => { + TestRegister.addTests([ + { + name: "Luhn Checksum Mod " + element.radix + " on " + element.input, + input: element.input, + expectedOutput: "Checksum: " + element.checksum + "\nCheckdigit: " + element.checkdigit + "\nLuhn Validated String: " + element.input + element.checkdigit, + recipeConfig: [ + { + op: "Luhn Checksum", + args: [element.radix] + }, + ], + }, + ]); +}); + TestRegister.addTests([ { name: "Luhn Checksum on standard data", @@ -15,7 +396,7 @@ TestRegister.addTests([ recipeConfig: [ { op: "Luhn Checksum", - args: [] + args: [10] }, ], }, @@ -26,7 +407,7 @@ TestRegister.addTests([ recipeConfig: [ { op: "Luhn Checksum", - args: [] + args: [10] }, ], }, @@ -37,18 +418,7 @@ TestRegister.addTests([ recipeConfig: [ { op: "Luhn Checksum", - args: [] - }, - ], - }, - { - name: "Luhn Checksum on invalid data", - input: "35641709b012469", - expectedOutput: "Character: b is not a digit.", - recipeConfig: [ - { - op: "Luhn Checksum", - args: [] + args: [10] }, ], }, @@ -59,8 +429,8 @@ TestRegister.addTests([ recipeConfig: [ { op: "Luhn Checksum", - args: [] + args: [10] }, ], - } + }, ]); From bab0a7ffed02153ad24e6d09b4f2c2b46078c726 Mon Sep 17 00:00:00 2001 From: "k3a.ch" <4323963+k3ach@users.noreply.github.com> Date: Sat, 30 Nov 2024 20:57:56 +0100 Subject: [PATCH 08/18] fixed typo --- src/core/operations/LuhnChecksum.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/operations/LuhnChecksum.mjs b/src/core/operations/LuhnChecksum.mjs index db7a6cd2..58e904fb 100644 --- a/src/core/operations/LuhnChecksum.mjs +++ b/src/core/operations/LuhnChecksum.mjs @@ -35,7 +35,7 @@ class LuhnChecksum extends Operation { } /** - * Generates the Luhn Checksum from the input. + * Generates the Luhn checksum from the input. * * @param {string} inputStr * @returns {number} From 8166f981ae7b6ef6644b8c9fe7ed652d1ea75c59 Mon Sep 17 00:00:00 2001 From: mshwed Date: Tue, 27 Aug 2019 11:41:16 -0400 Subject: [PATCH 09/18] in progress --- src/core/operations/MIMEDecoding.mjs | 129 +++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 src/core/operations/MIMEDecoding.mjs diff --git a/src/core/operations/MIMEDecoding.mjs b/src/core/operations/MIMEDecoding.mjs new file mode 100644 index 00000000..fb36326f --- /dev/null +++ b/src/core/operations/MIMEDecoding.mjs @@ -0,0 +1,129 @@ +/** + * @author mshwed [m@ttshwed.com] + * @copyright Crown Copyright 2019 + * @license Apache-2.0 + */ + +import Operation from "../Operation"; +import OperationError from "../errors/OperationError"; +import Utils from "../Utils"; +import { fromBase64 } from "../lib/Base64"; + +/** + * MIME Decoding operation + */ +class MIMEDecoding extends Operation { + + /** + * MIMEDecoding constructor + */ + constructor() { + super(); + + this.name = "MIME Decoding"; + this.module = "Default"; + this.description = ""; + this.infoURL = ""; + this.inputType = "byteArray"; + this.outputType = "string"; + this.args = [ + /* Example arguments. See the project wiki for full details. + { + name: "First arg", + type: "string", + value: "Don't Panic" + }, + { + name: "Second arg", + type: "number", + value: 42 + } + */ + ]; + } + + /** + * @param {byteArray} input + * @param {Object[]} args + * @returns {string} + */ + run(input, args) { + + let mimeEncodedText = Utils.byteArrayToUtf8(input) + + // const encodedWordRegex = /(\=\?)(.*?)(\?\=)/g; + + // let encodedWords = mimeEncodedText.match(encodedWordRegex); + + let parsedString = ""; + let currentPos = 0; + let pastPosition = 0; + while (currentPos >= 0) { + + // Find starting text + currentPos = mimeEncodedText.indexOf("=?", pastPosition); + console.log('CURRENT POSITION', currentPos); + if (currentPos < 0) break; + + // Add existing unparsed string + let fillerText = mimeEncodedText.substring(pastPosition, currentPos); + console.log("PROCESSING RANGE", pastPosition, ' ' ,currentPos) + console.log('FILLER TEXT: ', fillerText); + if (fillerText.indexOf('\r') > 0) console.log('CR detected', fillerText.indexOf('\r')); + if (fillerText.indexOf('\n') > 0) console.log('LF detected', fillerText.indexOf('\n')); + if (fillerText.indexOf('\r\n') > 0) console.log('CRLF detected', fillerText.indexOf('\r\n')); + if (fillerText.indexOf('\x20') > 0) console.log('SPACE detected', fillerText.indexOf('\x20')); + + if (fillerText !== '\r\n') + parsedString += fillerText + + pastPosition = currentPos; + + // find ending text + currentPos = mimeEncodedText.indexOf("?=", pastPosition); + + // Process block + let encodedTextBlock = mimeEncodedText.substring(pastPosition + 2, currentPos); + pastPosition = currentPos + 2; + + parsedString += this.parseEncodedWord(encodedTextBlock); + } + + return parsedString; + // let cleansedWord; + // for (let word of encodedWords) { + // cleansedWord = word.replace('=?', '').replace('?=', '').split('?'); + // let charset = cleansedWord[0]; + // let encoding = cleansedWord[1]; + // let encodedText = cleansedWord[2]; + + // if (encoding.toLowerCase() === 'b') { + // encodedText = fromBase64(encodedText); + // } + + // console.log(cleansedWord); + // } + + + throw new OperationError("Test"); + } + + parseEncodedWord(encodedWord) { + let [charset, encoding, encodedBlock] = encodedWord.split('?'); + + console.log('CURRENT BLOCK TO PROCESS', encodedBlock); + console.log('CURRENT CHARSET', charset); + + let encodedText = ''; + if (encoding.toLowerCase() === 'b') { + encodedText = fromBase64(encodedBlock); + } else { + encodedText = encodedBlock; + } + + return encodedText; + } + +} + +export default MIMEDecoding; From c3994aa8e3e8a6dc44ac5a736f18f58b50014acd Mon Sep 17 00:00:00 2001 From: mshwed Date: Wed, 28 Aug 2019 13:34:03 -0400 Subject: [PATCH 10/18] Added support for converting hex characters --- src/core/operations/MIMEDecoding.mjs | 30 ++++++++++------------------ 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/src/core/operations/MIMEDecoding.mjs b/src/core/operations/MIMEDecoding.mjs index fb36326f..c7844ad8 100644 --- a/src/core/operations/MIMEDecoding.mjs +++ b/src/core/operations/MIMEDecoding.mjs @@ -7,6 +7,7 @@ import Operation from "../Operation"; import OperationError from "../errors/OperationError"; import Utils from "../Utils"; +import {fromHex} from "../lib/Hex.mjs"; import { fromBase64 } from "../lib/Base64"; /** @@ -51,10 +52,6 @@ class MIMEDecoding extends Operation { let mimeEncodedText = Utils.byteArrayToUtf8(input) - // const encodedWordRegex = /(\=\?)(.*?)(\?\=)/g; - - // let encodedWords = mimeEncodedText.match(encodedWordRegex); - let parsedString = ""; let currentPos = 0; let pastPosition = 0; @@ -73,7 +70,8 @@ class MIMEDecoding extends Operation { if (fillerText.indexOf('\n') > 0) console.log('LF detected', fillerText.indexOf('\n')); if (fillerText.indexOf('\r\n') > 0) console.log('CRLF detected', fillerText.indexOf('\r\n')); if (fillerText.indexOf('\x20') > 0) console.log('SPACE detected', fillerText.indexOf('\x20')); - + if (fillerText.indexOf('\n\x20') > 0) console.log('newline SPACE detected', fillerText.indexOf('\x20')); + if (fillerText !== '\r\n') parsedString += fillerText @@ -90,20 +88,6 @@ class MIMEDecoding extends Operation { } return parsedString; - // let cleansedWord; - // for (let word of encodedWords) { - // cleansedWord = word.replace('=?', '').replace('?=', '').split('?'); - // let charset = cleansedWord[0]; - // let encoding = cleansedWord[1]; - // let encodedText = cleansedWord[2]; - - // if (encoding.toLowerCase() === 'b') { - // encodedText = fromBase64(encodedText); - // } - - // console.log(cleansedWord); - // } - throw new OperationError("Test"); } @@ -119,6 +103,14 @@ class MIMEDecoding extends Operation { encodedText = fromBase64(encodedBlock); } else { encodedText = encodedBlock; + let encodedChars = encodedText.indexOf("="); + if (encodedChars > 0) { + let extractedHex = encodedText.substring(encodedChars + 1, encodedChars + 3); + console.log("EXTRACTED HEX", extractedHex) + encodedText = encodedText.replace(`=${extractedHex}`, Utils.byteArrayToChars(fromHex(`=${extractedHex}`))) + } + + encodedText = encodedText.replace("_", " "); } return encodedText; From 7f97afd3e0a26058ac52a9d24bc448759174835a Mon Sep 17 00:00:00 2001 From: mshwed Date: Tue, 3 Sep 2019 20:33:57 -0400 Subject: [PATCH 11/18] Added parsing of headers. --- src/core/operations/MIMEDecoding.mjs | 194 +++++++++++++++--------- tests/operations/index.mjs | 10 +- tests/operations/tests/MIMEDecoding.mjs | 46 ++++++ 3 files changed, 172 insertions(+), 78 deletions(-) create mode 100644 tests/operations/tests/MIMEDecoding.mjs diff --git a/src/core/operations/MIMEDecoding.mjs b/src/core/operations/MIMEDecoding.mjs index c7844ad8..963bcd3b 100644 --- a/src/core/operations/MIMEDecoding.mjs +++ b/src/core/operations/MIMEDecoding.mjs @@ -7,8 +7,9 @@ import Operation from "../Operation"; import OperationError from "../errors/OperationError"; import Utils from "../Utils"; -import {fromHex} from "../lib/Hex.mjs"; +import { fromHex } from "../lib/Hex.mjs"; import { fromBase64 } from "../lib/Base64"; +import cptable from "../vendor/js-codepage/cptable.js"; /** * MIME Decoding operation @@ -23,24 +24,11 @@ class MIMEDecoding extends Operation { this.name = "MIME Decoding"; this.module = "Default"; - this.description = ""; - this.infoURL = ""; + this.description = "Enables the decoding of MIME message header extensions for non-ASCII text"; + this.infoURL = "https://tools.ietf.org/html/rfc2047"; this.inputType = "byteArray"; this.outputType = "string"; - this.args = [ - /* Example arguments. See the project wiki for full details. - { - name: "First arg", - type: "string", - value: "Don't Panic" - }, - { - name: "Second arg", - type: "number", - value: 42 - } - */ - ]; + this.args = []; } /** @@ -49,73 +37,135 @@ class MIMEDecoding extends Operation { * @returns {string} */ run(input, args) { + const mimeEncodedText = Utils.byteArrayToUtf8(input); + const encodedHeaders = mimeEncodedText.replace(/\r\n/g, "\n"); - let mimeEncodedText = Utils.byteArrayToUtf8(input) + const decodedHeader = this.decodeHeaders(encodedHeaders); - let parsedString = ""; - let currentPos = 0; - let pastPosition = 0; - while (currentPos >= 0) { - - // Find starting text - currentPos = mimeEncodedText.indexOf("=?", pastPosition); - console.log('CURRENT POSITION', currentPos); - if (currentPos < 0) break; - - // Add existing unparsed string - let fillerText = mimeEncodedText.substring(pastPosition, currentPos); - console.log("PROCESSING RANGE", pastPosition, ' ' ,currentPos) - console.log('FILLER TEXT: ', fillerText); - if (fillerText.indexOf('\r') > 0) console.log('CR detected', fillerText.indexOf('\r')); - if (fillerText.indexOf('\n') > 0) console.log('LF detected', fillerText.indexOf('\n')); - if (fillerText.indexOf('\r\n') > 0) console.log('CRLF detected', fillerText.indexOf('\r\n')); - if (fillerText.indexOf('\x20') > 0) console.log('SPACE detected', fillerText.indexOf('\x20')); - if (fillerText.indexOf('\n\x20') > 0) console.log('newline SPACE detected', fillerText.indexOf('\x20')); - - if (fillerText !== '\r\n') - parsedString += fillerText - - pastPosition = currentPos; - - // find ending text - currentPos = mimeEncodedText.indexOf("?=", pastPosition); - - // Process block - let encodedTextBlock = mimeEncodedText.substring(pastPosition + 2, currentPos); - pastPosition = currentPos + 2; - - parsedString += this.parseEncodedWord(encodedTextBlock); - } - - return parsedString; - - throw new OperationError("Test"); + return decodedHeader; } - parseEncodedWord(encodedWord) { - let [charset, encoding, encodedBlock] = encodedWord.split('?'); + /** + * Decode MIME header strings + * + * @param headerString + */ + decodeHeaders(headerString) { + // No encoded words detected + let i = headerString.indexOf("=?"); + if (i === -1) return headerString; - console.log('CURRENT BLOCK TO PROCESS', encodedBlock); - console.log('CURRENT CHARSET', charset); + let decodedHeaders = headerString.slice(0, i); + let header = headerString.slice(i); - let encodedText = ''; - if (encoding.toLowerCase() === 'b') { - encodedText = fromBase64(encodedBlock); - } else { - encodedText = encodedBlock; - let encodedChars = encodedText.indexOf("="); - if (encodedChars > 0) { - let extractedHex = encodedText.substring(encodedChars + 1, encodedChars + 3); - console.log("EXTRACTED HEX", extractedHex) - encodedText = encodedText.replace(`=${extractedHex}`, Utils.byteArrayToChars(fromHex(`=${extractedHex}`))) + let isBetweenWords = false; + let start, cur, charset, encoding, j, end, text; + while (header.length > -1) { + start = header.indexOf("=?"); + if (start === -1) break; + cur = start + "=?".length; + + i = header.slice(cur).indexOf("?"); + if (i === -1) break; + + charset = header.slice(cur, cur + i); + cur += i + "?".length; + + if (header.length < cur + "Q??=".length) break; + + encoding = header[cur]; + cur += 1; + + if (header[cur] !== "?") break; + + cur += 1; + + j = header.slice(cur).indexOf("?="); + if (j === -1) break; + + text = header.slice(cur, cur + j); + end = cur + j + "?=".length; + + if (encoding.toLowerCase() === "b") { + text = fromBase64(text); + } else if (encoding.toLowerCase() === "q") { + text = this.parseQEncodedWord(text); + } else { + isBetweenWords = false; + decodedHeaders += header.slice(0, start + 2); + header = header.slice(start + 2); } - encodedText = encodedText.replace("_", " "); + if (start > 0 && (!isBetweenWords || header.slice(0, start).search(/\S/g) > -1)) { + decodedHeaders += header.slice(0, start); + } + + decodedHeaders += this.convertFromCharset(charset, text); + + header = header.slice(end); + isBetweenWords = true; } - return encodedText; + if (header.length > 0) { + decodedHeaders += header; + } + + return decodedHeaders; } + /** + * Converts decoded text for supported charsets. + * Supports UTF-8, US-ASCII, ISO-8859-* + * + * @param encodedWord + */ + convertFromCharset(charset, encodedText) { + charset = charset.toLowerCase(); + const parsedCharset = charset.split("-"); + + if (parsedCharset.length === 2 && parsedCharset[0] === "utf" && charset === "utf-8") { + return cptable.utils.decode(65001, encodedText); + } else if (parsedCharset.length === 2 && charset === "us-ascii") { + return cptable.utils.decode(20127, encodedText); + } else if (parsedCharset.length === 3 && parsedCharset[0] === "iso" && parsedCharset[1] === "8859") { + const isoCharset = parseInt(parsedCharset[2], 10); + if (isoCharset >= 1 && isoCharset <= 16) { + return cptable.utils.decode(28590 + isoCharset, encodedText); + } + } + + throw new OperationError("Unhandled Charset"); + } + + /** + * Parses a Q encoded word + * + * @param encodedWord + */ + parseQEncodedWord(encodedWord) { + let decodedWord = ""; + for (let i = 0; i < encodedWord.length; i++) { + if (encodedWord[i] === "_") { + decodedWord += " "; + // Parse hex encoding + } else if (encodedWord[i] === "=") { + if ((i + 2) >= encodedWord.length) throw new OperationError("Incorrectly Encoded Word"); + const decodedHex = Utils.byteArrayToChars(fromHex(encodedWord.substring(i + 1, i + 3))); + decodedWord += decodedHex; + i += 2; + } else if ( + (encodedWord[i].charCodeAt(0) >= " ".charCodeAt(0) && encodedWord[i].charCodeAt(0) <= "~".charCodeAt(0)) || + encodedWord[i] === "\n" || + encodedWord[i] === "\r" || + encodedWord[i] === "\t") { + decodedWord += encodedWord[i]; + } else { + throw new OperationError("Incorrectly Encoded Word"); + } + } + + return decodedWord; + } } export default MIMEDecoding; diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs index 991bd356..259ec1e1 100644 --- a/tests/operations/index.mjs +++ b/tests/operations/index.mjs @@ -11,10 +11,7 @@ * @license Apache-2.0 */ -import { - setLongTestFailure, - logTestReport, -} from "../lib/utils.mjs"; +import { setLongTestFailure, logTestReport } from "../lib/utils.mjs"; import TestRegister from "../lib/TestRegister.mjs"; import "./tests/AESKeyWrap.mjs"; @@ -104,6 +101,7 @@ import "./tests/LZNT1Decompress.mjs"; import "./tests/LZString.mjs"; import "./tests/Magic.mjs"; import "./tests/Media.mjs"; +import "./tests/MIMEDecoding"; import "./tests/Modhex.mjs"; import "./tests/MorseCode.mjs"; import "./tests/MS.mjs"; @@ -167,14 +165,14 @@ const testStatus = { allTestsPassing: true, counts: { total: 0, - } + }, }; setLongTestFailure(); const logOpsTestReport = logTestReport.bind(null, testStatus); -(async function() { +(async function () { const results = await TestRegister.runTests(); logOpsTestReport(results); })(); diff --git a/tests/operations/tests/MIMEDecoding.mjs b/tests/operations/tests/MIMEDecoding.mjs new file mode 100644 index 00000000..f358d63f --- /dev/null +++ b/tests/operations/tests/MIMEDecoding.mjs @@ -0,0 +1,46 @@ +/** + * MIME Header Decoding tests + * + * @author mshwed [m@ttshwed.com] + * @copyright Crown Copyright 2019 + * @license Apache-2.0 + */ + +import TestRegister from "../../lib/TestRegister.mjs"; + +TestRegister.addTests([ + { + name: "Encoded =?", + input: "=?=?utf-8?q?test?=", + expectedOutput: "=?test", + recipeConfig: [ + { + "op": "MIME Decoding", + "args": [] + } + ] + }, + { + name: "UTF-8 Encodings Multiple Headers", + input: "=?utf-8?q?=C3=89ric?= , =?utf-8?q?Ana=C3=AFs?= ", + expectedOutput: "Éric , Anaïs ", + recipeConfig: [ + { + "op": "MIME Decoding", + "args": [] + } + ] + }, + { + name: "UTF-8 Encodings Single Header", + input: "=?utf-8?q?=C2=A1Hola,?= =?utf-8?q?_se=C3=B1or!?=", + expectedOutput: "¡Hola, señor!", + recipeConfig: [ + { + "op": "MIME Decoding", + "args": [] + } + ] + }, + +]); From 50c0d4bcd6ea604943c144c61e57759ac0a3a784 Mon Sep 17 00:00:00 2001 From: mshwed Date: Tue, 3 Sep 2019 21:02:47 -0400 Subject: [PATCH 12/18] Added test case for ISO and ASCII --- tests/operations/tests/MIMEDecoding.mjs | 59 +++++++++++++++++++++---- 1 file changed, 51 insertions(+), 8 deletions(-) diff --git a/tests/operations/tests/MIMEDecoding.mjs b/tests/operations/tests/MIMEDecoding.mjs index f358d63f..b3e51d8f 100644 --- a/tests/operations/tests/MIMEDecoding.mjs +++ b/tests/operations/tests/MIMEDecoding.mjs @@ -10,9 +10,53 @@ import TestRegister from "../../lib/TestRegister.mjs"; TestRegister.addTests([ { - name: "Encoded =?", - input: "=?=?utf-8?q?test?=", - expectedOutput: "=?test", + name: "Encoded comments", + input: "(=?ISO-8859-1?Q?a?=)", + expectedOutput: "(a)", + recipeConfig: [ + { + "op": "MIME Decoding", + "args": [] + } + ] + }, + { + name: "Encoded adjacent comments whitespace", + input: "(=?ISO-8859-1?Q?a?= b)", + expectedOutput: "(a b)", + recipeConfig: [ + { + "op": "MIME Decoding", + "args": [] + } + ] + }, + { + name: "Encoded adjacent single whitespace ignored", + input: "(=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=)", + expectedOutput: "(ab)", + recipeConfig: [ + { + "op": "MIME Decoding", + "args": [] + } + ] + }, + { + name: "Encoded adjacent double whitespace ignored", + input: "(=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?=)", + expectedOutput: "(ab)", + recipeConfig: [ + { + "op": "MIME Decoding", + "args": [] + } + ] + }, + { + name: "Encoded adjacent CRLF whitespace ignored", + input: "(=?ISO-8859-1?Q?a?=\r\n =?ISO-8859-1?Q?b?=)", + expectedOutput: "(ab)", recipeConfig: [ { "op": "MIME Decoding", @@ -32,15 +76,14 @@ TestRegister.addTests([ ] }, { - name: "UTF-8 Encodings Single Header", - input: "=?utf-8?q?=C2=A1Hola,?= =?utf-8?q?_se=C3=B1or!?=", - expectedOutput: "¡Hola, señor!", + name: "ISO Decoding", + input: "From: =?US-ASCII?Q?Keith_Moore?= \nTo: =?ISO-8859-1?Q?Keld_J=F8rn_Simonsen?= \nCC: =?ISO-8859-1?Q?Andr=E9?= Pirard \nSubject: =?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?=\n=?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?=", + expectedOutput: "From: Keith Moore \nTo: Keld Jørn Simonsen \nCC: André Pirard \nSubject: If you can read this you understand the example.", recipeConfig: [ { "op": "MIME Decoding", "args": [] } ] - }, - + } ]); From 23faeadea25491c201f359bb01d652bc957f7f06 Mon Sep 17 00:00:00 2001 From: mshwed Date: Tue, 3 Sep 2019 21:05:25 -0400 Subject: [PATCH 13/18] Fixed linting issues --- src/core/operations/MIMEDecoding.mjs | 2 +- tests/operations/tests/MIMEDecoding.mjs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/core/operations/MIMEDecoding.mjs b/src/core/operations/MIMEDecoding.mjs index 963bcd3b..2d7eac99 100644 --- a/src/core/operations/MIMEDecoding.mjs +++ b/src/core/operations/MIMEDecoding.mjs @@ -47,7 +47,7 @@ class MIMEDecoding extends Operation { /** * Decode MIME header strings - * + * * @param headerString */ decodeHeaders(headerString) { diff --git a/tests/operations/tests/MIMEDecoding.mjs b/tests/operations/tests/MIMEDecoding.mjs index b3e51d8f..b99fc489 100644 --- a/tests/operations/tests/MIMEDecoding.mjs +++ b/tests/operations/tests/MIMEDecoding.mjs @@ -1,6 +1,6 @@ /** * MIME Header Decoding tests - * + * * @author mshwed [m@ttshwed.com] * @copyright Crown Copyright 2019 * @license Apache-2.0 From 15bbed093c570d41ecb149b2220a600bfe4650eb Mon Sep 17 00:00:00 2001 From: mshwed Date: Sat, 15 Feb 2025 22:23:49 -0500 Subject: [PATCH 14/18] fixed formatting --- tests/operations/index.mjs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs index 259ec1e1..0f61fd90 100644 --- a/tests/operations/index.mjs +++ b/tests/operations/index.mjs @@ -11,7 +11,10 @@ * @license Apache-2.0 */ -import { setLongTestFailure, logTestReport } from "../lib/utils.mjs"; +import { + setLongTestFailure, + logTestReport, +} from "../lib/utils.mjs"; import TestRegister from "../lib/TestRegister.mjs"; import "./tests/AESKeyWrap.mjs"; @@ -165,14 +168,14 @@ const testStatus = { allTestsPassing: true, counts: { total: 0, - }, + } }; setLongTestFailure(); const logOpsTestReport = logTestReport.bind(null, testStatus); -(async function () { +(async function() { const results = await TestRegister.runTests(); logOpsTestReport(results); })(); From 2ae923b73e27aff537b070516e4e433967a81ba8 Mon Sep 17 00:00:00 2001 From: mshwed Date: Sat, 15 Feb 2025 23:03:05 -0500 Subject: [PATCH 15/18] Updated category and fixed imports --- src/core/config/Categories.json | 3 ++- src/core/operations/MIMEDecoding.mjs | 10 +++++----- tests/operations/index.mjs | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/core/config/Categories.json b/src/core/config/Categories.json index 1f309d82..de3ea882 100644 --- a/src/core/config/Categories.json +++ b/src/core/config/Categories.json @@ -76,7 +76,8 @@ "Rison Encode", "Rison Decode", "To Modhex", - "From Modhex" + "From Modhex", + "MIME Decoding" ] }, { diff --git a/src/core/operations/MIMEDecoding.mjs b/src/core/operations/MIMEDecoding.mjs index 2d7eac99..7b52fbdd 100644 --- a/src/core/operations/MIMEDecoding.mjs +++ b/src/core/operations/MIMEDecoding.mjs @@ -4,12 +4,12 @@ * @license Apache-2.0 */ -import Operation from "../Operation"; -import OperationError from "../errors/OperationError"; -import Utils from "../Utils"; +import Operation from "../Operation.mjs"; +import OperationError from "../errors/OperationError.mjs"; +import Utils from "../Utils.mjs"; import { fromHex } from "../lib/Hex.mjs"; -import { fromBase64 } from "../lib/Base64"; -import cptable from "../vendor/js-codepage/cptable.js"; +import { fromBase64 } from "../lib/Base64.mjs"; +import cptable from "codepage"; /** * MIME Decoding operation diff --git a/tests/operations/index.mjs b/tests/operations/index.mjs index 0f61fd90..a82bc874 100644 --- a/tests/operations/index.mjs +++ b/tests/operations/index.mjs @@ -104,7 +104,7 @@ import "./tests/LZNT1Decompress.mjs"; import "./tests/LZString.mjs"; import "./tests/Magic.mjs"; import "./tests/Media.mjs"; -import "./tests/MIMEDecoding"; +import "./tests/MIMEDecoding.mjs"; import "./tests/Modhex.mjs"; import "./tests/MorseCode.mjs"; import "./tests/MS.mjs"; From 7b3980a5e203112237dd0814cd0041b3c878921a Mon Sep 17 00:00:00 2001 From: Even Stensberg Date: Sun, 16 Feb 2025 13:50:10 +0100 Subject: [PATCH 16/18] chore(root): add cspell --- .cspell.json | 17 + package-lock.json | 1136 +++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 + 3 files changed, 1155 insertions(+) create mode 100644 .cspell.json diff --git a/.cspell.json b/.cspell.json new file mode 100644 index 00000000..66fca29b --- /dev/null +++ b/.cspell.json @@ -0,0 +1,17 @@ +{ + "version": "0.2", + "language": "en,en-gb", + "words": [], + "dictionaries": [ + "npm", + "softwareTerms", + "node", + "html", + "css", + "bash", + "en-gb", + "misc" + ], + "ignorePaths": ["package.json", "package-lock.json", "node_modules"] + } + \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 8f961994..50639ea8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -121,6 +121,7 @@ "compression-webpack-plugin": "^11.1.0", "copy-webpack-plugin": "^12.0.2", "core-js": "^3.37.1", + "cspell": "^8.17.3", "css-loader": "7.1.2", "eslint": "^9.4.0", "eslint-plugin-jsdoc": "^48.2.9", @@ -1908,6 +1909,594 @@ "node": ">=0.1.90" } }, + "node_modules/@cspell/cspell-bundled-dicts": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/@cspell/cspell-bundled-dicts/-/cspell-bundled-dicts-8.17.3.tgz", + "integrity": "sha512-6uOF726o3JnExAUKM20OJJXZo+Qf9Jt64nkVwnVXx7Upqr5I9Pb1npYPEAIpUA03SnWYmKwUIqhAmkwrN+bLPA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/dict-ada": "^4.1.0", + "@cspell/dict-al": "^1.1.0", + "@cspell/dict-aws": "^4.0.9", + "@cspell/dict-bash": "^4.2.0", + "@cspell/dict-companies": "^3.1.13", + "@cspell/dict-cpp": "^6.0.3", + "@cspell/dict-cryptocurrencies": "^5.0.4", + "@cspell/dict-csharp": "^4.0.6", + "@cspell/dict-css": "^4.0.17", + "@cspell/dict-dart": "^2.3.0", + "@cspell/dict-data-science": "^2.0.7", + "@cspell/dict-django": "^4.1.4", + "@cspell/dict-docker": "^1.1.12", + "@cspell/dict-dotnet": "^5.0.9", + "@cspell/dict-elixir": "^4.0.7", + "@cspell/dict-en_us": "^4.3.30", + "@cspell/dict-en-common-misspellings": "^2.0.9", + "@cspell/dict-en-gb": "1.1.33", + "@cspell/dict-filetypes": "^3.0.10", + "@cspell/dict-flutter": "^1.1.0", + "@cspell/dict-fonts": "^4.0.4", + "@cspell/dict-fsharp": "^1.1.0", + "@cspell/dict-fullstack": "^3.2.3", + "@cspell/dict-gaming-terms": "^1.1.0", + "@cspell/dict-git": "^3.0.4", + "@cspell/dict-golang": "^6.0.18", + "@cspell/dict-google": "^1.0.8", + "@cspell/dict-haskell": "^4.0.5", + "@cspell/dict-html": "^4.0.11", + "@cspell/dict-html-symbol-entities": "^4.0.3", + "@cspell/dict-java": "^5.0.11", + "@cspell/dict-julia": "^1.1.0", + "@cspell/dict-k8s": "^1.0.10", + "@cspell/dict-kotlin": "^1.1.0", + "@cspell/dict-latex": "^4.0.3", + "@cspell/dict-lorem-ipsum": "^4.0.4", + "@cspell/dict-lua": "^4.0.7", + "@cspell/dict-makefile": "^1.0.4", + "@cspell/dict-markdown": "^2.0.9", + "@cspell/dict-monkeyc": "^1.0.10", + "@cspell/dict-node": "^5.0.6", + "@cspell/dict-npm": "^5.1.24", + "@cspell/dict-php": "^4.0.14", + "@cspell/dict-powershell": "^5.0.14", + "@cspell/dict-public-licenses": "^2.0.13", + "@cspell/dict-python": "^4.2.15", + "@cspell/dict-r": "^2.1.0", + "@cspell/dict-ruby": "^5.0.7", + "@cspell/dict-rust": "^4.0.11", + "@cspell/dict-scala": "^5.0.7", + "@cspell/dict-shell": "^1.1.0", + "@cspell/dict-software-terms": "^4.2.4", + "@cspell/dict-sql": "^2.2.0", + "@cspell/dict-svelte": "^1.0.6", + "@cspell/dict-swift": "^2.0.5", + "@cspell/dict-terraform": "^1.1.0", + "@cspell/dict-typescript": "^3.2.0", + "@cspell/dict-vue": "^3.0.4" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@cspell/cspell-json-reporter": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/@cspell/cspell-json-reporter/-/cspell-json-reporter-8.17.3.tgz", + "integrity": "sha512-RWSfyHOin/d9CqLjz00JMvPkag3yUSsQZr6G9BnCT5cMEO/ws8wQZzA54CNj/LAOccbknTX65SSroPPAtxs56w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-types": "8.17.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@cspell/cspell-pipe": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/@cspell/cspell-pipe/-/cspell-pipe-8.17.3.tgz", + "integrity": "sha512-DqqSWKt9NLWPGloYxZTpzUhgdW8ObMkZmOOF6TyqpJ4IbckEct8ULgskNorTNRlmmjLniaNgvg6JSHuYO3Urxw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@cspell/cspell-resolver": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/@cspell/cspell-resolver/-/cspell-resolver-8.17.3.tgz", + "integrity": "sha512-yQlVaIsWiax6RRuuacZs++kl6Y9rwH9ZkVlsG9fhdeCJ5Xf3WCW+vmX1chzhhKDzRr8CF9fsvb1uagd/5/bBYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "global-directory": "^4.0.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@cspell/cspell-service-bus": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/@cspell/cspell-service-bus/-/cspell-service-bus-8.17.3.tgz", + "integrity": "sha512-CC3nob/Kbuesz5WTW+LjAHnDFXJrA49pW5ckmbufJxNnoAk7EJez/qr7/ELMTf6Fl3A5xZ776Lhq7738Hy/fmQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@cspell/cspell-types": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/@cspell/cspell-types/-/cspell-types-8.17.3.tgz", + "integrity": "sha512-ozgeuSioX9z2wtlargfgdw3LKwDFAfm8gxu+xwNREvXiLsevb+lb7ZlY5/ay+MahqR5Hfs7XzYzBLTKL/ldn9g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@cspell/dict-ada": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-ada/-/dict-ada-4.1.0.tgz", + "integrity": "sha512-7SvmhmX170gyPd+uHXrfmqJBY5qLcCX8kTGURPVeGxmt8XNXT75uu9rnZO+jwrfuU2EimNoArdVy5GZRGljGNg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-al": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-al/-/dict-al-1.1.0.tgz", + "integrity": "sha512-PtNI1KLmYkELYltbzuoztBxfi11jcE9HXBHCpID2lou/J4VMYKJPNqe4ZjVzSI9NYbMnMnyG3gkbhIdx66VSXg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-aws": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@cspell/dict-aws/-/dict-aws-4.0.9.tgz", + "integrity": "sha512-bDYdnnJGwSkIZ4gzrauu7qzOs/ZAY/FnU4k11LgdMI8BhwMfsbsy2EI1iS+sD/BI5ZnNT9kU5YR3WADeNOmhRg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-bash": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-bash/-/dict-bash-4.2.0.tgz", + "integrity": "sha512-HOyOS+4AbCArZHs/wMxX/apRkjxg6NDWdt0jF9i9XkvJQUltMwEhyA2TWYjQ0kssBsnof+9amax2lhiZnh3kCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/dict-shell": "1.1.0" + } + }, + "node_modules/@cspell/dict-companies": { + "version": "3.1.14", + "resolved": "https://registry.npmjs.org/@cspell/dict-companies/-/dict-companies-3.1.14.tgz", + "integrity": "sha512-iqo1Ce4L7h0l0GFSicm2wCLtfuymwkvgFGhmu9UHyuIcTbdFkDErH+m6lH3Ed+QuskJlpQ9dM7puMIGqUlVERw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-cpp": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-cpp/-/dict-cpp-6.0.3.tgz", + "integrity": "sha512-OFrVXdxCeGKnon36Pe3yFjBuY4kzzEwWFf3vDz+cJTodZDkjFkBifQeTtt5YfimgF8cfAJZXkBCsxjipAgmAiw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-cryptocurrencies": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@cspell/dict-cryptocurrencies/-/dict-cryptocurrencies-5.0.4.tgz", + "integrity": "sha512-6iFu7Abu+4Mgqq08YhTKHfH59mpMpGTwdzDB2Y8bbgiwnGFCeoiSkVkgLn1Kel2++hYcZ8vsAW/MJS9oXxuMag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-csharp": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-csharp/-/dict-csharp-4.0.6.tgz", + "integrity": "sha512-w/+YsqOknjQXmIlWDRmkW+BHBPJZ/XDrfJhZRQnp0wzpPOGml7W0q1iae65P2AFRtTdPKYmvSz7AL5ZRkCnSIw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-css": { + "version": "4.0.17", + "resolved": "https://registry.npmjs.org/@cspell/dict-css/-/dict-css-4.0.17.tgz", + "integrity": "sha512-2EisRLHk6X/PdicybwlajLGKF5aJf4xnX2uuG5lexuYKt05xV/J/OiBADmi8q9obhxf1nesrMQbqAt+6CsHo/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-dart": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-dart/-/dict-dart-2.3.0.tgz", + "integrity": "sha512-1aY90lAicek8vYczGPDKr70pQSTQHwMFLbmWKTAI6iavmb1fisJBS1oTmMOKE4ximDf86MvVN6Ucwx3u/8HqLg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-data-science": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@cspell/dict-data-science/-/dict-data-science-2.0.7.tgz", + "integrity": "sha512-XhAkK+nSW6zmrnWzusmZ1BpYLc62AWYHZc2p17u4nE2Z9XG5DleG55PCZxXQTKz90pmwlhFM9AfpkJsYaBWATA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-django": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@cspell/dict-django/-/dict-django-4.1.4.tgz", + "integrity": "sha512-fX38eUoPvytZ/2GA+g4bbdUtCMGNFSLbdJJPKX2vbewIQGfgSFJKY56vvcHJKAvw7FopjvgyS/98Ta9WN1gckg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-docker": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@cspell/dict-docker/-/dict-docker-1.1.12.tgz", + "integrity": "sha512-6d25ZPBnYZaT9D9An/x6g/4mk542R8bR3ipnby3QFCxnfdd6xaWiTcwDPsCgwN2aQZIQ1jX/fil9KmBEqIK/qA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-dotnet": { + "version": "5.0.9", + "resolved": "https://registry.npmjs.org/@cspell/dict-dotnet/-/dict-dotnet-5.0.9.tgz", + "integrity": "sha512-JGD6RJW5sHtO5lfiJl11a5DpPN6eKSz5M1YBa1I76j4dDOIqgZB6rQexlDlK1DH9B06X4GdDQwdBfnpAB0r2uQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-elixir": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@cspell/dict-elixir/-/dict-elixir-4.0.7.tgz", + "integrity": "sha512-MAUqlMw73mgtSdxvbAvyRlvc3bYnrDqXQrx5K9SwW8F7fRYf9V4vWYFULh+UWwwkqkhX9w03ZqFYRTdkFku6uA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-en_us": { + "version": "4.3.31", + "resolved": "https://registry.npmjs.org/@cspell/dict-en_us/-/dict-en_us-4.3.31.tgz", + "integrity": "sha512-MDc+1B0aFwQONS0JZ6w7ks2KFGkUcaNTFJ8kI6GHvFRmEl3zP5NJDwFEXFsoEdLDb86j2myauSWMJXR3JFuwbA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-en-common-misspellings": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@cspell/dict-en-common-misspellings/-/dict-en-common-misspellings-2.0.9.tgz", + "integrity": "sha512-O/jAr1VNtuyCFckbTmpeEf43ZFWVD9cJFvWaA6rO2IVmLirJViHWJUyBZOuQcesSplzEIw80MAYmnK06/MDWXQ==", + "dev": true, + "license": "CC BY-SA 4.0" + }, + "node_modules/@cspell/dict-en-gb": { + "version": "1.1.33", + "resolved": "https://registry.npmjs.org/@cspell/dict-en-gb/-/dict-en-gb-1.1.33.tgz", + "integrity": "sha512-tKSSUf9BJEV+GJQAYGw5e+ouhEe2ZXE620S7BLKe3ZmpnjlNG9JqlnaBhkIMxKnNFkLY2BP/EARzw31AZnOv4g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-filetypes": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/@cspell/dict-filetypes/-/dict-filetypes-3.0.11.tgz", + "integrity": "sha512-bBtCHZLo7MiSRUqx5KEiPdGOmXIlDGY+L7SJEtRWZENpAKE+96rT7hj+TUUYWBbCzheqHr0OXZJFEKDgsG/uZg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-flutter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-flutter/-/dict-flutter-1.1.0.tgz", + "integrity": "sha512-3zDeS7zc2p8tr9YH9tfbOEYfopKY/srNsAa+kE3rfBTtQERAZeOhe5yxrnTPoufctXLyuUtcGMUTpxr3dO0iaA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-fonts": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@cspell/dict-fonts/-/dict-fonts-4.0.4.tgz", + "integrity": "sha512-cHFho4hjojBcHl6qxidl9CvUb492IuSk7xIf2G2wJzcHwGaCFa2o3gRcxmIg1j62guetAeDDFELizDaJlVRIOg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-fsharp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-fsharp/-/dict-fsharp-1.1.0.tgz", + "integrity": "sha512-oguWmHhGzgbgbEIBKtgKPrFSVAFtvGHaQS0oj+vacZqMObwkapcTGu7iwf4V3Bc2T3caf0QE6f6rQfIJFIAVsw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-fullstack": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@cspell/dict-fullstack/-/dict-fullstack-3.2.4.tgz", + "integrity": "sha512-JRRvaOLBZ13BO9sP395W+06tyO1Jy/87aFlKe9xQiCWMiwpCo2kGq0xBGq0PDWe253lYLs+GKrNmLU0fSxrObg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-gaming-terms": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-gaming-terms/-/dict-gaming-terms-1.1.0.tgz", + "integrity": "sha512-46AnDs9XkgJ2f1Sqol1WgfJ8gOqp60fojpc9Wxch7x+BA63g4JfMV5/M5x0sI0TLlLY8EBSglcr8wQF/7C80AQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-git": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@cspell/dict-git/-/dict-git-3.0.4.tgz", + "integrity": "sha512-C44M+m56rYn6QCsLbiKiedyPTMZxlDdEYAsPwwlL5bhMDDzXZ3Ic8OCQIhMbiunhCOJJT+er4URmOmM+sllnjg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-golang": { + "version": "6.0.18", + "resolved": "https://registry.npmjs.org/@cspell/dict-golang/-/dict-golang-6.0.18.tgz", + "integrity": "sha512-Mt+7NwfodDwUk7423DdaQa0YaA+4UoV3XSxQwZioqjpFBCuxfvvv4l80MxCTAAbK6duGj0uHbGTwpv8fyKYPKg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-google": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@cspell/dict-google/-/dict-google-1.0.8.tgz", + "integrity": "sha512-BnMHgcEeaLyloPmBs8phCqprI+4r2Jb8rni011A8hE+7FNk7FmLE3kiwxLFrcZnnb7eqM0agW4zUaNoB0P+z8A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-haskell": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@cspell/dict-haskell/-/dict-haskell-4.0.5.tgz", + "integrity": "sha512-s4BG/4tlj2pPM9Ha7IZYMhUujXDnI0Eq1+38UTTCpatYLbQqDwRFf2KNPLRqkroU+a44yTUAe0rkkKbwy4yRtQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-html": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/@cspell/dict-html/-/dict-html-4.0.11.tgz", + "integrity": "sha512-QR3b/PB972SRQ2xICR1Nw/M44IJ6rjypwzA4jn+GH8ydjAX9acFNfc+hLZVyNe0FqsE90Gw3evLCOIF0vy1vQw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-html-symbol-entities": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-html-symbol-entities/-/dict-html-symbol-entities-4.0.3.tgz", + "integrity": "sha512-aABXX7dMLNFdSE8aY844X4+hvfK7977sOWgZXo4MTGAmOzR8524fjbJPswIBK7GaD3+SgFZ2yP2o0CFvXDGF+A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-java": { + "version": "5.0.11", + "resolved": "https://registry.npmjs.org/@cspell/dict-java/-/dict-java-5.0.11.tgz", + "integrity": "sha512-T4t/1JqeH33Raa/QK/eQe26FE17eUCtWu+JsYcTLkQTci2dk1DfcIKo8YVHvZXBnuM43ATns9Xs0s+AlqDeH7w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-julia": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-julia/-/dict-julia-1.1.0.tgz", + "integrity": "sha512-CPUiesiXwy3HRoBR3joUseTZ9giFPCydSKu2rkh6I2nVjXnl5vFHzOMLXpbF4HQ1tH2CNfnDbUndxD+I+7eL9w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-k8s": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@cspell/dict-k8s/-/dict-k8s-1.0.10.tgz", + "integrity": "sha512-313haTrX9prep1yWO7N6Xw4D6tvUJ0Xsx+YhCP+5YrrcIKoEw5Rtlg8R4PPzLqe6zibw6aJ+Eqq+y76Vx5BZkw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-kotlin": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-kotlin/-/dict-kotlin-1.1.0.tgz", + "integrity": "sha512-vySaVw6atY7LdwvstQowSbdxjXG6jDhjkWVWSjg1XsUckyzH1JRHXe9VahZz1i7dpoFEUOWQrhIe5B9482UyJQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-latex": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/@cspell/dict-latex/-/dict-latex-4.0.3.tgz", + "integrity": "sha512-2KXBt9fSpymYHxHfvhUpjUFyzrmN4c4P8mwIzweLyvqntBT3k0YGZJSriOdjfUjwSygrfEwiuPI1EMrvgrOMJw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-lorem-ipsum": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/@cspell/dict-lorem-ipsum/-/dict-lorem-ipsum-4.0.4.tgz", + "integrity": "sha512-+4f7vtY4dp2b9N5fn0za/UR0kwFq2zDtA62JCbWHbpjvO9wukkbl4rZg4YudHbBgkl73HRnXFgCiwNhdIA1JPw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-lua": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@cspell/dict-lua/-/dict-lua-4.0.7.tgz", + "integrity": "sha512-Wbr7YSQw+cLHhTYTKV6cAljgMgcY+EUAxVIZW3ljKswEe4OLxnVJ7lPqZF5JKjlXdgCjbPSimsHqyAbC5pQN/Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-makefile": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@cspell/dict-makefile/-/dict-makefile-1.0.4.tgz", + "integrity": "sha512-E4hG/c0ekPqUBvlkrVvzSoAA+SsDA9bLi4xSV3AXHTVru7Y2bVVGMPtpfF+fI3zTkww/jwinprcU1LSohI3ylw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-markdown": { + "version": "2.0.9", + "resolved": "https://registry.npmjs.org/@cspell/dict-markdown/-/dict-markdown-2.0.9.tgz", + "integrity": "sha512-j2e6Eg18BlTb1mMP1DkyRFMM/FLS7qiZjltpURzDckB57zDZbUyskOFdl4VX7jItZZEeY0fe22bSPOycgS1Z5A==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@cspell/dict-css": "^4.0.17", + "@cspell/dict-html": "^4.0.11", + "@cspell/dict-html-symbol-entities": "^4.0.3", + "@cspell/dict-typescript": "^3.2.0" + } + }, + "node_modules/@cspell/dict-monkeyc": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/@cspell/dict-monkeyc/-/dict-monkeyc-1.0.10.tgz", + "integrity": "sha512-7RTGyKsTIIVqzbvOtAu6Z/lwwxjGRtY5RkKPlXKHEoEAgIXwfDxb5EkVwzGQwQr8hF/D3HrdYbRT8MFBfsueZw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-node": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-node/-/dict-node-5.0.6.tgz", + "integrity": "sha512-CEbhPCpxGvRNByGolSBTrXXW2rJA4bGqZuTx1KKO85mwR6aadeOmUE7xf/8jiCkXSy+qvr9aJeh+jlfXcsrziQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-npm": { + "version": "5.1.26", + "resolved": "https://registry.npmjs.org/@cspell/dict-npm/-/dict-npm-5.1.26.tgz", + "integrity": "sha512-JU0/9P4nLPPC3Py+sF42tUKm9J4KAvwXaJubp2a4QwhCPzFVlOJTP2tTseFlLbdZn23d61pt0hZ+Jhyy7N76Mg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-php": { + "version": "4.0.14", + "resolved": "https://registry.npmjs.org/@cspell/dict-php/-/dict-php-4.0.14.tgz", + "integrity": "sha512-7zur8pyncYZglxNmqsRycOZ6inpDoVd4yFfz1pQRe5xaRWMiK3Km4n0/X/1YMWhh3e3Sl/fQg5Axb2hlN68t1g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-powershell": { + "version": "5.0.14", + "resolved": "https://registry.npmjs.org/@cspell/dict-powershell/-/dict-powershell-5.0.14.tgz", + "integrity": "sha512-ktjjvtkIUIYmj/SoGBYbr3/+CsRGNXGpvVANrY0wlm/IoGlGywhoTUDYN0IsGwI2b8Vktx3DZmQkfb3Wo38jBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-public-licenses": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@cspell/dict-public-licenses/-/dict-public-licenses-2.0.13.tgz", + "integrity": "sha512-1Wdp/XH1ieim7CadXYE7YLnUlW0pULEjVl9WEeziZw3EKCAw8ZI8Ih44m4bEa5VNBLnuP5TfqC4iDautAleQzQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-python": { + "version": "4.2.15", + "resolved": "https://registry.npmjs.org/@cspell/dict-python/-/dict-python-4.2.15.tgz", + "integrity": "sha512-VNXhj0Eh+hdHN89MgyaoSAexBQKmYtJaMhucbMI7XmBs4pf8fuFFN3xugk51/A4TZJr8+RImdFFsGMOw+I4bDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/dict-data-science": "^2.0.7" + } + }, + "node_modules/@cspell/dict-r": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-r/-/dict-r-2.1.0.tgz", + "integrity": "sha512-k2512wgGG0lTpTYH9w5Wwco+lAMf3Vz7mhqV8+OnalIE7muA0RSuD9tWBjiqLcX8zPvEJr4LdgxVju8Gk3OKyA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-ruby": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@cspell/dict-ruby/-/dict-ruby-5.0.7.tgz", + "integrity": "sha512-4/d0hcoPzi5Alk0FmcyqlzFW9lQnZh9j07MJzPcyVO62nYJJAGKaPZL2o4qHeCS/od/ctJC5AHRdoUm0ktsw6Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-rust": { + "version": "4.0.11", + "resolved": "https://registry.npmjs.org/@cspell/dict-rust/-/dict-rust-4.0.11.tgz", + "integrity": "sha512-OGWDEEzm8HlkSmtD8fV3pEcO2XBpzG2XYjgMCJCRwb2gRKvR+XIm6Dlhs04N/K2kU+iH8bvrqNpM8fS/BFl0uw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-scala": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@cspell/dict-scala/-/dict-scala-5.0.7.tgz", + "integrity": "sha512-yatpSDW/GwulzO3t7hB5peoWwzo+Y3qTc0pO24Jf6f88jsEeKmDeKkfgPbYuCgbE4jisGR4vs4+jfQZDIYmXPA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-shell": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-shell/-/dict-shell-1.1.0.tgz", + "integrity": "sha512-D/xHXX7T37BJxNRf5JJHsvziFDvh23IF/KvkZXNSh8VqcRdod3BAz9VGHZf6VDqcZXr1VRqIYR3mQ8DSvs3AVQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-software-terms": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/@cspell/dict-software-terms/-/dict-software-terms-4.2.5.tgz", + "integrity": "sha512-CaRzkWti3AgcXoxuRcMijaNG7YUk/MH1rHjB8VX34v3UdCxXXeqvRyElRKnxhFeVLB/robb2UdShqh/CpskxRg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-sql": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-sql/-/dict-sql-2.2.0.tgz", + "integrity": "sha512-MUop+d1AHSzXpBvQgQkCiok8Ejzb+nrzyG16E8TvKL2MQeDwnIvMe3bv90eukP6E1HWb+V/MA/4pnq0pcJWKqQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-svelte": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@cspell/dict-svelte/-/dict-svelte-1.0.6.tgz", + "integrity": "sha512-8LAJHSBdwHCoKCSy72PXXzz7ulGROD0rP1CQ0StOqXOOlTUeSFaJJlxNYjlONgd2c62XBQiN2wgLhtPN+1Zv7Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-swift": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@cspell/dict-swift/-/dict-swift-2.0.5.tgz", + "integrity": "sha512-3lGzDCwUmnrfckv3Q4eVSW3sK3cHqqHlPprFJZD4nAqt23ot7fic5ALR7J4joHpvDz36nHX34TgcbZNNZOC/JA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-terraform": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-terraform/-/dict-terraform-1.1.0.tgz", + "integrity": "sha512-G55pcUUxeXAhejstmD35B47SkFd4uqCQimc+CMgq8Nx0dr03guL2iMsz8faRWQGkCnGimX8S91rbOhDv9p/heg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-typescript": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@cspell/dict-typescript/-/dict-typescript-3.2.0.tgz", + "integrity": "sha512-Pk3zNePLT8qg51l0M4g1ISowYAEGxTuNfZlgkU5SvHa9Cu7x/BWoyYq9Fvc3kAyoisCjRPyvWF4uRYrPitPDFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dict-vue": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@cspell/dict-vue/-/dict-vue-3.0.4.tgz", + "integrity": "sha512-0dPtI0lwHcAgSiQFx8CzvqjdoXROcH+1LyqgROCpBgppommWpVhbQ0eubnKotFEXgpUCONVkeZJ6Ql8NbTEu+w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@cspell/dynamic-import": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/@cspell/dynamic-import/-/dynamic-import-8.17.3.tgz", + "integrity": "sha512-Kg6IJhGHPv+9OxpxaXUpcqgnHEOhMLRWHLyx7FADZ+CJyO4AVeWQfhpTRM6KXhzIl7dPlLG1g8JAQxaoy88KTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/url": "8.17.3", + "import-meta-resolve": "^4.1.0" + }, + "engines": { + "node": ">=18.0" + } + }, + "node_modules/@cspell/filetypes": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/@cspell/filetypes/-/filetypes-8.17.3.tgz", + "integrity": "sha512-UFqRmJPccOSo+RYP/jZ4cr0s7ni37GrvnNAg1H/qIIxfmBYsexTAmsNzMqxp1M31NeI1Cx3LL7PspPMT0ms+7w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@cspell/strong-weak-map": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/@cspell/strong-weak-map/-/strong-weak-map-8.17.3.tgz", + "integrity": "sha512-l/CaFc3CITI/dC+whEBZ05Om0KXR3V2whhVOWOBPIqA5lCjWAyvWWvmFD+CxWd0Hs6Qcb/YDnMyJW14aioXN4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@cspell/url": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/@cspell/url/-/url-8.17.3.tgz", + "integrity": "sha512-gcsCz8g0qY94C8RXiAlUH/89n84Q9RSptP91XrvnLOT+Xva9Aibd7ywd5k9ameuf8Nagyl0ezB1MInZ30S9SRw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.0" + } + }, "node_modules/@csstools/color-helpers": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.1.tgz", @@ -4400,6 +4989,13 @@ "node": ">=0.10.0" } }, + "node_modules/array-timsort": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-timsort/-/array-timsort-1.0.3.tgz", + "integrity": "sha512-/+3GRL7dDAGEfM6TseQk/U+mi18TU2Ms9I3UlLdUMhz2hbvGNTKdj9xniwXfUqgYhHxRx0+8UnKkvlNwVU+cWQ==", + "dev": true, + "license": "MIT" + }, "node_modules/arrify": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", @@ -5687,6 +6283,35 @@ "node": ">=0.10.0" } }, + "node_modules/chalk-template": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/chalk-template/-/chalk-template-1.1.0.tgz", + "integrity": "sha512-T2VJbcDuZQ0Tb2EWwSotMPJjgpy1/tGee1BTpUNsGZ/qgNjV2t7Mvu+d4600U564nbLesN1x2dPL+xii174Ekg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.2.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/chalk/chalk-template?sponsor=1" + } + }, + "node_modules/chalk-template/node_modules/chalk": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", + "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, "node_modules/check-error": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.2.tgz", @@ -5813,6 +6438,46 @@ "node": ">= 10.0" } }, + "node_modules/clear-module": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/clear-module/-/clear-module-4.1.2.tgz", + "integrity": "sha512-LWAxzHqdHsAZlPlEyJ2Poz6AIs384mPeqLVCru2p0BrP9G/kVGuhNyZYClLO6cXlnuJjzC8xtsJIuMjKqLXoAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^2.0.0", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/clear-module/node_modules/parent-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-2.0.0.tgz", + "integrity": "sha512-uo0Z9JJeWzv8BG+tRcapBKNJ0dro9cLyczGzulS6EfeyAdeC9sbojtW6XwvYxJkEne9En+J2XEl4zyglVeIwFg==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/clear-module/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/cli-boxes": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz", @@ -5994,6 +6659,23 @@ "node": ">= 10" } }, + "node_modules/comment-json": { + "version": "4.2.5", + "resolved": "https://registry.npmjs.org/comment-json/-/comment-json-4.2.5.tgz", + "integrity": "sha512-bKw/r35jR3HGt5PEPm1ljsQQGyCrR8sFGNiN5L+ykDHdpO8Smxkrkla9Yi6NkQyUrb8V54PGhfMs6NrIwtxtdw==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-timsort": "^1.0.3", + "core-util-is": "^1.0.3", + "esprima": "^4.0.1", + "has-own-prop": "^2.0.0", + "repeat-string": "^1.6.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/comment-parser": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.1.tgz", @@ -6492,6 +7174,275 @@ "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==", "license": "MIT" }, + "node_modules/cspell": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/cspell/-/cspell-8.17.3.tgz", + "integrity": "sha512-fBZg674Dir9y/FWMwm2JyixM/1eB2vnqHJjRxOgGS/ZiZ3QdQ3LkK02Aqvlni8ffWYDZnYnYY9rfWmql9bb42w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-json-reporter": "8.17.3", + "@cspell/cspell-pipe": "8.17.3", + "@cspell/cspell-types": "8.17.3", + "@cspell/dynamic-import": "8.17.3", + "@cspell/url": "8.17.3", + "chalk": "^5.4.1", + "chalk-template": "^1.1.0", + "commander": "^13.1.0", + "cspell-dictionary": "8.17.3", + "cspell-gitignore": "8.17.3", + "cspell-glob": "8.17.3", + "cspell-io": "8.17.3", + "cspell-lib": "8.17.3", + "fast-json-stable-stringify": "^2.1.0", + "file-entry-cache": "^9.1.0", + "get-stdin": "^9.0.0", + "semver": "^7.6.3", + "tinyglobby": "^0.2.10" + }, + "bin": { + "cspell": "bin.mjs", + "cspell-esm": "bin.mjs" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/streetsidesoftware/cspell?sponsor=1" + } + }, + "node_modules/cspell-config-lib": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/cspell-config-lib/-/cspell-config-lib-8.17.3.tgz", + "integrity": "sha512-+N32Q6xck3D2RqZIFwq8s0TnzHYMpyh4bgNtYqW5DIP3TLDiA4/MJGjwmLKAg/s9dkre6n8/++vVli3MZAOhIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-types": "8.17.3", + "comment-json": "^4.2.5", + "yaml": "^2.7.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cspell-dictionary": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/cspell-dictionary/-/cspell-dictionary-8.17.3.tgz", + "integrity": "sha512-89I/lpQKdkX17RCFrUIJnc70Rjfpup/o+ynHZen0hUxGTfLsEJPrK6H2oGvic3Yrv5q8IOtwM1p8vqPqBkBheA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-pipe": "8.17.3", + "@cspell/cspell-types": "8.17.3", + "cspell-trie-lib": "8.17.3", + "fast-equals": "^5.2.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cspell-gitignore": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-8.17.3.tgz", + "integrity": "sha512-rQamjb8R+Nwib/Bpcgf+xv5IdsOHgbP+fe4hCgv0jjgUPkeOR2c4dGwc0WS+2UkJbc+wQohpzBGDLRYGSB/hQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/url": "8.17.3", + "cspell-glob": "8.17.3", + "cspell-io": "8.17.3", + "find-up-simple": "^1.0.0" + }, + "bin": { + "cspell-gitignore": "bin.mjs" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cspell-glob": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-8.17.3.tgz", + "integrity": "sha512-0ov9A0E6OuOO7KOxlGCxJ09LR/ubZ6xcGwWc5bu+jp/8onUowQfe+9vZdznj/o8/vcf5JkDzyhRSBsdhWKqoAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/url": "8.17.3", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cspell-grammar": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/cspell-grammar/-/cspell-grammar-8.17.3.tgz", + "integrity": "sha512-wfjkkvHthnKJtEaTgx3cPUPquGRXfgXSCwvMJaDyUi36KBlopXX38PejBTdmuqrvp7bINLSuHErml9wAfL5Fxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-pipe": "8.17.3", + "@cspell/cspell-types": "8.17.3" + }, + "bin": { + "cspell-grammar": "bin.mjs" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cspell-io": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-8.17.3.tgz", + "integrity": "sha512-NwEVb3Kr8loV1C8Stz9QSMgUrBkxqf2s7A9H2/RBnfvQBt9CWZS6NgoNxTPwHj3h1sUNl9reDkMQQzkKtgWGBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-service-bus": "8.17.3", + "@cspell/url": "8.17.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cspell-lib": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-8.17.3.tgz", + "integrity": "sha512-KpwYIj8HwFyTzCCQcyezlmomvyNfPwZQmqTh4V126sFvf9HLoMdfyq8KYDZmZ//4HzwrF/ufJOF3CpuVUiJHfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-bundled-dicts": "8.17.3", + "@cspell/cspell-pipe": "8.17.3", + "@cspell/cspell-resolver": "8.17.3", + "@cspell/cspell-types": "8.17.3", + "@cspell/dynamic-import": "8.17.3", + "@cspell/filetypes": "8.17.3", + "@cspell/strong-weak-map": "8.17.3", + "@cspell/url": "8.17.3", + "clear-module": "^4.1.2", + "comment-json": "^4.2.5", + "cspell-config-lib": "8.17.3", + "cspell-dictionary": "8.17.3", + "cspell-glob": "8.17.3", + "cspell-grammar": "8.17.3", + "cspell-io": "8.17.3", + "cspell-trie-lib": "8.17.3", + "env-paths": "^3.0.0", + "fast-equals": "^5.2.2", + "gensequence": "^7.0.0", + "import-fresh": "^3.3.0", + "resolve-from": "^5.0.0", + "vscode-languageserver-textdocument": "^1.0.12", + "vscode-uri": "^3.0.8", + "xdg-basedir": "^5.1.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cspell-lib/node_modules/env-paths": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", + "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cspell-lib/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/cspell-trie-lib": { + "version": "8.17.3", + "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-8.17.3.tgz", + "integrity": "sha512-6LE5BeT2Rwv0bkQckpxX0K1fnFCWfeJ8zVPFtYOaix0trtqj0VNuwWzYDnxyW+OwMioCH29yRAMODa+JDFfUrA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspell/cspell-pipe": "8.17.3", + "@cspell/cspell-types": "8.17.3", + "gensequence": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cspell/node_modules/chalk": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.4.1.tgz", + "integrity": "sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cspell/node_modules/commander": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/cspell/node_modules/file-entry-cache": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-9.1.0.tgz", + "integrity": "sha512-/pqPFG+FdxWQj+/WSuzXSDaNzxgTLr/OrR1QuqfEZzDakpdYE70PwUxL7BPUa8hpjbvY1+qvCl8k+8Tq34xJgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cspell/node_modules/flat-cache": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-5.0.0.tgz", + "integrity": "sha512-JrqFmyUl2PnPi1OvLyTVHnQvwQ0S+e6lGSwu8OkAZlSaNIZciTY2H/cOOROxsBA1m/LZNHDsqAgDZt6akWcjsQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.3.1", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/cspell/node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/css-loader": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-7.1.2.tgz", @@ -8480,6 +9431,16 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-equals": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.2.2.tgz", + "integrity": "sha512-V7/RktU11J3I36Nwq2JnZEM7tNm17eBJz+u25qdxBZeCKiX6BkVSZQjwWIr+IobgnZy+ag73tTZgZi7tr0LrBw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/fast-glob": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", @@ -8749,6 +9710,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/find-up-simple": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.0.tgz", + "integrity": "sha512-q7Us7kcjj2VMePAa02hDAF6d+MzsdsAWEwYyOpwUtlerRBkOEPBCRZrAV4XfcSN8fHAgaD0hP7miwoay6DCprw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/findup-sync": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-5.0.0.tgz", @@ -9023,6 +9997,16 @@ "node": ">= 4.0.0" } }, + "node_modules/gensequence": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/gensequence/-/gensequence-7.0.0.tgz", + "integrity": "sha512-47Frx13aZh01afHJTB3zTtKIlFI6vWY+MYCN9Qpew6i52rfKjnhCF/l1YlC8UmEMvvntZZ6z4PiCcmyuedR2aQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -9096,6 +10080,19 @@ "node": ">= 0.4" } }, + "node_modules/get-stdin": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", + "integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-stream": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", @@ -9198,6 +10195,32 @@ "process": "^0.11.10" } }, + "node_modules/global-directory": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", + "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ini": "4.1.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-directory/node_modules/ini": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "node_modules/global-modules": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", @@ -9838,6 +10861,16 @@ "node": ">=8" } }, + "node_modules/has-own-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-own-prop/-/has-own-prop-2.0.0.tgz", + "integrity": "sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/has-property-descriptors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", @@ -10369,6 +11402,17 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/import-meta-resolve": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", + "integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/imports-loader": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/imports-loader/-/imports-loader-5.0.0.tgz", @@ -14900,6 +15944,16 @@ "node": ">=8" } }, + "node_modules/repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -16486,6 +17540,48 @@ "integrity": "sha512-XPaBkWQJdsf3pLKJV9p4qN/S+fm2Oj8AIPo1BTUhg5oxkvm9+SVEGFdhyOz7tTdUTfvxMiAs4sp6/eZO2Ew+pw==", "license": "MIT" }, + "node_modules/tinyglobby": { + "version": "0.2.10", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.10.tgz", + "integrity": "sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.4.2", + "picomatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/tinyglobby/node_modules/fdir": { + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz", + "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/tmp": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", @@ -17031,6 +18127,20 @@ "integrity": "sha512-2ozZEFfmVvQcHWoHLNuiKlUfDKlhh4KGsy54U0UrlLMR1SO+XKAIDqBxtBwHgNrekurlJwE8A9K6L49T78ZQ9Q==", "license": "MIT" }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", + "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "dev": true, + "license": "MIT" + }, "node_modules/w3c-keyname": { "version": "2.2.8", "resolved": "https://registry.npmjs.org/w3c-keyname/-/w3c-keyname-2.2.8.tgz", @@ -17941,6 +19051,19 @@ } } }, + "node_modules/xdg-basedir": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-5.1.0.tgz", + "integrity": "sha512-GCPAHLvrIH13+c0SuacwvRYj2SxJXQ4kaVTT5xgL3kPrz56XxkF21IGhjSE1+W0aw7gpBWRGXLCPnPby6lSpmQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/xhr": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/xhr/-/xhr-2.6.0.tgz", @@ -18042,6 +19165,19 @@ "dev": true, "license": "ISC" }, + "node_modules/yaml": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.0.tgz", + "integrity": "sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", diff --git a/package.json b/package.json index 7c8a97de..20180e05 100644 --- a/package.json +++ b/package.json @@ -61,6 +61,7 @@ "compression-webpack-plugin": "^11.1.0", "copy-webpack-plugin": "^12.0.2", "core-js": "^3.37.1", + "cspell": "^8.17.3", "css-loader": "7.1.2", "eslint": "^9.4.0", "eslint-plugin-jsdoc": "^48.2.9", @@ -193,6 +194,7 @@ "testui": "npx grunt testui", "testuidev": "npx nightwatch --env=dev", "lint": "npx grunt lint", + "lint:grammar": "cspell ./src", "postinstall": "npx grunt exec:fixCryptoApiImports && npx grunt exec:fixSnackbarMarkup && npx grunt exec:fixJimpModule", "newop": "node --experimental-modules --experimental-json-modules src/core/config/scripts/newOperation.mjs", "minor": "node --experimental-modules --experimental-json-modules src/core/config/scripts/newMinorVersion.mjs", From 6ccbc892c77bed565a82ff990b800664357a389c Mon Sep 17 00:00:00 2001 From: David Marshall Date: Sun, 16 Feb 2025 09:03:46 -0500 Subject: [PATCH 17/18] CC-1889 --- src/core/lib/Extract.mjs | 6 ++++++ src/core/operations/ExtractDomains.mjs | 11 ++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/core/lib/Extract.mjs b/src/core/lib/Extract.mjs index 18fec28c..3de2dd6d 100644 --- a/src/core/lib/Extract.mjs +++ b/src/core/lib/Extract.mjs @@ -62,3 +62,9 @@ export const URL_REGEX = new RegExp(protocol + hostname + "(?:" + port + ")?(?:" * Domain name regular expression */ export const DOMAIN_REGEX = /\b((?=[a-z0-9-]{1,63}\.)(xn--)?[a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{2,63}\b/ig; + + +/** + * DMARC Domain name regular expression + */ +export const DMARC_DOMAIN_REGEX = /\b((?=[a-z0-9_-]{1,63}\.)(xn--)?[a-z0-9_]+(-[a-z0-9_]+)*\.)+[a-z]{2,63}\b/ig; diff --git a/src/core/operations/ExtractDomains.mjs b/src/core/operations/ExtractDomains.mjs index c28efbb5..9e78bf3a 100644 --- a/src/core/operations/ExtractDomains.mjs +++ b/src/core/operations/ExtractDomains.mjs @@ -5,7 +5,7 @@ */ import Operation from "../Operation.mjs"; -import { search, DOMAIN_REGEX } from "../lib/Extract.mjs"; +import { search, DOMAIN_REGEX, DMARC_DOMAIN_REGEX } from "../lib/Extract.mjs"; import { caseInsensitiveSort } from "../lib/Sort.mjs"; /** @@ -39,6 +39,11 @@ class ExtractDomains extends Operation { name: "Unique", type: "boolean", value: false + }, + { + name: "Underscore (DMARC, DKIM, etc)", + type: "boolean", + value: false } ]; } @@ -49,11 +54,11 @@ class ExtractDomains extends Operation { * @returns {string} */ run(input, args) { - const [displayTotal, sort, unique] = args; + const [displayTotal, sort, unique, dmarc] = args; const results = search( input, - DOMAIN_REGEX, + dmarc ? DMARC_DOMAIN_REGEX : DOMAIN_REGEX, null, sort ? caseInsensitiveSort : null, unique From 7babef6f93be06440bbf88a2375b4e7c34348698 Mon Sep 17 00:00:00 2001 From: bartblaze <3075118+bartblaze@users.noreply.github.com> Date: Mon, 17 Feb 2025 17:35:22 +0100 Subject: [PATCH 18/18] Preserve uppercase This will preserve uppercase. --- src/core/operations/ConvertLeetSpeak.mjs | 13 +++++++----- tests/operations/tests/ConvertLeetSpeak.mjs | 22 +++++++++++++++++++++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/core/operations/ConvertLeetSpeak.mjs b/src/core/operations/ConvertLeetSpeak.mjs index 54fa62f6..1a7cb2fc 100644 --- a/src/core/operations/ConvertLeetSpeak.mjs +++ b/src/core/operations/ConvertLeetSpeak.mjs @@ -18,7 +18,7 @@ class ConvertLeetSpeak extends Operation { this.name = "Convert Leet Speak"; this.module = "Default"; - this.description = "Converts to and from Leet Speak"; + this.description = "Converts to and from Leet Speak."; this.infoURL = "https://wikipedia.org/wiki/Leet"; this.inputType = "string"; this.outputType = "string"; @@ -39,13 +39,16 @@ class ConvertLeetSpeak extends Operation { */ run(input, args) { const direction = args[0]; + if (direction === "To Leet Speak") { - return input.replace(/[abcdefghijklmnopqrstuvwxyz]/gi, char => { - return toLeetMap[char.toLowerCase()] || char; + return input.replace(/[a-z]/gi, char => { + const leetChar = toLeetMap[char.toLowerCase()] || char; + return char === char.toUpperCase() ? leetChar.toUpperCase() : leetChar; }); } else if (direction === "From Leet Speak") { - return input.replace(/[48cd3f6h1jklmn0pqr57uvwxyz]/g, char => { - return fromLeetMap[char] || char; + return input.replace(/[48cd3f6h1jklmn0pqr57uvwxyz]/gi, char => { + const normalChar = fromLeetMap[char] || char; + return normalChar; }); } } diff --git a/tests/operations/tests/ConvertLeetSpeak.mjs b/tests/operations/tests/ConvertLeetSpeak.mjs index 198f7e57..d3445803 100644 --- a/tests/operations/tests/ConvertLeetSpeak.mjs +++ b/tests/operations/tests/ConvertLeetSpeak.mjs @@ -28,6 +28,28 @@ TestRegister.addTests([ args: ["From Leet Speak"] } ] + }, + { + name: "Convert to Leet Speak: basic text, keep case", + input: "HELLO", + expectedOutput: "H3LL0", + recipeConfig: [ + { + op: "Convert Leet Speak", + args: ["To Leet Speak"] + } + ] + }, + { + name: "Convert from Leet Speak: basic leet, keep case", + input: "H3LL0", + expectedOutput: "HeLLo", + recipeConfig: [ + { + op: "Convert Leet Speak", + args: ["From Leet Speak"] + } + ] } ]);