2020-11-27 00:03:23 +08:00
|
|
|
'use strict';
|
|
|
|
|
|
|
|
const os = require('os');
|
|
|
|
const uuid = require('uuid');
|
2022-05-16 14:32:01 +08:00
|
|
|
const HTMLParser = require('node-html-parser');
|
2020-11-27 00:03:23 +08:00
|
|
|
|
|
|
|
function processDataUrl(element, useBase64) {
|
|
|
|
let parts = (element.path || element.href).match(/^data:((?:[^;]*;)*(?:[^,]*)),(.*)$/i);
|
|
|
|
if (!parts) {
|
|
|
|
return element;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (useBase64) {
|
2022-05-16 14:32:01 +08:00
|
|
|
element.content = /\bbase64$/i.test(parts[1])
|
|
|
|
? Buffer.from(parts[2], 'base64').toString('base64')
|
|
|
|
: Buffer.from(decodeURIComponent(parts[2])).toString('base64');
|
2020-11-27 00:03:23 +08:00
|
|
|
element.encoding = 'base64';
|
|
|
|
} else {
|
|
|
|
element.content = /\bbase64$/i.test(parts[1]) ? Buffer.from(parts[2], 'base64') : Buffer.from(decodeURIComponent(parts[2]));
|
|
|
|
}
|
|
|
|
|
|
|
|
if ('path' in element) {
|
|
|
|
delete element.path;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ('href' in element) {
|
|
|
|
delete element.href;
|
|
|
|
}
|
|
|
|
|
|
|
|
parts[1].split(';').forEach(item => {
|
|
|
|
if (/^\w+\/[^/]+$/i.test(item)) {
|
|
|
|
element.contentType = element.contentType || item.toLowerCase();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
return element;
|
|
|
|
}
|
2022-05-16 14:32:01 +08:00
|
|
|
function preprocessHtml(html, hostname) {
|
|
|
|
if (Buffer.isBuffer(html)) {
|
|
|
|
html = html.toString();
|
|
|
|
}
|
|
|
|
|
|
|
|
const root = HTMLParser.parse(html);
|
|
|
|
let attachments = [];
|
|
|
|
|
|
|
|
for (let img of root.getElementsByTagName('img')) {
|
|
|
|
let src = img.getAttribute('src');
|
|
|
|
if (/^data:/.test(src)) {
|
|
|
|
try {
|
|
|
|
let attachment = processDataUrl(src, true);
|
|
|
|
if (attachment) {
|
|
|
|
let filename = img.getAttribute('data-filename');
|
|
|
|
if (filename) {
|
|
|
|
attachment.filename = filename;
|
|
|
|
img.removeAttribute('data-filename');
|
|
|
|
}
|
|
|
|
attachment.cid = `${uuid.v4()}@${hostname ? hostname : 'inline'}`;
|
|
|
|
img.setAttribute('src', `cid:${attachment.cid}`);
|
|
|
|
|
|
|
|
attachments.push(attachment);
|
|
|
|
}
|
|
|
|
} catch (err) {
|
|
|
|
// should log?
|
|
|
|
console.error(err);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return {
|
|
|
|
html: attachments.length ? root.outerHTML : html,
|
|
|
|
attachments
|
|
|
|
};
|
|
|
|
}
|
2020-11-27 00:03:23 +08:00
|
|
|
|
|
|
|
function preprocessAttachments(data) {
|
|
|
|
let hostname = data.from && data.from.address && typeof data.from.address === 'string' ? data.from.address.split('@').pop() : os.hostname();
|
2022-05-16 14:32:01 +08:00
|
|
|
if (!data.html || !data.html.length || data.html.length > 12 * 1024 * 1024) {
|
|
|
|
return;
|
|
|
|
}
|
2020-11-27 00:03:23 +08:00
|
|
|
|
2022-05-16 14:32:01 +08:00
|
|
|
try {
|
|
|
|
let { html, attachments } = preprocessHtml(data.html, hostname);
|
2020-11-27 00:03:23 +08:00
|
|
|
|
2022-05-16 14:32:01 +08:00
|
|
|
if (html) {
|
|
|
|
data.html = html;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (attachments && attachments.length) {
|
2020-11-27 00:03:23 +08:00
|
|
|
data.attachments = [].concat(data.attachments || []).concat(attachments);
|
|
|
|
}
|
2022-05-16 14:32:01 +08:00
|
|
|
} catch (err) {
|
|
|
|
// should log?
|
|
|
|
console.error(err);
|
2020-11-27 00:03:23 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = {
|
|
|
|
processDataUrl,
|
|
|
|
preprocessAttachments
|
|
|
|
};
|