diff --git a/lib/mail-composer/index.js b/lib/mail-composer/index.js index e85ebc4b..7e902155 100644 --- a/lib/mail-composer/index.js +++ b/lib/mail-composer/index.js @@ -4,6 +4,7 @@ const MimeNode = require('../mime-node'); const mimeFuncs = require('../mime-funcs'); +const parseDataURI = require('../shared').parseDataURI; /** * Creates the object for composing a MimeNode instance out from the mail options @@ -539,7 +540,7 @@ class MailComposer { _processDataUrl(element) { let parsedDataUri; if ((element.path || element.href).match(/^data:/)) { - parsedDataUri = this.parseDataURI(element.path || element.href); + parsedDataUri = parseDataURI(element.path || element.href); } if (!parsedDataUri) { @@ -559,55 +560,6 @@ class MailComposer { return element; } - - parseDataURI(uri) { - let input = uri; - let commaPos = input.indexOf(','); - if (!commaPos) { - return uri; - } - - let data = input.substring(commaPos + 1); - let metaStr = input.substring('data:'.length, commaPos); - - let encoding; - - let metaEntries = metaStr.split(';'); - let lastMetaEntry = metaEntries.length > 1 ? metaEntries[metaEntries.length - 1] : false; - if (lastMetaEntry && lastMetaEntry.indexOf('=') < 0) { - encoding = lastMetaEntry.toLowerCase(); - metaEntries.pop(); - } - - let contentType = metaEntries.shift() || 'application/octet-stream'; - let params = {}; - for (let entry of metaEntries) { - let sep = entry.indexOf('='); - if (sep >= 0) { - let key = entry.substring(0, sep); - let value = entry.substring(sep + 1); - params[key] = value; - } - } - - switch (encoding) { - case 'base64': - data = Buffer.from(data, 'base64'); - break; - case 'utf8': - data = Buffer.from(data); - break; - default: - try { - data = Buffer.from(decodeURIComponent(data)); - } catch (err) { - data = Buffer.from(data); - } - data = Buffer.from(data); - } - - return { data, encoding, contentType, params }; - } } module.exports = MailComposer; diff --git a/lib/shared/index.js b/lib/shared/index.js index 23e88f00..4c16a375 100644 --- a/lib/shared/index.js +++ b/lib/shared/index.js @@ -418,6 +418,55 @@ module.exports.callbackPromise = (resolve, reject) => } }; +module.exports.parseDataURI = uri => { + let input = uri; + let commaPos = input.indexOf(','); + if (!commaPos) { + return uri; + } + + let data = input.substring(commaPos + 1); + let metaStr = input.substring('data:'.length, commaPos); + + let encoding; + + let metaEntries = metaStr.split(';'); + let lastMetaEntry = metaEntries.length > 1 ? metaEntries[metaEntries.length - 1] : false; + if (lastMetaEntry && lastMetaEntry.indexOf('=') < 0) { + encoding = lastMetaEntry.toLowerCase(); + metaEntries.pop(); + } + + let contentType = metaEntries.shift() || 'application/octet-stream'; + let params = {}; + for (let entry of metaEntries) { + let sep = entry.indexOf('='); + if (sep >= 0) { + let key = entry.substring(0, sep); + let value = entry.substring(sep + 1); + params[key] = value; + } + } + + switch (encoding) { + case 'base64': + data = Buffer.from(data, 'base64'); + break; + case 'utf8': + data = Buffer.from(data); + break; + default: + try { + data = Buffer.from(decodeURIComponent(data)); + } catch (err) { + data = Buffer.from(data); + } + data = Buffer.from(data); + } + + return { data, encoding, contentType, params }; +}; + /** * Resolves a String or a Buffer value for content value. Useful if the value * is a Stream or a file or an URL. If the value is a Stream, overwrites @@ -470,11 +519,12 @@ module.exports.resolveContent = (data, key, callback) => { contentStream = nmfetch(content.path || content.href); return resolveStream(contentStream, callback); } else if (/^data:/i.test(content.path || content.href)) { - let parts = (content.path || content.href).match(/^data:((?:[^;]*;)*(?:[^,]*)),(.*)$/i); - if (!parts) { + let parsedDataUri = module.exports.parseDataURI(content.path || content.href); + + if (!parsedDataUri || !parsedDataUri.data) { return callback(null, Buffer.from(0)); } - return callback(null, /\bbase64$/i.test(parts[1]) ? Buffer.from(parts[2], 'base64') : Buffer.from(decodeURIComponent(parts[2]))); + return callback(null, parsedDataUri.data); } else if (content.path) { return resolveStream(fs.createReadStream(content.path), callback); }