wildduck/lib/data-url.js

102 lines
2.8 KiB
JavaScript
Raw Permalink Normal View History

'use strict';
const os = require('os');
const uuid = require('uuid');
const HTMLParser = require('node-html-parser');
function processDataUrl(element, useBase64) {
let parts = (element.path || element.href).match(/^data:((?:[^;]*;)*(?:[^,]*)),(.*)$/i);
if (!parts) {
return element;
}
if (useBase64) {
element.content = /\bbase64$/i.test(parts[1])
? Buffer.from(parts[2], 'base64').toString('base64')
: Buffer.from(decodeURIComponent(parts[2])).toString('base64');
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;
}
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 {
2022-07-05 16:57:57 +08:00
let attachment = processDataUrl({ href: 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
};
}
function preprocessAttachments(data) {
let hostname = data.from && data.from.address && typeof data.from.address === 'string' ? data.from.address.split('@').pop() : os.hostname();
2022-07-05 16:57:57 +08:00
if (!data.html || !data.html.length || data.html.length > 12 * 1024 * 1024) {
return;
}
try {
let { html, attachments } = preprocessHtml(data.html, hostname);
if (html) {
data.html = html;
}
if (attachments && attachments.length) {
data.attachments = [].concat(data.attachments || []).concat(attachments);
}
} catch (err) {
// should log?
console.error(err);
}
}
module.exports = {
processDataUrl,
preprocessAttachments
};