Newer
Older
import dataUriToBlob from "data-uri-to-blob";
import libmime from "libmime";
import union from "lodash/union";
import {
fixNewLines,
parseMIME,
getHTML,
getPlain,
getAttachments,
getAttachment,
getGlobalHeaderValue
} from "../helpers/mailparser";
import { getCertificateChain } from "./signingUtilities";
const SIGNATURE_CONTENT_TYPE = "application/pkcs7-signature";
const splitParticipants = participantsList => {
if (!participantsList) {
return [];
}
const participants = participantsList.map(participants =>
participants.split(",").map(p => p.trim())
);
return union.apply(null, participants);
};
export const parseSMIME = smimeString => {
return new Promise(resolve => {
setTimeout(async () => {
const emailString = fixNewLines(smimeString);
const parts = parseMIME(emailString);
const html = getHTML(emailString, parts);
const plain = getPlain(emailString, parts);
const rawAttachments = getAttachments(emailString, parts);
const attachments = [];
let signatureBase64;
for (const rawAttachment of rawAttachments) {
const { contentType, base64 } = getAttachment(
emailString,
rawAttachment
);
if (contentType.indexOf(SIGNATURE_CONTENT_TYPE) !== -1) {
signatureBase64 = base64;
}
const dataURI = "data:" + contentType + ";base64, " + base64;
const blob = dataUriToBlob(dataURI);
const filename = getFilenameFromHeaders(rawAttachment.headers);
attachments.push({
blob,
filename
});
}
const certificateChain = getCertificateChain(signatureBase64);
const from = splitParticipants(getGlobalHeaderValue("from", parts));
const to = splitParticipants(getGlobalHeaderValue("to", parts));
const cc = splitParticipants(getGlobalHeaderValue("cc", parts));
from,
to,
cc,
subject: getGlobalHeaderValue("subject", parts).join(" "),
html: extractHtmlBodyFromString(html),
plain,
attachments,
certificateChain
};
resolve(message);
}, 50);
});
};
/**
* Function extracts file name from content type header
* @param headers
* @returns {string} ('file.txt')
*/
export const getFilenameFromHeaders = headers => {
const headersToSearch = ["content-type", "content-disposition"];
const filename =
headers &&
Object.keys(headers)
.filter(key => headersToSearch.includes(key))
.reduce((result, key) => {
const headerValue = libmime.parseHeaderValue(headers[key][0]);
return result || headerValue.params.name || headerValue.params.filename;
}, "");
return filename || DEFAULT_ATTACHMENT_NAME;
};
/**
* Function extracts all tags within <body></body> from provided string
* and removes whitespaces between tags and HTML comments.
* @param string
* @returns {*}
*/
export const extractHtmlBodyFromString = string => {
const extractBodyRegex = /<body.*?>([\s\S]+)<\/body>/gm;
const bodyMatch = extractBodyRegex.exec(string);
if (bodyMatch && bodyMatch[1]) {
body = bodyMatch[1];
return body
.replace(/>\s+</gm, "><")
.replace(/<!--[\s\S]*?-->/gm, "")
.trim();