nodemailer 8.0.2 → 8.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +17 -0
- package/lib/addressparser/index.js +68 -83
- package/lib/base64/index.js +6 -5
- package/lib/dkim/index.js +8 -16
- package/lib/dkim/message-parser.js +12 -13
- package/lib/dkim/relaxed-body.js +2 -2
- package/lib/dkim/sign.js +13 -14
- package/lib/errors.js +4 -7
- package/lib/fetch/cookies.js +13 -18
- package/lib/fetch/index.js +12 -15
- package/lib/json-transport/index.js +4 -4
- package/lib/mail-composer/index.js +86 -116
- package/lib/mailer/index.js +26 -26
- package/lib/mailer/mail-message.js +17 -21
- package/lib/mime-funcs/index.js +25 -40
- package/lib/mime-funcs/mime-types.js +7 -11
- package/lib/mime-node/index.js +81 -72
- package/lib/mime-node/last-newline.js +1 -1
- package/lib/mime-node/le-unix.js +4 -7
- package/lib/mime-node/le-windows.js +1 -4
- package/lib/nodemailer.js +11 -18
- package/lib/qp/index.js +24 -21
- package/lib/sendmail-transport/index.js +30 -41
- package/lib/ses-transport/index.js +23 -34
- package/lib/shared/index.js +94 -140
- package/lib/smtp-connection/data-stream.js +3 -6
- package/lib/smtp-connection/http-proxy-client.js +11 -13
- package/lib/smtp-connection/index.js +118 -182
- package/lib/smtp-pool/index.js +20 -32
- package/lib/smtp-pool/pool-resource.js +8 -12
- package/lib/smtp-transport/index.js +22 -42
- package/lib/stream-transport/index.js +7 -7
- package/lib/well-known/index.js +7 -7
- package/lib/xoauth2/index.js +22 -28
- package/package.json +4 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const spawn = require('child_process')
|
|
3
|
+
const { spawn } = require('child_process');
|
|
4
4
|
const packageData = require('../../package.json');
|
|
5
5
|
const shared = require('../shared');
|
|
6
6
|
const errors = require('../errors');
|
|
@@ -24,30 +24,26 @@ class SendmailTransport {
|
|
|
24
24
|
// use a reference to spawn for mocking purposes
|
|
25
25
|
this._spawn = spawn;
|
|
26
26
|
|
|
27
|
-
this.options = options
|
|
27
|
+
this.options = options;
|
|
28
28
|
|
|
29
29
|
this.name = 'Sendmail';
|
|
30
30
|
this.version = packageData.version;
|
|
31
31
|
|
|
32
32
|
this.path = 'sendmail';
|
|
33
33
|
this.args = false;
|
|
34
|
-
this.winbreak = false;
|
|
35
34
|
|
|
36
35
|
this.logger = shared.getLogger(this.options, {
|
|
37
36
|
component: this.options.component || 'sendmail'
|
|
38
37
|
});
|
|
39
38
|
|
|
40
|
-
if (options) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
this.args = options.args;
|
|
49
|
-
}
|
|
50
|
-
this.winbreak = ['win', 'windows', 'dos', '\r\n'].includes((options.newline || '').toString().toLowerCase());
|
|
39
|
+
if (typeof options === 'string') {
|
|
40
|
+
this.path = options;
|
|
41
|
+
} else if (typeof options === 'object') {
|
|
42
|
+
if (options.path) {
|
|
43
|
+
this.path = options.path;
|
|
44
|
+
}
|
|
45
|
+
if (Array.isArray(options.args)) {
|
|
46
|
+
this.args = options.args;
|
|
51
47
|
}
|
|
52
48
|
}
|
|
53
49
|
}
|
|
@@ -62,10 +58,8 @@ class SendmailTransport {
|
|
|
62
58
|
// Sendmail strips this header line by itself
|
|
63
59
|
mail.message.keepBcc = true;
|
|
64
60
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
let args;
|
|
68
|
-
let sendmail;
|
|
61
|
+
const envelope = mail.data.envelope || mail.message.getEnvelope();
|
|
62
|
+
const messageId = mail.message.messageId();
|
|
69
63
|
let returned;
|
|
70
64
|
|
|
71
65
|
const hasInvalidAddresses = []
|
|
@@ -73,19 +67,17 @@ class SendmailTransport {
|
|
|
73
67
|
.concat(envelope.to || [])
|
|
74
68
|
.some(addr => /^-/.test(addr));
|
|
75
69
|
if (hasInvalidAddresses) {
|
|
76
|
-
|
|
70
|
+
const err = new Error('Can not send mail. Invalid envelope addresses.');
|
|
77
71
|
err.code = errors.ESENDMAIL;
|
|
78
72
|
return done(err);
|
|
79
73
|
}
|
|
80
74
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
args = ['-i'].concat(envelope.from ? ['-f', envelope.from] : []).concat(envelope.to);
|
|
86
|
-
}
|
|
75
|
+
// force -i to keep single dots
|
|
76
|
+
const args = this.args
|
|
77
|
+
? ['-i'].concat(this.args).concat(envelope.to)
|
|
78
|
+
: ['-i'].concat(envelope.from ? ['-f', envelope.from] : []).concat(envelope.to);
|
|
87
79
|
|
|
88
|
-
|
|
80
|
+
const callback = err => {
|
|
89
81
|
if (returned) {
|
|
90
82
|
// ignore any additional responses, already done
|
|
91
83
|
return;
|
|
@@ -94,16 +86,16 @@ class SendmailTransport {
|
|
|
94
86
|
if (typeof done === 'function') {
|
|
95
87
|
if (err) {
|
|
96
88
|
return done(err);
|
|
97
|
-
} else {
|
|
98
|
-
return done(null, {
|
|
99
|
-
envelope: mail.data.envelope || mail.message.getEnvelope(),
|
|
100
|
-
messageId,
|
|
101
|
-
response: 'Messages queued for delivery'
|
|
102
|
-
});
|
|
103
89
|
}
|
|
90
|
+
return done(null, {
|
|
91
|
+
envelope,
|
|
92
|
+
messageId,
|
|
93
|
+
response: 'Messages queued for delivery'
|
|
94
|
+
});
|
|
104
95
|
}
|
|
105
96
|
};
|
|
106
97
|
|
|
98
|
+
let sendmail;
|
|
107
99
|
try {
|
|
108
100
|
sendmail = this._spawn(this.path, args);
|
|
109
101
|
} catch (E) {
|
|
@@ -138,12 +130,9 @@ class SendmailTransport {
|
|
|
138
130
|
if (!code) {
|
|
139
131
|
return callback();
|
|
140
132
|
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
} else {
|
|
145
|
-
err = new Error('Sendmail exited with code ' + code);
|
|
146
|
-
}
|
|
133
|
+
const err = new Error(
|
|
134
|
+
code === 127 ? 'Sendmail command not found, process exited with code ' + code : 'Sendmail exited with code ' + code
|
|
135
|
+
);
|
|
147
136
|
err.code = errors.ESENDMAIL;
|
|
148
137
|
|
|
149
138
|
this.logger.error(
|
|
@@ -174,7 +163,7 @@ class SendmailTransport {
|
|
|
174
163
|
callback(err);
|
|
175
164
|
});
|
|
176
165
|
|
|
177
|
-
|
|
166
|
+
const recipients = [].concat(envelope.to || []);
|
|
178
167
|
if (recipients.length > 3) {
|
|
179
168
|
recipients.push('...and ' + recipients.splice(2).length + ' more');
|
|
180
169
|
}
|
|
@@ -188,7 +177,7 @@ class SendmailTransport {
|
|
|
188
177
|
recipients.join(', ')
|
|
189
178
|
);
|
|
190
179
|
|
|
191
|
-
|
|
180
|
+
const sourceStream = mail.message.createReadStream();
|
|
192
181
|
sourceStream.once('error', err => {
|
|
193
182
|
this.logger.error(
|
|
194
183
|
{
|
|
@@ -206,7 +195,7 @@ class SendmailTransport {
|
|
|
206
195
|
|
|
207
196
|
sourceStream.pipe(sendmail.stdin);
|
|
208
197
|
} else {
|
|
209
|
-
|
|
198
|
+
const err = new Error('sendmail was not found');
|
|
210
199
|
err.code = errors.ESENDMAIL;
|
|
211
200
|
return callback(err);
|
|
212
201
|
}
|
|
@@ -17,7 +17,7 @@ class SESTransport extends EventEmitter {
|
|
|
17
17
|
super();
|
|
18
18
|
options = options || {};
|
|
19
19
|
|
|
20
|
-
this.options = options
|
|
20
|
+
this.options = options;
|
|
21
21
|
this.ses = this.options.SES;
|
|
22
22
|
|
|
23
23
|
this.name = 'SESTransport';
|
|
@@ -46,21 +46,16 @@ class SESTransport extends EventEmitter {
|
|
|
46
46
|
* @param {Function} callback Callback function to run when the sending is completed
|
|
47
47
|
*/
|
|
48
48
|
send(mail, callback) {
|
|
49
|
-
let statObject = {
|
|
50
|
-
ts: Date.now(),
|
|
51
|
-
pending: true
|
|
52
|
-
};
|
|
53
|
-
|
|
54
49
|
let fromHeader = mail.message._headers.find(header => /^from$/i.test(header.key));
|
|
55
50
|
if (fromHeader) {
|
|
56
|
-
|
|
51
|
+
const mimeNode = new MimeNode('text/plain');
|
|
57
52
|
fromHeader = mimeNode._convertAddresses(mimeNode._parseAddresses(fromHeader.value));
|
|
58
53
|
}
|
|
59
54
|
|
|
60
|
-
|
|
61
|
-
|
|
55
|
+
const envelope = mail.data.envelope || mail.message.getEnvelope();
|
|
56
|
+
const messageId = mail.message.messageId();
|
|
62
57
|
|
|
63
|
-
|
|
58
|
+
const recipients = [].concat(envelope.to || []);
|
|
64
59
|
if (recipients.length > 3) {
|
|
65
60
|
recipients.push('...and ' + recipients.splice(2).length + ' more');
|
|
66
61
|
}
|
|
@@ -74,7 +69,7 @@ class SESTransport extends EventEmitter {
|
|
|
74
69
|
recipients.join(', ')
|
|
75
70
|
);
|
|
76
71
|
|
|
77
|
-
|
|
72
|
+
const getRawMessage = next => {
|
|
78
73
|
// do not use Message-ID and Date in DKIM signature
|
|
79
74
|
if (!mail.data._dkim) {
|
|
80
75
|
mail.data._dkim = {};
|
|
@@ -85,9 +80,9 @@ class SESTransport extends EventEmitter {
|
|
|
85
80
|
mail.data._dkim.skipFields = 'date:message-id';
|
|
86
81
|
}
|
|
87
82
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
83
|
+
const sourceStream = mail.message.createReadStream();
|
|
84
|
+
const stream = sourceStream.pipe(new LeWindows());
|
|
85
|
+
const chunks = [];
|
|
91
86
|
let chunklen = 0;
|
|
92
87
|
|
|
93
88
|
stream.on('readable', () => {
|
|
@@ -100,9 +95,7 @@ class SESTransport extends EventEmitter {
|
|
|
100
95
|
|
|
101
96
|
sourceStream.once('error', err => stream.emit('error', err));
|
|
102
97
|
|
|
103
|
-
stream.once('error', err =>
|
|
104
|
-
next(err);
|
|
105
|
-
});
|
|
98
|
+
stream.once('error', err => next(err));
|
|
106
99
|
|
|
107
100
|
stream.once('end', () => next(null, Buffer.concat(chunks, chunklen)));
|
|
108
101
|
};
|
|
@@ -120,26 +113,24 @@ class SESTransport extends EventEmitter {
|
|
|
120
113
|
messageId,
|
|
121
114
|
err.message
|
|
122
115
|
);
|
|
123
|
-
statObject.pending = false;
|
|
124
116
|
return callback(err);
|
|
125
117
|
}
|
|
126
118
|
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
119
|
+
const sesMessage = Object.assign(
|
|
120
|
+
{
|
|
121
|
+
Content: {
|
|
122
|
+
Raw: {
|
|
123
|
+
// required
|
|
124
|
+
Data: raw // required
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
FromEmailAddress: fromHeader || envelope.from,
|
|
128
|
+
Destination: {
|
|
129
|
+
ToAddresses: envelope.to
|
|
132
130
|
}
|
|
133
131
|
},
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
ToAddresses: envelope.to
|
|
137
|
-
}
|
|
138
|
-
};
|
|
139
|
-
|
|
140
|
-
Object.keys(mail.data.ses || {}).forEach(key => {
|
|
141
|
-
sesMessage[key] = mail.data.ses[key];
|
|
142
|
-
});
|
|
132
|
+
mail.data.ses || {}
|
|
133
|
+
);
|
|
143
134
|
|
|
144
135
|
this.getRegion((err, region) => {
|
|
145
136
|
if (err || !region) {
|
|
@@ -155,7 +146,6 @@ class SESTransport extends EventEmitter {
|
|
|
155
146
|
region = 'email';
|
|
156
147
|
}
|
|
157
148
|
|
|
158
|
-
statObject.pending = true;
|
|
159
149
|
callback(null, {
|
|
160
150
|
envelope: {
|
|
161
151
|
from: envelope.from,
|
|
@@ -176,7 +166,6 @@ class SESTransport extends EventEmitter {
|
|
|
176
166
|
messageId,
|
|
177
167
|
err.message
|
|
178
168
|
);
|
|
179
|
-
statObject.pending = false;
|
|
180
169
|
callback(err);
|
|
181
170
|
});
|
|
182
171
|
});
|
package/lib/shared/index.js
CHANGED
|
@@ -30,34 +30,28 @@ try {
|
|
|
30
30
|
module.exports.networkInterfaces = networkInterfaces;
|
|
31
31
|
|
|
32
32
|
const isFamilySupported = (family, allowInternal) => {
|
|
33
|
-
|
|
34
|
-
if (!
|
|
33
|
+
const ifaces = module.exports.networkInterfaces;
|
|
34
|
+
if (!ifaces) {
|
|
35
35
|
// hope for the best
|
|
36
36
|
return true;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
.reduce((acc, val) => acc.concat(val), [])
|
|
45
|
-
.filter(i => !i.internal || allowInternal)
|
|
46
|
-
.filter(i => i.family === 'IPv' + family || i.family === family).length > 0;
|
|
47
|
-
|
|
48
|
-
return familySupported;
|
|
39
|
+
return Object.keys(ifaces)
|
|
40
|
+
.map(key => ifaces[key])
|
|
41
|
+
.reduce((acc, val) => acc.concat(val), [])
|
|
42
|
+
.filter(i => !i.internal || allowInternal)
|
|
43
|
+
.some(i => i.family === 'IPv' + family || i.family === family);
|
|
49
44
|
};
|
|
50
45
|
|
|
51
|
-
const
|
|
46
|
+
const resolve = (family, hostname, options, callback) => {
|
|
52
47
|
options = options || {};
|
|
53
|
-
const familySupported = isFamilySupported(family, options.allowInternalNetworkInterfaces);
|
|
54
48
|
|
|
55
|
-
if (!
|
|
49
|
+
if (!isFamilySupported(family, options.allowInternalNetworkInterfaces)) {
|
|
56
50
|
return callback(null, []);
|
|
57
51
|
}
|
|
58
52
|
|
|
59
|
-
const
|
|
60
|
-
|
|
53
|
+
const dnsResolver = dns.Resolver ? new dns.Resolver(options) : dns;
|
|
54
|
+
dnsResolver['resolve' + family](hostname, (err, addresses) => {
|
|
61
55
|
if (err) {
|
|
62
56
|
switch (err.code) {
|
|
63
57
|
case dns.NODATA:
|
|
@@ -82,15 +76,10 @@ const formatDNSValue = (value, extra) => {
|
|
|
82
76
|
return Object.assign({}, extra || {});
|
|
83
77
|
}
|
|
84
78
|
|
|
85
|
-
|
|
79
|
+
const addresses = value.addresses || [];
|
|
86
80
|
|
|
87
81
|
// Select a random address from available addresses, or null if none
|
|
88
|
-
|
|
89
|
-
if (addresses.length === 1) {
|
|
90
|
-
host = addresses[0];
|
|
91
|
-
} else if (addresses.length > 1) {
|
|
92
|
-
host = addresses[Math.floor(Math.random() * addresses.length)];
|
|
93
|
-
}
|
|
82
|
+
const host = addresses.length > 0 ? addresses[Math.floor(Math.random() * addresses.length)] : null;
|
|
94
83
|
|
|
95
84
|
return Object.assign(
|
|
96
85
|
{
|
|
@@ -112,7 +101,7 @@ module.exports.resolveHostname = (options, callback) => {
|
|
|
112
101
|
|
|
113
102
|
if (!options.host || net.isIP(options.host)) {
|
|
114
103
|
// nothing to do here
|
|
115
|
-
|
|
104
|
+
const value = {
|
|
116
105
|
addresses: [options.host],
|
|
117
106
|
servername: options.servername || false
|
|
118
107
|
};
|
|
@@ -164,14 +153,14 @@ module.exports.resolveHostname = (options, callback) => {
|
|
|
164
153
|
let ipv4Error = null;
|
|
165
154
|
let ipv6Error = null;
|
|
166
155
|
|
|
167
|
-
|
|
156
|
+
resolve(4, options.host, options, (err, addresses) => {
|
|
168
157
|
if (err) {
|
|
169
158
|
ipv4Error = err;
|
|
170
159
|
} else {
|
|
171
160
|
ipv4Addresses = addresses || [];
|
|
172
161
|
}
|
|
173
162
|
|
|
174
|
-
|
|
163
|
+
resolve(6, options.host, options, (err, addresses) => {
|
|
175
164
|
if (err) {
|
|
176
165
|
ipv6Error = err;
|
|
177
166
|
} else {
|
|
@@ -179,10 +168,10 @@ module.exports.resolveHostname = (options, callback) => {
|
|
|
179
168
|
}
|
|
180
169
|
|
|
181
170
|
// Combine addresses: IPv4 first, then IPv6
|
|
182
|
-
|
|
171
|
+
const allAddresses = ipv4Addresses.concat(ipv6Addresses);
|
|
183
172
|
|
|
184
173
|
if (allAddresses.length) {
|
|
185
|
-
|
|
174
|
+
const value = {
|
|
186
175
|
addresses: allAddresses,
|
|
187
176
|
servername: options.servername || options.host
|
|
188
177
|
};
|
|
@@ -240,7 +229,7 @@ module.exports.resolveHostname = (options, callback) => {
|
|
|
240
229
|
}
|
|
241
230
|
|
|
242
231
|
// Get all supported addresses from dns.lookup
|
|
243
|
-
|
|
232
|
+
const supportedAddresses = addresses
|
|
244
233
|
? addresses.filter(addr => isFamilySupported(addr.family)).map(addr => addr.address)
|
|
245
234
|
: [];
|
|
246
235
|
|
|
@@ -259,7 +248,7 @@ module.exports.resolveHostname = (options, callback) => {
|
|
|
259
248
|
);
|
|
260
249
|
}
|
|
261
250
|
|
|
262
|
-
|
|
251
|
+
const value = {
|
|
263
252
|
addresses: supportedAddresses.length ? supportedAddresses : [options.host],
|
|
264
253
|
servername: options.servername || options.host
|
|
265
254
|
};
|
|
@@ -304,95 +293,78 @@ module.exports.resolveHostname = (options, callback) => {
|
|
|
304
293
|
*/
|
|
305
294
|
module.exports.parseConnectionUrl = str => {
|
|
306
295
|
str = str || '';
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
break;
|
|
322
|
-
}
|
|
296
|
+
const options = {};
|
|
297
|
+
const url = urllib.parse(str, true);
|
|
298
|
+
|
|
299
|
+
switch (url.protocol) {
|
|
300
|
+
case 'smtp:':
|
|
301
|
+
options.secure = false;
|
|
302
|
+
break;
|
|
303
|
+
case 'smtps:':
|
|
304
|
+
options.secure = true;
|
|
305
|
+
break;
|
|
306
|
+
case 'direct:':
|
|
307
|
+
options.direct = true;
|
|
308
|
+
break;
|
|
309
|
+
}
|
|
323
310
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
311
|
+
if (!isNaN(url.port) && Number(url.port)) {
|
|
312
|
+
options.port = Number(url.port);
|
|
313
|
+
}
|
|
327
314
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
315
|
+
if (url.hostname) {
|
|
316
|
+
options.host = url.hostname;
|
|
317
|
+
}
|
|
331
318
|
|
|
332
|
-
|
|
333
|
-
|
|
319
|
+
if (url.auth) {
|
|
320
|
+
const auth = url.auth.split(':');
|
|
321
|
+
options.auth = {
|
|
322
|
+
user: auth.shift(),
|
|
323
|
+
pass: auth.join(':')
|
|
324
|
+
};
|
|
325
|
+
}
|
|
334
326
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
327
|
+
Object.keys(url.query || {}).forEach(key => {
|
|
328
|
+
let obj = options;
|
|
329
|
+
let lKey = key;
|
|
330
|
+
let value = url.query[key];
|
|
338
331
|
|
|
339
|
-
|
|
340
|
-
|
|
332
|
+
if (!isNaN(value)) {
|
|
333
|
+
value = Number(value);
|
|
341
334
|
}
|
|
342
335
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
switch (value) {
|
|
353
|
-
case 'true':
|
|
354
|
-
value = true;
|
|
355
|
-
break;
|
|
356
|
-
case 'false':
|
|
357
|
-
value = false;
|
|
358
|
-
break;
|
|
359
|
-
}
|
|
336
|
+
switch (value) {
|
|
337
|
+
case 'true':
|
|
338
|
+
value = true;
|
|
339
|
+
break;
|
|
340
|
+
case 'false':
|
|
341
|
+
value = false;
|
|
342
|
+
break;
|
|
343
|
+
}
|
|
360
344
|
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
}
|
|
367
|
-
obj = options.tls;
|
|
368
|
-
} else if (key.indexOf('.') >= 0) {
|
|
369
|
-
// ignore nested properties besides tls
|
|
370
|
-
return;
|
|
345
|
+
// tls is nested object
|
|
346
|
+
if (key.indexOf('tls.') === 0) {
|
|
347
|
+
lKey = key.substr(4);
|
|
348
|
+
if (!options.tls) {
|
|
349
|
+
options.tls = {};
|
|
371
350
|
}
|
|
351
|
+
obj = options.tls;
|
|
352
|
+
} else if (key.indexOf('.') >= 0) {
|
|
353
|
+
// ignore nested properties besides tls
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
372
356
|
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
});
|
|
357
|
+
if (!(lKey in obj)) {
|
|
358
|
+
obj[lKey] = value;
|
|
359
|
+
}
|
|
377
360
|
});
|
|
378
361
|
|
|
379
362
|
return options;
|
|
380
363
|
};
|
|
381
364
|
|
|
382
365
|
module.exports._logFunc = (logger, level, defaults, data, message, ...args) => {
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
Object.keys(defaults || {}).forEach(key => {
|
|
386
|
-
if (key !== 'level') {
|
|
387
|
-
entry[key] = defaults[key];
|
|
388
|
-
}
|
|
389
|
-
});
|
|
390
|
-
|
|
391
|
-
Object.keys(data || {}).forEach(key => {
|
|
392
|
-
if (key !== 'level') {
|
|
393
|
-
entry[key] = data[key];
|
|
394
|
-
}
|
|
395
|
-
});
|
|
366
|
+
const entry = Object.assign({}, defaults || {}, data || {});
|
|
367
|
+
delete entry.level;
|
|
396
368
|
|
|
397
369
|
logger[level](entry, message, ...args);
|
|
398
370
|
};
|
|
@@ -407,8 +379,8 @@ module.exports._logFunc = (logger, level, defaults, data, message, ...args) => {
|
|
|
407
379
|
module.exports.getLogger = (options, defaults) => {
|
|
408
380
|
options = options || {};
|
|
409
381
|
|
|
410
|
-
|
|
411
|
-
|
|
382
|
+
const response = {};
|
|
383
|
+
const levels = ['trace', 'debug', 'info', 'warn', 'error', 'fatal'];
|
|
412
384
|
|
|
413
385
|
if (!options.logger) {
|
|
414
386
|
// use vanity logger
|
|
@@ -418,12 +390,7 @@ module.exports.getLogger = (options, defaults) => {
|
|
|
418
390
|
return response;
|
|
419
391
|
}
|
|
420
392
|
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
if (options.logger === true) {
|
|
424
|
-
// create console logger
|
|
425
|
-
logger = createDefaultLogger(levels);
|
|
426
|
-
}
|
|
393
|
+
const logger = options.logger === true ? createDefaultLogger(levels) : options.logger;
|
|
427
394
|
|
|
428
395
|
levels.forEach(level => {
|
|
429
396
|
response[level] = (data, message, ...args) => {
|
|
@@ -443,8 +410,8 @@ module.exports.getLogger = (options, defaults) => {
|
|
|
443
410
|
*/
|
|
444
411
|
module.exports.callbackPromise = (resolve, reject) =>
|
|
445
412
|
function () {
|
|
446
|
-
|
|
447
|
-
|
|
413
|
+
const args = Array.from(arguments);
|
|
414
|
+
const err = args.shift();
|
|
448
415
|
if (err) {
|
|
449
416
|
reject(err);
|
|
450
417
|
} else {
|
|
@@ -546,8 +513,7 @@ module.exports.resolveContent = (data, key, callback) => {
|
|
|
546
513
|
}
|
|
547
514
|
|
|
548
515
|
let content = (data && data[key] && data[key].content) || data[key];
|
|
549
|
-
|
|
550
|
-
let encoding = ((typeof data[key] === 'object' && data[key].encoding) || 'utf8')
|
|
516
|
+
const encoding = ((typeof data[key] === 'object' && data[key].encoding) || 'utf8')
|
|
551
517
|
.toString()
|
|
552
518
|
.toLowerCase()
|
|
553
519
|
.replace(/[-_\s]/g, '');
|
|
@@ -572,10 +538,9 @@ module.exports.resolveContent = (data, key, callback) => {
|
|
|
572
538
|
callback(null, value);
|
|
573
539
|
});
|
|
574
540
|
} else if (/^https?:\/\//i.test(content.path || content.href)) {
|
|
575
|
-
|
|
576
|
-
return resolveStream(contentStream, callback);
|
|
541
|
+
return resolveStream(nmfetch(content.path || content.href), callback);
|
|
577
542
|
} else if (/^data:/i.test(content.path || content.href)) {
|
|
578
|
-
|
|
543
|
+
const parsedDataUri = module.exports.parseDataURI(content.path || content.href);
|
|
579
544
|
|
|
580
545
|
if (!parsedDataUri || !parsedDataUri.data) {
|
|
581
546
|
return callback(null, Buffer.from(0));
|
|
@@ -600,21 +565,15 @@ module.exports.resolveContent = (data, key, callback) => {
|
|
|
600
565
|
* Copies properties from source objects to target objects
|
|
601
566
|
*/
|
|
602
567
|
module.exports.assign = function (/* target, ... sources */) {
|
|
603
|
-
|
|
604
|
-
|
|
568
|
+
const args = Array.from(arguments);
|
|
569
|
+
const target = args.shift() || {};
|
|
605
570
|
|
|
606
571
|
args.forEach(source => {
|
|
607
572
|
Object.keys(source || {}).forEach(key => {
|
|
608
573
|
if (['tls', 'auth'].includes(key) && source[key] && typeof source[key] === 'object') {
|
|
609
574
|
// tls and auth are special keys that need to be enumerated separately
|
|
610
575
|
// other objects are passed as is
|
|
611
|
-
|
|
612
|
-
// ensure that target has this key
|
|
613
|
-
target[key] = {};
|
|
614
|
-
}
|
|
615
|
-
Object.keys(source[key]).forEach(subKey => {
|
|
616
|
-
target[key][subKey] = source[key][subKey];
|
|
617
|
-
});
|
|
576
|
+
target[key] = Object.assign(target[key] || {}, source[key]);
|
|
618
577
|
} else {
|
|
619
578
|
target[key] = source[key];
|
|
620
579
|
}
|
|
@@ -631,10 +590,10 @@ module.exports.encodeXText = str => {
|
|
|
631
590
|
if (!/[^\x21-\x2A\x2C-\x3C\x3E-\x7E]/.test(str)) {
|
|
632
591
|
return str;
|
|
633
592
|
}
|
|
634
|
-
|
|
593
|
+
const buf = Buffer.from(str);
|
|
635
594
|
let result = '';
|
|
636
595
|
for (let i = 0, len = buf.length; i < len; i++) {
|
|
637
|
-
|
|
596
|
+
const c = buf[i];
|
|
638
597
|
if (c < 0x21 || c > 0x7e || c === 0x2b || c === 0x3d) {
|
|
639
598
|
result += '+' + (c < 0x10 ? '0' : '') + c.toString(16).toUpperCase();
|
|
640
599
|
} else {
|
|
@@ -652,7 +611,7 @@ module.exports.encodeXText = str => {
|
|
|
652
611
|
*/
|
|
653
612
|
function resolveStream(stream, callback) {
|
|
654
613
|
let responded = false;
|
|
655
|
-
|
|
614
|
+
const chunks = [];
|
|
656
615
|
let chunklen = 0;
|
|
657
616
|
|
|
658
617
|
stream.on('error', err => {
|
|
@@ -695,13 +654,8 @@ function resolveStream(stream, callback) {
|
|
|
695
654
|
* @returns {Object} Bunyan logger instance
|
|
696
655
|
*/
|
|
697
656
|
function createDefaultLogger(levels) {
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
levels.forEach(level => {
|
|
701
|
-
if (level.length > levelMaxLen) {
|
|
702
|
-
levelMaxLen = level.length;
|
|
703
|
-
}
|
|
704
|
-
});
|
|
657
|
+
const levelMaxLen = levels.reduce((max, level) => Math.max(max, level.length), 0);
|
|
658
|
+
const levelNames = new Map();
|
|
705
659
|
|
|
706
660
|
levels.forEach(level => {
|
|
707
661
|
let levelName = level.toUpperCase();
|
|
@@ -711,7 +665,7 @@ function createDefaultLogger(levels) {
|
|
|
711
665
|
levelNames.set(level, levelName);
|
|
712
666
|
});
|
|
713
667
|
|
|
714
|
-
|
|
668
|
+
const print = (level, entry, message, ...args) => {
|
|
715
669
|
let prefix = '';
|
|
716
670
|
if (entry) {
|
|
717
671
|
if (entry.tnx === 'server') {
|
|
@@ -735,7 +689,7 @@ function createDefaultLogger(levels) {
|
|
|
735
689
|
});
|
|
736
690
|
};
|
|
737
691
|
|
|
738
|
-
|
|
692
|
+
const logger = {};
|
|
739
693
|
levels.forEach(level => {
|
|
740
694
|
logger[level] = print.bind(null, level);
|
|
741
695
|
});
|