From 8166f981ae7b6ef6644b8c9fe7ed652d1ea75c59 Mon Sep 17 00:00:00 2001 From: mshwed Date: Tue, 27 Aug 2019 11:41:16 -0400 Subject: [PATCH 1/7] 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 0000000000..fb36326f6b --- /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 2/7] 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 fb36326f6b..c7844ad87f 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 3/7] Added parsing of headers. --- src/core/operations/MIMEDecoding.mjs | 196 +++++++++++++++--------- tests/operations/index.mjs | 10 +- tests/operations/tests/MIMEDecoding.mjs | 46 ++++++ 3 files changed, 173 insertions(+), 79 deletions(-) create mode 100644 tests/operations/tests/MIMEDecoding.mjs diff --git a/src/core/operations/MIMEDecoding.mjs b/src/core/operations/MIMEDecoding.mjs index c7844ad87f..963bcd3b76 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"); + + const decodedHeader = this.decodeHeaders(encodedHeaders); + + return decodedHeader; + } + + /** + * Decode MIME header strings + * + * @param headerString + */ + decodeHeaders(headerString) { + // No encoded words detected + let i = headerString.indexOf("=?"); + if (i === -1) return headerString; + + let decodedHeaders = headerString.slice(0, i); + let header = headerString.slice(i); + + 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; - let mimeEncodedText = Utils.byteArrayToUtf8(input) - - 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); + 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); + } + + 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 parsedString; + if (header.length > 0) { + decodedHeaders += header; + } - throw new OperationError("Test"); + return decodedHeaders; } - 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; - 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}`))) + /** + * 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); } - - encodedText = encodedText.replace("_", " "); } - return 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 991bd3565c..259ec1e1c1 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 0000000000..f358d63f79 --- /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 4/7] 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 f358d63f79..b3e51d8fea 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 5/7] 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 963bcd3b76..2d7eac99e8 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 b3e51d8fea..b99fc489e1 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 6/7] 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 259ec1e1c1..0f61fd90dd 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 7/7] 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 1f309d8259..de3ea8826a 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 2d7eac99e8..7b52fbdd25 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 0f61fd90dd..a82bc874c6 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";