Files
FrenoCorp/node_modules/postal-mime/dist/postal-mime.cjs

497 lines
18 KiB
JavaScript

"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
var postal_mime_exports = {};
__export(postal_mime_exports, {
addressParser: () => import_address_parser.default,
decodeWords: () => import_decode_strings.decodeWords,
default: () => PostalMime
});
module.exports = __toCommonJS(postal_mime_exports);
var import_mime_node = __toESM(require("./mime-node.cjs"), 1);
var import_text_format = require("./text-format.cjs");
var import_address_parser = __toESM(require("./address-parser.cjs"), 1);
var import_decode_strings = require("./decode-strings.cjs");
var import_base64_encoder = require("./base64-encoder.cjs");
const MAX_NESTING_DEPTH = 256;
const MAX_HEADERS_SIZE = 2 * 1024 * 1024;
function toCamelCase(key) {
return key.replace(/-(.)/g, (o, c) => c.toUpperCase());
}
class PostalMime {
static parse(buf, options) {
const parser = new PostalMime(options);
return parser.parse(buf);
}
constructor(options) {
this.options = options || {};
this.mimeOptions = {
maxNestingDepth: this.options.maxNestingDepth || MAX_NESTING_DEPTH,
maxHeadersSize: this.options.maxHeadersSize || MAX_HEADERS_SIZE
};
this.root = this.currentNode = new import_mime_node.default({
postalMime: this,
...this.mimeOptions
});
this.boundaries = [];
this.textContent = {};
this.attachments = [];
this.attachmentEncoding = (this.options.attachmentEncoding || "").toString().replace(/[-_\s]/g, "").trim().toLowerCase() || "arraybuffer";
this.started = false;
}
async finalize() {
await this.root.finalize();
}
async processLine(line, isFinal) {
let boundaries = this.boundaries;
if (boundaries.length && line.length > 2 && line[0] === 45 && line[1] === 45) {
for (let i = boundaries.length - 1; i >= 0; i--) {
let boundary = boundaries[i];
if (line.length < boundary.value.length + 2) {
continue;
}
let boundaryMatches = true;
for (let j = 0; j < boundary.value.length; j++) {
if (line[j + 2] !== boundary.value[j]) {
boundaryMatches = false;
break;
}
}
if (!boundaryMatches) {
continue;
}
let boundaryEnd = boundary.value.length + 2;
let isTerminator = false;
if (line.length >= boundary.value.length + 4 && line[boundary.value.length + 2] === 45 && line[boundary.value.length + 3] === 45) {
isTerminator = true;
boundaryEnd = boundary.value.length + 4;
}
let hasValidTrailing = true;
for (let j = boundaryEnd; j < line.length; j++) {
if (line[j] !== 32 && line[j] !== 9) {
hasValidTrailing = false;
break;
}
}
if (!hasValidTrailing) {
continue;
}
if (isTerminator) {
await boundary.node.finalize();
this.currentNode = boundary.node.parentNode || this.root;
} else {
await boundary.node.finalizeChildNodes();
this.currentNode = new import_mime_node.default({
postalMime: this,
parentNode: boundary.node,
parentMultipartType: boundary.node.contentType.multipart,
...this.mimeOptions
});
}
if (isFinal) {
return this.finalize();
}
return;
}
}
this.currentNode.feed(line);
if (isFinal) {
return this.finalize();
}
}
readLine() {
let startPos = this.readPos;
let endPos = this.readPos;
while (this.readPos < this.av.length) {
const c = this.av[this.readPos++];
if (c !== 13 && c !== 10) {
endPos = this.readPos;
}
if (c === 10) {
return {
bytes: new Uint8Array(this.buf, startPos, endPos - startPos),
done: this.readPos >= this.av.length
};
}
}
return {
bytes: new Uint8Array(this.buf, startPos, endPos - startPos),
done: this.readPos >= this.av.length
};
}
async processNodeTree() {
let textContent = {};
let textTypes = /* @__PURE__ */ new Set();
let textMap = this.textMap = /* @__PURE__ */ new Map();
let forceRfc822Attachments = this.forceRfc822Attachments();
let walk = async (node, alternative, related) => {
var _a, _b, _c, _d, _e;
alternative = alternative || false;
related = related || false;
if (!node.contentType.multipart) {
if (this.isInlineMessageRfc822(node) && !forceRfc822Attachments) {
const subParser = new PostalMime();
node.subMessage = await subParser.parse(node.content);
if (!textMap.has(node)) {
textMap.set(node, {});
}
let textEntry = textMap.get(node);
if (node.subMessage.text || !node.subMessage.html) {
textEntry.plain = textEntry.plain || [];
textEntry.plain.push({ type: "subMessage", value: node.subMessage });
textTypes.add("plain");
}
if (node.subMessage.html) {
textEntry.html = textEntry.html || [];
textEntry.html.push({ type: "subMessage", value: node.subMessage });
textTypes.add("html");
}
if (subParser.textMap) {
subParser.textMap.forEach((subTextEntry, subTextNode) => {
textMap.set(subTextNode, subTextEntry);
});
}
for (let attachment of node.subMessage.attachments || []) {
this.attachments.push(attachment);
}
} else if (this.isInlineTextNode(node)) {
let textType = node.contentType.parsed.value.substr(node.contentType.parsed.value.indexOf("/") + 1);
let selectorNode = alternative || node;
if (!textMap.has(selectorNode)) {
textMap.set(selectorNode, {});
}
let textEntry = textMap.get(selectorNode);
textEntry[textType] = textEntry[textType] || [];
textEntry[textType].push({ type: "text", value: node.getTextContent() });
textTypes.add(textType);
} else if (node.content) {
const filename = ((_c = (_b = (_a = node.contentDisposition) == null ? void 0 : _a.parsed) == null ? void 0 : _b.params) == null ? void 0 : _c.filename) || node.contentType.parsed.params.name || null;
const attachment = {
filename: filename ? (0, import_decode_strings.decodeWords)(filename) : null,
mimeType: node.contentType.parsed.value,
disposition: ((_e = (_d = node.contentDisposition) == null ? void 0 : _d.parsed) == null ? void 0 : _e.value) || null
};
if (related && node.contentId) {
attachment.related = true;
}
if (node.contentDescription) {
attachment.description = node.contentDescription;
}
if (node.contentId) {
attachment.contentId = node.contentId;
}
switch (node.contentType.parsed.value) {
// Special handling for calendar events
case "text/calendar":
case "application/ics": {
if (node.contentType.parsed.params.method) {
attachment.method = node.contentType.parsed.params.method.toString().toUpperCase().trim();
}
const decodedText = node.getTextContent().replace(/\r?\n/g, "\n").replace(/\n*$/, "\n");
attachment.content = import_decode_strings.textEncoder.encode(decodedText);
break;
}
// Regular attachments
default:
attachment.content = node.content;
}
this.attachments.push(attachment);
}
} else if (node.contentType.multipart === "alternative") {
alternative = node;
} else if (node.contentType.multipart === "related") {
related = node;
}
for (let childNode of node.childNodes) {
await walk(childNode, alternative, related);
}
};
await walk(this.root, false, false);
textMap.forEach((mapEntry) => {
textTypes.forEach((textType) => {
if (!textContent[textType]) {
textContent[textType] = [];
}
if (mapEntry[textType]) {
mapEntry[textType].forEach((textEntry) => {
switch (textEntry.type) {
case "text":
textContent[textType].push(textEntry.value);
break;
case "subMessage":
{
switch (textType) {
case "html":
textContent[textType].push((0, import_text_format.formatHtmlHeader)(textEntry.value));
break;
case "plain":
textContent[textType].push((0, import_text_format.formatTextHeader)(textEntry.value));
break;
}
}
break;
}
});
} else {
let alternativeType;
switch (textType) {
case "html":
alternativeType = "plain";
break;
case "plain":
alternativeType = "html";
break;
}
(mapEntry[alternativeType] || []).forEach((textEntry) => {
switch (textEntry.type) {
case "text":
switch (textType) {
case "html":
textContent[textType].push((0, import_text_format.textToHtml)(textEntry.value));
break;
case "plain":
textContent[textType].push((0, import_text_format.htmlToText)(textEntry.value));
break;
}
break;
case "subMessage":
{
switch (textType) {
case "html":
textContent[textType].push((0, import_text_format.formatHtmlHeader)(textEntry.value));
break;
case "plain":
textContent[textType].push((0, import_text_format.formatTextHeader)(textEntry.value));
break;
}
}
break;
}
});
}
});
});
Object.keys(textContent).forEach((textType) => {
textContent[textType] = textContent[textType].join("\n");
});
this.textContent = textContent;
}
isInlineTextNode(node) {
var _a, _b, _c;
if (((_b = (_a = node.contentDisposition) == null ? void 0 : _a.parsed) == null ? void 0 : _b.value) === "attachment") {
return false;
}
switch ((_c = node.contentType.parsed) == null ? void 0 : _c.value) {
case "text/html":
case "text/plain":
return true;
case "text/calendar":
case "text/csv":
default:
return false;
}
}
isInlineMessageRfc822(node) {
var _a, _b, _c;
if (((_a = node.contentType.parsed) == null ? void 0 : _a.value) !== "message/rfc822") {
return false;
}
let disposition = ((_c = (_b = node.contentDisposition) == null ? void 0 : _b.parsed) == null ? void 0 : _c.value) || (this.options.rfc822Attachments ? "attachment" : "inline");
return disposition === "inline";
}
// Check if this is a specially crafted report email where message/rfc822 content should not be inlined
forceRfc822Attachments() {
if (this.options.forceRfc822Attachments) {
return true;
}
let forceRfc822Attachments = false;
let walk = (node) => {
if (!node.contentType.multipart) {
if (node.contentType.parsed && ["message/delivery-status", "message/feedback-report"].includes(node.contentType.parsed.value)) {
forceRfc822Attachments = true;
}
}
for (let childNode of node.childNodes) {
walk(childNode);
}
};
walk(this.root);
return forceRfc822Attachments;
}
async resolveStream(stream) {
let chunkLen = 0;
let chunks = [];
const reader = stream.getReader();
while (true) {
const { done, value } = await reader.read();
if (done) {
break;
}
chunks.push(value);
chunkLen += value.length;
}
const result = new Uint8Array(chunkLen);
let chunkPointer = 0;
for (let chunk of chunks) {
result.set(chunk, chunkPointer);
chunkPointer += chunk.length;
}
return result;
}
async parse(buf) {
var _a, _b;
if (this.started) {
throw new Error("Can not reuse parser, create a new PostalMime object");
}
this.started = true;
if (buf && typeof buf.getReader === "function") {
buf = await this.resolveStream(buf);
}
buf = buf || new ArrayBuffer(0);
if (typeof buf === "string") {
buf = import_decode_strings.textEncoder.encode(buf);
}
if (buf instanceof Blob || Object.prototype.toString.call(buf) === "[object Blob]") {
buf = await (0, import_decode_strings.blobToArrayBuffer)(buf);
}
if (buf.buffer instanceof ArrayBuffer) {
buf = new Uint8Array(buf).buffer;
}
this.buf = buf;
this.av = new Uint8Array(buf);
this.readPos = 0;
while (this.readPos < this.av.length) {
const line = this.readLine();
await this.processLine(line.bytes, line.done);
}
await this.processNodeTree();
const message = {
headers: this.root.headers.map((entry) => ({ key: entry.key, originalKey: entry.originalKey, value: entry.value })).reverse()
};
for (const key of ["from", "sender"]) {
const addressHeader = this.root.headers.find((line) => line.key === key);
if (addressHeader && addressHeader.value) {
const addresses = (0, import_address_parser.default)(addressHeader.value);
if (addresses && addresses.length) {
message[key] = addresses[0];
}
}
}
for (const key of ["delivered-to", "return-path"]) {
const addressHeader = this.root.headers.find((line) => line.key === key);
if (addressHeader && addressHeader.value) {
const addresses = (0, import_address_parser.default)(addressHeader.value);
if (addresses && addresses.length && addresses[0].address) {
const camelKey = toCamelCase(key);
message[camelKey] = addresses[0].address;
}
}
}
for (const key of ["to", "cc", "bcc", "reply-to"]) {
const addressHeaders = this.root.headers.filter((line) => line.key === key);
let addresses = [];
addressHeaders.filter((entry) => entry && entry.value).map((entry) => (0, import_address_parser.default)(entry.value)).forEach((parsed) => addresses = addresses.concat(parsed || []));
if (addresses && addresses.length) {
const camelKey = toCamelCase(key);
message[camelKey] = addresses;
}
}
for (const key of ["subject", "message-id", "in-reply-to", "references"]) {
const header = this.root.headers.find((line) => line.key === key);
if (header && header.value) {
const camelKey = toCamelCase(key);
message[camelKey] = (0, import_decode_strings.decodeWords)(header.value);
}
}
let dateHeader = this.root.headers.find((line) => line.key === "date");
if (dateHeader) {
let date = new Date(dateHeader.value);
if (date.toString() === "Invalid Date") {
date = dateHeader.value;
} else {
date = date.toISOString();
}
message.date = date;
}
if ((_a = this.textContent) == null ? void 0 : _a.html) {
message.html = this.textContent.html;
}
if ((_b = this.textContent) == null ? void 0 : _b.plain) {
message.text = this.textContent.plain;
}
message.attachments = this.attachments;
message.headerLines = (this.root.rawHeaderLines || []).slice().reverse();
switch (this.attachmentEncoding) {
case "arraybuffer":
break;
case "base64":
for (let attachment of message.attachments || []) {
if (attachment == null ? void 0 : attachment.content) {
attachment.content = (0, import_base64_encoder.base64ArrayBuffer)(attachment.content);
attachment.encoding = "base64";
}
}
break;
case "utf8":
let attachmentDecoder = new TextDecoder("utf8");
for (let attachment of message.attachments || []) {
if (attachment == null ? void 0 : attachment.content) {
attachment.content = attachmentDecoder.decode(attachment.content);
attachment.encoding = "utf8";
}
}
break;
default:
throw new Error("Unknown attachment encoding");
}
return message;
}
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
addressParser,
decodeWords
});
// Make default export work naturally with require()
if (module.exports.default) {
var defaultExport = module.exports.default;
var namedExports = {};
for (var key in module.exports) {
if (key !== 'default' && key !== '__esModule') {
namedExports[key] = module.exports[key];
}
}
module.exports = defaultExport;
Object.assign(module.exports, namedExports);
// Preserve __esModule and .default for bundler/transpiler interop
Object.defineProperty(module.exports, '__esModule', { value: true });
module.exports.default = defaultExport;
}