mirror of
				https://github.com/dawidd6/action-send-mail.git
				synced 2025-10-31 07:06:26 +07:00 
			
		
		
		
	initial javascript rewrite
This commit is contained in:
		
							
								
								
									
										510
									
								
								node_modules/nodemailer/lib/shared/index.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										510
									
								
								node_modules/nodemailer/lib/shared/index.js
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @ -0,0 +1,510 @@ | ||||
| /* eslint no-console: 0 */ | ||||
|  | ||||
| 'use strict'; | ||||
|  | ||||
| const urllib = require('url'); | ||||
| const util = require('util'); | ||||
| const fs = require('fs'); | ||||
| const fetch = require('../fetch'); | ||||
| const dns = require('dns'); | ||||
| const net = require('net'); | ||||
|  | ||||
| const DNS_TTL = 5 * 60 * 1000; | ||||
|  | ||||
| const resolver = (family, hostname, callback) => { | ||||
|     dns['resolve' + family](hostname, (err, addresses) => { | ||||
|         if (err) { | ||||
|             switch (err.code) { | ||||
|                 case dns.NODATA: | ||||
|                 case dns.NOTFOUND: | ||||
|                 case dns.NOTIMP: | ||||
|                 case dns.SERVFAIL: | ||||
|                 case dns.CONNREFUSED: | ||||
|                 case 'EAI_AGAIN': | ||||
|                     return callback(null, []); | ||||
|             } | ||||
|             return callback(err); | ||||
|         } | ||||
|         return callback(null, Array.isArray(addresses) ? addresses : [].concat(addresses || [])); | ||||
|     }); | ||||
| }; | ||||
|  | ||||
| const dnsCache = (module.exports.dnsCache = new Map()); | ||||
| module.exports.resolveHostname = (options, callback) => { | ||||
|     options = options || {}; | ||||
|  | ||||
|     if (!options.host || net.isIP(options.host)) { | ||||
|         // nothing to do here | ||||
|         let value = { | ||||
|             host: options.host, | ||||
|             servername: options.servername || false | ||||
|         }; | ||||
|         return callback(null, value); | ||||
|     } | ||||
|  | ||||
|     let cached; | ||||
|  | ||||
|     if (dnsCache.has(options.host)) { | ||||
|         cached = dnsCache.get(options.host); | ||||
|         if (!cached.expires || cached.expires >= Date.now()) { | ||||
|             return callback(null, { | ||||
|                 host: cached.value.host, | ||||
|                 servername: cached.value.servername, | ||||
|                 _cached: true | ||||
|             }); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     resolver(4, options.host, (err, addresses) => { | ||||
|         if (err) { | ||||
|             if (cached) { | ||||
|                 // ignore error, use expired value | ||||
|                 return callback(null, cached.value); | ||||
|             } | ||||
|             return callback(err); | ||||
|         } | ||||
|         if (addresses && addresses.length) { | ||||
|             let value = { | ||||
|                 host: addresses[0] || options.host, | ||||
|                 servername: options.servername || options.host | ||||
|             }; | ||||
|             dnsCache.set(options.host, { | ||||
|                 value, | ||||
|                 expires: Date.now() + DNS_TTL | ||||
|             }); | ||||
|             return callback(null, value); | ||||
|         } | ||||
|  | ||||
|         resolver(6, options.host, (err, addresses) => { | ||||
|             if (err) { | ||||
|                 if (cached) { | ||||
|                     // ignore error, use expired value | ||||
|                     return callback(null, cached.value); | ||||
|                 } | ||||
|                 return callback(err); | ||||
|             } | ||||
|             if (addresses && addresses.length) { | ||||
|                 let value = { | ||||
|                     host: addresses[0] || options.host, | ||||
|                     servername: options.servername || options.host | ||||
|                 }; | ||||
|                 dnsCache.set(options.host, { | ||||
|                     value, | ||||
|                     expires: Date.now() + DNS_TTL | ||||
|                 }); | ||||
|                 return callback(null, value); | ||||
|             } | ||||
|  | ||||
|             try { | ||||
|                 dns.lookup(options.host, {}, (err, address) => { | ||||
|                     if (err) { | ||||
|                         if (cached) { | ||||
|                             // ignore error, use expired value | ||||
|                             return callback(null, cached.value); | ||||
|                         } | ||||
|                         return callback(err); | ||||
|                     } | ||||
|  | ||||
|                     if (!address && cached) { | ||||
|                         // nothing was found, fallback to cached value | ||||
|                         return callback(null, cached.value); | ||||
|                     } | ||||
|  | ||||
|                     let value = { | ||||
|                         host: address || options.host, | ||||
|                         servername: options.servername || options.host | ||||
|                     }; | ||||
|                     dnsCache.set(options.host, { | ||||
|                         value, | ||||
|                         expires: Date.now() + DNS_TTL | ||||
|                     }); | ||||
|                     return callback(null, value); | ||||
|                 }); | ||||
|             } catch (err) { | ||||
|                 if (cached) { | ||||
|                     // ignore error, use expired value | ||||
|                     return callback(null, cached.value); | ||||
|                 } | ||||
|                 return callback(err); | ||||
|             } | ||||
|         }); | ||||
|     }); | ||||
| }; | ||||
| /** | ||||
|  * Parses connection url to a structured configuration object | ||||
|  * | ||||
|  * @param {String} str Connection url | ||||
|  * @return {Object} Configuration object | ||||
|  */ | ||||
| module.exports.parseConnectionUrl = str => { | ||||
|     str = str || ''; | ||||
|     let options = {}; | ||||
|  | ||||
|     [urllib.parse(str, true)].forEach(url => { | ||||
|         let auth; | ||||
|  | ||||
|         switch (url.protocol) { | ||||
|             case 'smtp:': | ||||
|                 options.secure = false; | ||||
|                 break; | ||||
|             case 'smtps:': | ||||
|                 options.secure = true; | ||||
|                 break; | ||||
|             case 'direct:': | ||||
|                 options.direct = true; | ||||
|                 break; | ||||
|         } | ||||
|  | ||||
|         if (!isNaN(url.port) && Number(url.port)) { | ||||
|             options.port = Number(url.port); | ||||
|         } | ||||
|  | ||||
|         if (url.hostname) { | ||||
|             options.host = url.hostname; | ||||
|         } | ||||
|  | ||||
|         if (url.auth) { | ||||
|             auth = url.auth.split(':'); | ||||
|  | ||||
|             if (!options.auth) { | ||||
|                 options.auth = {}; | ||||
|             } | ||||
|  | ||||
|             options.auth.user = auth.shift(); | ||||
|             options.auth.pass = auth.join(':'); | ||||
|         } | ||||
|  | ||||
|         Object.keys(url.query || {}).forEach(key => { | ||||
|             let obj = options; | ||||
|             let lKey = key; | ||||
|             let value = url.query[key]; | ||||
|  | ||||
|             if (!isNaN(value)) { | ||||
|                 value = Number(value); | ||||
|             } | ||||
|  | ||||
|             switch (value) { | ||||
|                 case 'true': | ||||
|                     value = true; | ||||
|                     break; | ||||
|                 case 'false': | ||||
|                     value = false; | ||||
|                     break; | ||||
|             } | ||||
|  | ||||
|             // tls is nested object | ||||
|             if (key.indexOf('tls.') === 0) { | ||||
|                 lKey = key.substr(4); | ||||
|                 if (!options.tls) { | ||||
|                     options.tls = {}; | ||||
|                 } | ||||
|                 obj = options.tls; | ||||
|             } else if (key.indexOf('.') >= 0) { | ||||
|                 // ignore nested properties besides tls | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             if (!(lKey in obj)) { | ||||
|                 obj[lKey] = value; | ||||
|             } | ||||
|         }); | ||||
|     }); | ||||
|  | ||||
|     return options; | ||||
| }; | ||||
|  | ||||
| module.exports._logFunc = (logger, level, defaults, data, message, ...args) => { | ||||
|     let entry = {}; | ||||
|  | ||||
|     Object.keys(defaults || {}).forEach(key => { | ||||
|         if (key !== 'level') { | ||||
|             entry[key] = defaults[key]; | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|     Object.keys(data || {}).forEach(key => { | ||||
|         if (key !== 'level') { | ||||
|             entry[key] = data[key]; | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|     logger[level](entry, message, ...args); | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * Returns a bunyan-compatible logger interface. Uses either provided logger or | ||||
|  * creates a default console logger | ||||
|  * | ||||
|  * @param {Object} [options] Options object that might include 'logger' value | ||||
|  * @return {Object} bunyan compatible logger | ||||
|  */ | ||||
| module.exports.getLogger = (options, defaults) => { | ||||
|     options = options || {}; | ||||
|  | ||||
|     let response = {}; | ||||
|     let levels = ['trace', 'debug', 'info', 'warn', 'error', 'fatal']; | ||||
|  | ||||
|     if (!options.logger) { | ||||
|         // use vanity logger | ||||
|         levels.forEach(level => { | ||||
|             response[level] = () => false; | ||||
|         }); | ||||
|         return response; | ||||
|     } | ||||
|  | ||||
|     let logger = options.logger; | ||||
|  | ||||
|     if (options.logger === true) { | ||||
|         // create console logger | ||||
|         logger = createDefaultLogger(levels); | ||||
|     } | ||||
|  | ||||
|     levels.forEach(level => { | ||||
|         response[level] = (data, message, ...args) => { | ||||
|             module.exports._logFunc(logger, level, defaults, data, message, ...args); | ||||
|         }; | ||||
|     }); | ||||
|  | ||||
|     return response; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * Wrapper for creating a callback that either resolves or rejects a promise | ||||
|  * based on input | ||||
|  * | ||||
|  * @param {Function} resolve Function to run if callback is called | ||||
|  * @param {Function} reject Function to run if callback ends with an error | ||||
|  */ | ||||
| module.exports.callbackPromise = (resolve, reject) => | ||||
|     function() { | ||||
|         let args = Array.from(arguments); | ||||
|         let err = args.shift(); | ||||
|         if (err) { | ||||
|             reject(err); | ||||
|         } else { | ||||
|             resolve(...args); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
| /** | ||||
|  * 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 | ||||
|  * the stream object with the resolved value (you can't stream a value twice). | ||||
|  * | ||||
|  * This is useful when you want to create a plugin that needs a content value, | ||||
|  * for example the `html` or `text` value as a String or a Buffer but not as | ||||
|  * a file path or an URL. | ||||
|  * | ||||
|  * @param {Object} data An object or an Array you want to resolve an element for | ||||
|  * @param {String|Number} key Property name or an Array index | ||||
|  * @param {Function} callback Callback function with (err, value) | ||||
|  */ | ||||
| module.exports.resolveContent = (data, key, callback) => { | ||||
|     let promise; | ||||
|  | ||||
|     if (!callback) { | ||||
|         promise = new Promise((resolve, reject) => { | ||||
|             callback = module.exports.callbackPromise(resolve, reject); | ||||
|         }); | ||||
|     } | ||||
|  | ||||
|     let content = (data && data[key] && data[key].content) || data[key]; | ||||
|     let contentStream; | ||||
|     let encoding = ((typeof data[key] === 'object' && data[key].encoding) || 'utf8') | ||||
|         .toString() | ||||
|         .toLowerCase() | ||||
|         .replace(/[-_\s]/g, ''); | ||||
|  | ||||
|     if (!content) { | ||||
|         return callback(null, content); | ||||
|     } | ||||
|  | ||||
|     if (typeof content === 'object') { | ||||
|         if (typeof content.pipe === 'function') { | ||||
|             return resolveStream(content, (err, value) => { | ||||
|                 if (err) { | ||||
|                     return callback(err); | ||||
|                 } | ||||
|                 // we can't stream twice the same content, so we need | ||||
|                 // to replace the stream object with the streaming result | ||||
|                 data[key] = value; | ||||
|                 callback(null, value); | ||||
|             }); | ||||
|         } else if (/^https?:\/\//i.test(content.path || content.href)) { | ||||
|             contentStream = fetch(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) { | ||||
|                 return callback(null, Buffer.from(0)); | ||||
|             } | ||||
|             return callback(null, /\bbase64$/i.test(parts[1]) ? Buffer.from(parts[2], 'base64') : Buffer.from(decodeURIComponent(parts[2]))); | ||||
|         } else if (content.path) { | ||||
|             return resolveStream(fs.createReadStream(content.path), callback); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     if (typeof data[key].content === 'string' && !['utf8', 'usascii', 'ascii'].includes(encoding)) { | ||||
|         content = Buffer.from(data[key].content, encoding); | ||||
|     } | ||||
|  | ||||
|     // default action, return as is | ||||
|     setImmediate(() => callback(null, content)); | ||||
|  | ||||
|     return promise; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * Copies properties from source objects to target objects | ||||
|  */ | ||||
| module.exports.assign = function(/* target, ... sources */) { | ||||
|     let args = Array.from(arguments); | ||||
|     let target = args.shift() || {}; | ||||
|  | ||||
|     args.forEach(source => { | ||||
|         Object.keys(source || {}).forEach(key => { | ||||
|             if (['tls', 'auth'].includes(key) && source[key] && typeof source[key] === 'object') { | ||||
|                 // tls and auth are special keys that need to be enumerated separately | ||||
|                 // other objects are passed as is | ||||
|                 if (!target[key]) { | ||||
|                     // ensure that target has this key | ||||
|                     target[key] = {}; | ||||
|                 } | ||||
|                 Object.keys(source[key]).forEach(subKey => { | ||||
|                     target[key][subKey] = source[key][subKey]; | ||||
|                 }); | ||||
|             } else { | ||||
|                 target[key] = source[key]; | ||||
|             } | ||||
|         }); | ||||
|     }); | ||||
|     return target; | ||||
| }; | ||||
|  | ||||
| module.exports.encodeXText = str => { | ||||
|     // ! 0x21 | ||||
|     // + 0x2B | ||||
|     // = 0x3D | ||||
|     // ~ 0x7E | ||||
|     if (!/[^\x21-\x2A\x2C-\x3C\x3E-\x7E]/.test(str)) { | ||||
|         return str; | ||||
|     } | ||||
|     let buf = Buffer.from(str); | ||||
|     let result = ''; | ||||
|     for (let i = 0, len = buf.length; i < len; i++) { | ||||
|         let c = buf[i]; | ||||
|         if (c < 0x21 || c > 0x7e || c === 0x2b || c === 0x3d) { | ||||
|             result += '+' + (c < 0x10 ? '0' : '') + c.toString(16).toUpperCase(); | ||||
|         } else { | ||||
|             result += String.fromCharCode(c); | ||||
|         } | ||||
|     } | ||||
|     return result; | ||||
| }; | ||||
|  | ||||
| /** | ||||
|  * Streams a stream value into a Buffer | ||||
|  * | ||||
|  * @param {Object} stream Readable stream | ||||
|  * @param {Function} callback Callback function with (err, value) | ||||
|  */ | ||||
| function resolveStream(stream, callback) { | ||||
|     let responded = false; | ||||
|     let chunks = []; | ||||
|     let chunklen = 0; | ||||
|  | ||||
|     stream.on('error', err => { | ||||
|         if (responded) { | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         responded = true; | ||||
|         callback(err); | ||||
|     }); | ||||
|  | ||||
|     stream.on('readable', () => { | ||||
|         let chunk; | ||||
|         while ((chunk = stream.read()) !== null) { | ||||
|             chunks.push(chunk); | ||||
|             chunklen += chunk.length; | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|     stream.on('end', () => { | ||||
|         if (responded) { | ||||
|             return; | ||||
|         } | ||||
|         responded = true; | ||||
|  | ||||
|         let value; | ||||
|  | ||||
|         try { | ||||
|             value = Buffer.concat(chunks, chunklen); | ||||
|         } catch (E) { | ||||
|             return callback(E); | ||||
|         } | ||||
|         callback(null, value); | ||||
|     }); | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * Generates a bunyan-like logger that prints to console | ||||
|  * | ||||
|  * @returns {Object} Bunyan logger instance | ||||
|  */ | ||||
| function createDefaultLogger(levels) { | ||||
|     let levelMaxLen = 0; | ||||
|     let levelNames = new Map(); | ||||
|     levels.forEach(level => { | ||||
|         if (level.length > levelMaxLen) { | ||||
|             levelMaxLen = level.length; | ||||
|         } | ||||
|     }); | ||||
|  | ||||
|     levels.forEach(level => { | ||||
|         let levelName = level.toUpperCase(); | ||||
|         if (levelName.length < levelMaxLen) { | ||||
|             levelName += ' '.repeat(levelMaxLen - levelName.length); | ||||
|         } | ||||
|         levelNames.set(level, levelName); | ||||
|     }); | ||||
|  | ||||
|     let print = (level, entry, message, ...args) => { | ||||
|         let prefix = ''; | ||||
|         if (entry) { | ||||
|             if (entry.tnx === 'server') { | ||||
|                 prefix = 'S: '; | ||||
|             } else if (entry.tnx === 'client') { | ||||
|                 prefix = 'C: '; | ||||
|             } | ||||
|  | ||||
|             if (entry.sid) { | ||||
|                 prefix = '[' + entry.sid + '] ' + prefix; | ||||
|             } | ||||
|  | ||||
|             if (entry.cid) { | ||||
|                 prefix = '[#' + entry.cid + '] ' + prefix; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         message = util.format(message, ...args); | ||||
|         message.split(/\r?\n/).forEach(line => { | ||||
|             console.log( | ||||
|                 '[%s] %s %s', | ||||
|                 new Date() | ||||
|                     .toISOString() | ||||
|                     .substr(0, 19) | ||||
|                     .replace(/T/, ' '), | ||||
|                 levelNames.get(level), | ||||
|                 prefix + line | ||||
|             ); | ||||
|         }); | ||||
|     }; | ||||
|  | ||||
|     let logger = {}; | ||||
|     levels.forEach(level => { | ||||
|         logger[level] = print.bind(null, level); | ||||
|     }); | ||||
|  | ||||
|     return logger; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user
	 Dawid Dziurla
					Dawid Dziurla