zhuha 1.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of zhuha might be problematic. Click here for more details.

Files changed (53) hide show
  1. package/06-02.html +81 -0
  2. package/06-02.js +72 -0
  3. package/06-03.js +7 -0
  4. package/06-04.js +7 -0
  5. package/AnswersLW5.pdf +0 -0
  6. package/m0603/m0603.js +30 -0
  7. package/m0603/node_modules/.package-lock.json +16 -0
  8. package/m0603/node_modules/nodemailer/.gitattributes +6 -0
  9. package/m0603/node_modules/nodemailer/.prettierrc.js +8 -0
  10. package/m0603/node_modules/nodemailer/CHANGELOG.md +725 -0
  11. package/m0603/node_modules/nodemailer/CODE_OF_CONDUCT.md +76 -0
  12. package/m0603/node_modules/nodemailer/CONTRIBUTING.md +67 -0
  13. package/m0603/node_modules/nodemailer/LICENSE +16 -0
  14. package/m0603/node_modules/nodemailer/README.md +97 -0
  15. package/m0603/node_modules/nodemailer/SECURITY.txt +22 -0
  16. package/m0603/node_modules/nodemailer/lib/addressparser/index.js +313 -0
  17. package/m0603/node_modules/nodemailer/lib/base64/index.js +142 -0
  18. package/m0603/node_modules/nodemailer/lib/dkim/index.js +251 -0
  19. package/m0603/node_modules/nodemailer/lib/dkim/message-parser.js +155 -0
  20. package/m0603/node_modules/nodemailer/lib/dkim/relaxed-body.js +154 -0
  21. package/m0603/node_modules/nodemailer/lib/dkim/sign.js +117 -0
  22. package/m0603/node_modules/nodemailer/lib/fetch/cookies.js +281 -0
  23. package/m0603/node_modules/nodemailer/lib/fetch/index.js +274 -0
  24. package/m0603/node_modules/nodemailer/lib/json-transport/index.js +82 -0
  25. package/m0603/node_modules/nodemailer/lib/mail-composer/index.js +558 -0
  26. package/m0603/node_modules/nodemailer/lib/mailer/index.js +427 -0
  27. package/m0603/node_modules/nodemailer/lib/mailer/mail-message.js +315 -0
  28. package/m0603/node_modules/nodemailer/lib/mime-funcs/index.js +625 -0
  29. package/m0603/node_modules/nodemailer/lib/mime-funcs/mime-types.js +2102 -0
  30. package/m0603/node_modules/nodemailer/lib/mime-node/index.js +1290 -0
  31. package/m0603/node_modules/nodemailer/lib/mime-node/last-newline.js +33 -0
  32. package/m0603/node_modules/nodemailer/lib/mime-node/le-unix.js +43 -0
  33. package/m0603/node_modules/nodemailer/lib/mime-node/le-windows.js +52 -0
  34. package/m0603/node_modules/nodemailer/lib/nodemailer.js +143 -0
  35. package/m0603/node_modules/nodemailer/lib/qp/index.js +219 -0
  36. package/m0603/node_modules/nodemailer/lib/sendmail-transport/index.js +210 -0
  37. package/m0603/node_modules/nodemailer/lib/ses-transport/index.js +349 -0
  38. package/m0603/node_modules/nodemailer/lib/shared/index.js +638 -0
  39. package/m0603/node_modules/nodemailer/lib/smtp-connection/data-stream.js +108 -0
  40. package/m0603/node_modules/nodemailer/lib/smtp-connection/http-proxy-client.js +143 -0
  41. package/m0603/node_modules/nodemailer/lib/smtp-connection/index.js +1796 -0
  42. package/m0603/node_modules/nodemailer/lib/smtp-pool/index.js +648 -0
  43. package/m0603/node_modules/nodemailer/lib/smtp-pool/pool-resource.js +253 -0
  44. package/m0603/node_modules/nodemailer/lib/smtp-transport/index.js +416 -0
  45. package/m0603/node_modules/nodemailer/lib/stream-transport/index.js +135 -0
  46. package/m0603/node_modules/nodemailer/lib/well-known/index.js +47 -0
  47. package/m0603/node_modules/nodemailer/lib/well-known/services.json +286 -0
  48. package/m0603/node_modules/nodemailer/lib/xoauth2/index.js +376 -0
  49. package/m0603/node_modules/nodemailer/package.json +46 -0
  50. package/m0603/node_modules/nodemailer/postinstall.js +101 -0
  51. package/m0603/package-lock.json +31 -0
  52. package/m0603/package.json +15 -0
  53. package/package.json +16 -0
@@ -0,0 +1,82 @@
1
+ 'use strict';
2
+
3
+ const packageData = require('../../package.json');
4
+ const shared = require('../shared');
5
+
6
+ /**
7
+ * Generates a Transport object to generate JSON output
8
+ *
9
+ * @constructor
10
+ * @param {Object} optional config parameter
11
+ */
12
+ class JSONTransport {
13
+ constructor(options) {
14
+ options = options || {};
15
+
16
+ this.options = options || {};
17
+
18
+ this.name = 'JSONTransport';
19
+ this.version = packageData.version;
20
+
21
+ this.logger = shared.getLogger(this.options, {
22
+ component: this.options.component || 'json-transport'
23
+ });
24
+ }
25
+
26
+ /**
27
+ * <p>Compiles a mailcomposer message and forwards it to handler that sends it.</p>
28
+ *
29
+ * @param {Object} emailMessage MailComposer object
30
+ * @param {Function} callback Callback function to run when the sending is completed
31
+ */
32
+ send(mail, done) {
33
+ // Sendmail strips this header line by itself
34
+ mail.message.keepBcc = true;
35
+
36
+ let envelope = mail.data.envelope || mail.message.getEnvelope();
37
+ let messageId = mail.message.messageId();
38
+
39
+ let recipients = [].concat(envelope.to || []);
40
+ if (recipients.length > 3) {
41
+ recipients.push('...and ' + recipients.splice(2).length + ' more');
42
+ }
43
+ this.logger.info(
44
+ {
45
+ tnx: 'send',
46
+ messageId
47
+ },
48
+ 'Composing JSON structure of %s to <%s>',
49
+ messageId,
50
+ recipients.join(', ')
51
+ );
52
+
53
+ setImmediate(() => {
54
+ mail.normalize((err, data) => {
55
+ if (err) {
56
+ this.logger.error(
57
+ {
58
+ err,
59
+ tnx: 'send',
60
+ messageId
61
+ },
62
+ 'Failed building JSON structure for %s. %s',
63
+ messageId,
64
+ err.message
65
+ );
66
+ return done(err);
67
+ }
68
+
69
+ delete data.envelope;
70
+ delete data.normalizedHeaders;
71
+
72
+ return done(null, {
73
+ envelope,
74
+ messageId,
75
+ message: this.options.skipEncoding ? data : JSON.stringify(data)
76
+ });
77
+ });
78
+ });
79
+ }
80
+ }
81
+
82
+ module.exports = JSONTransport;
@@ -0,0 +1,558 @@
1
+ /* eslint no-undefined: 0 */
2
+
3
+ 'use strict';
4
+
5
+ const MimeNode = require('../mime-node');
6
+ const mimeFuncs = require('../mime-funcs');
7
+
8
+ /**
9
+ * Creates the object for composing a MimeNode instance out from the mail options
10
+ *
11
+ * @constructor
12
+ * @param {Object} mail Mail options
13
+ */
14
+ class MailComposer {
15
+ constructor(mail) {
16
+ this.mail = mail || {};
17
+ this.message = false;
18
+ }
19
+
20
+ /**
21
+ * Builds MimeNode instance
22
+ */
23
+ compile() {
24
+ this._alternatives = this.getAlternatives();
25
+ this._htmlNode = this._alternatives.filter(alternative => /^text\/html\b/i.test(alternative.contentType)).pop();
26
+ this._attachments = this.getAttachments(!!this._htmlNode);
27
+
28
+ this._useRelated = !!(this._htmlNode && this._attachments.related.length);
29
+ this._useAlternative = this._alternatives.length > 1;
30
+ this._useMixed = this._attachments.attached.length > 1 || (this._alternatives.length && this._attachments.attached.length === 1);
31
+
32
+ // Compose MIME tree
33
+ if (this.mail.raw) {
34
+ this.message = new MimeNode('message/rfc822', { newline: this.mail.newline }).setRaw(this.mail.raw);
35
+ } else if (this._useMixed) {
36
+ this.message = this._createMixed();
37
+ } else if (this._useAlternative) {
38
+ this.message = this._createAlternative();
39
+ } else if (this._useRelated) {
40
+ this.message = this._createRelated();
41
+ } else {
42
+ this.message = this._createContentNode(
43
+ false,
44
+ []
45
+ .concat(this._alternatives || [])
46
+ .concat(this._attachments.attached || [])
47
+ .shift() || {
48
+ contentType: 'text/plain',
49
+ content: ''
50
+ }
51
+ );
52
+ }
53
+
54
+ // Add custom headers
55
+ if (this.mail.headers) {
56
+ this.message.addHeader(this.mail.headers);
57
+ }
58
+
59
+ // Add headers to the root node, always overrides custom headers
60
+ ['from', 'sender', 'to', 'cc', 'bcc', 'reply-to', 'in-reply-to', 'references', 'subject', 'message-id', 'date'].forEach(header => {
61
+ let key = header.replace(/-(\w)/g, (o, c) => c.toUpperCase());
62
+ if (this.mail[key]) {
63
+ this.message.setHeader(header, this.mail[key]);
64
+ }
65
+ });
66
+
67
+ // Sets custom envelope
68
+ if (this.mail.envelope) {
69
+ this.message.setEnvelope(this.mail.envelope);
70
+ }
71
+
72
+ // ensure Message-Id value
73
+ this.message.messageId();
74
+
75
+ return this.message;
76
+ }
77
+
78
+ /**
79
+ * List all attachments. Resulting attachment objects can be used as input for MimeNode nodes
80
+ *
81
+ * @param {Boolean} findRelated If true separate related attachments from attached ones
82
+ * @returns {Object} An object of arrays (`related` and `attached`)
83
+ */
84
+ getAttachments(findRelated) {
85
+ let icalEvent, eventObject;
86
+ let attachments = [].concat(this.mail.attachments || []).map((attachment, i) => {
87
+ let data;
88
+ let isMessageNode = /^message\//i.test(attachment.contentType);
89
+
90
+ if (/^data:/i.test(attachment.path || attachment.href)) {
91
+ attachment = this._processDataUrl(attachment);
92
+ }
93
+
94
+ data = {
95
+ contentType: attachment.contentType || mimeFuncs.detectMimeType(attachment.filename || attachment.path || attachment.href || 'bin'),
96
+ contentDisposition: attachment.contentDisposition || (isMessageNode ? 'inline' : 'attachment'),
97
+ contentTransferEncoding: 'contentTransferEncoding' in attachment ? attachment.contentTransferEncoding : 'base64'
98
+ };
99
+
100
+ if (attachment.filename) {
101
+ data.filename = attachment.filename;
102
+ } else if (!isMessageNode && attachment.filename !== false) {
103
+ data.filename = (attachment.path || attachment.href || '').split('/').pop().split('?').shift() || 'attachment-' + (i + 1);
104
+ if (data.filename.indexOf('.') < 0) {
105
+ data.filename += '.' + mimeFuncs.detectExtension(data.contentType);
106
+ }
107
+ }
108
+
109
+ if (/^https?:\/\//i.test(attachment.path)) {
110
+ attachment.href = attachment.path;
111
+ attachment.path = undefined;
112
+ }
113
+
114
+ if (attachment.cid) {
115
+ data.cid = attachment.cid;
116
+ }
117
+
118
+ if (attachment.raw) {
119
+ data.raw = attachment.raw;
120
+ } else if (attachment.path) {
121
+ data.content = {
122
+ path: attachment.path
123
+ };
124
+ } else if (attachment.href) {
125
+ data.content = {
126
+ href: attachment.href,
127
+ httpHeaders: attachment.httpHeaders
128
+ };
129
+ } else {
130
+ data.content = attachment.content || '';
131
+ }
132
+
133
+ if (attachment.encoding) {
134
+ data.encoding = attachment.encoding;
135
+ }
136
+
137
+ if (attachment.headers) {
138
+ data.headers = attachment.headers;
139
+ }
140
+
141
+ return data;
142
+ });
143
+
144
+ if (this.mail.icalEvent) {
145
+ if (
146
+ typeof this.mail.icalEvent === 'object' &&
147
+ (this.mail.icalEvent.content || this.mail.icalEvent.path || this.mail.icalEvent.href || this.mail.icalEvent.raw)
148
+ ) {
149
+ icalEvent = this.mail.icalEvent;
150
+ } else {
151
+ icalEvent = {
152
+ content: this.mail.icalEvent
153
+ };
154
+ }
155
+
156
+ eventObject = {};
157
+ Object.keys(icalEvent).forEach(key => {
158
+ eventObject[key] = icalEvent[key];
159
+ });
160
+
161
+ eventObject.contentType = 'application/ics';
162
+ if (!eventObject.headers) {
163
+ eventObject.headers = {};
164
+ }
165
+ eventObject.filename = eventObject.filename || 'invite.ics';
166
+ eventObject.headers['Content-Disposition'] = 'attachment';
167
+ eventObject.headers['Content-Transfer-Encoding'] = 'base64';
168
+ }
169
+
170
+ if (!findRelated) {
171
+ return {
172
+ attached: attachments.concat(eventObject || []),
173
+ related: []
174
+ };
175
+ } else {
176
+ return {
177
+ attached: attachments.filter(attachment => !attachment.cid).concat(eventObject || []),
178
+ related: attachments.filter(attachment => !!attachment.cid)
179
+ };
180
+ }
181
+ }
182
+
183
+ /**
184
+ * List alternatives. Resulting objects can be used as input for MimeNode nodes
185
+ *
186
+ * @returns {Array} An array of alternative elements. Includes the `text` and `html` values as well
187
+ */
188
+ getAlternatives() {
189
+ let alternatives = [],
190
+ text,
191
+ html,
192
+ watchHtml,
193
+ amp,
194
+ icalEvent,
195
+ eventObject;
196
+
197
+ if (this.mail.text) {
198
+ if (typeof this.mail.text === 'object' && (this.mail.text.content || this.mail.text.path || this.mail.text.href || this.mail.text.raw)) {
199
+ text = this.mail.text;
200
+ } else {
201
+ text = {
202
+ content: this.mail.text
203
+ };
204
+ }
205
+ text.contentType = 'text/plain; charset=utf-8';
206
+ }
207
+
208
+ if (this.mail.watchHtml) {
209
+ if (
210
+ typeof this.mail.watchHtml === 'object' &&
211
+ (this.mail.watchHtml.content || this.mail.watchHtml.path || this.mail.watchHtml.href || this.mail.watchHtml.raw)
212
+ ) {
213
+ watchHtml = this.mail.watchHtml;
214
+ } else {
215
+ watchHtml = {
216
+ content: this.mail.watchHtml
217
+ };
218
+ }
219
+ watchHtml.contentType = 'text/watch-html; charset=utf-8';
220
+ }
221
+
222
+ if (this.mail.amp) {
223
+ if (typeof this.mail.amp === 'object' && (this.mail.amp.content || this.mail.amp.path || this.mail.amp.href || this.mail.amp.raw)) {
224
+ amp = this.mail.amp;
225
+ } else {
226
+ amp = {
227
+ content: this.mail.amp
228
+ };
229
+ }
230
+ amp.contentType = 'text/x-amp-html; charset=utf-8';
231
+ }
232
+
233
+ // NB! when including attachments with a calendar alternative you might end up in a blank screen on some clients
234
+ if (this.mail.icalEvent) {
235
+ if (
236
+ typeof this.mail.icalEvent === 'object' &&
237
+ (this.mail.icalEvent.content || this.mail.icalEvent.path || this.mail.icalEvent.href || this.mail.icalEvent.raw)
238
+ ) {
239
+ icalEvent = this.mail.icalEvent;
240
+ } else {
241
+ icalEvent = {
242
+ content: this.mail.icalEvent
243
+ };
244
+ }
245
+
246
+ eventObject = {};
247
+ Object.keys(icalEvent).forEach(key => {
248
+ eventObject[key] = icalEvent[key];
249
+ });
250
+
251
+ if (eventObject.content && typeof eventObject.content === 'object') {
252
+ // we are going to have the same attachment twice, so mark this to be
253
+ // resolved just once
254
+ eventObject.content._resolve = true;
255
+ }
256
+
257
+ eventObject.filename = false;
258
+ eventObject.contentType = 'text/calendar; charset=utf-8; method=' + (eventObject.method || 'PUBLISH').toString().trim().toUpperCase();
259
+ if (!eventObject.headers) {
260
+ eventObject.headers = {};
261
+ }
262
+ }
263
+
264
+ if (this.mail.html) {
265
+ if (typeof this.mail.html === 'object' && (this.mail.html.content || this.mail.html.path || this.mail.html.href || this.mail.html.raw)) {
266
+ html = this.mail.html;
267
+ } else {
268
+ html = {
269
+ content: this.mail.html
270
+ };
271
+ }
272
+ html.contentType = 'text/html; charset=utf-8';
273
+ }
274
+
275
+ []
276
+ .concat(text || [])
277
+ .concat(watchHtml || [])
278
+ .concat(amp || [])
279
+ .concat(html || [])
280
+ .concat(eventObject || [])
281
+ .concat(this.mail.alternatives || [])
282
+ .forEach(alternative => {
283
+ let data;
284
+
285
+ if (/^data:/i.test(alternative.path || alternative.href)) {
286
+ alternative = this._processDataUrl(alternative);
287
+ }
288
+
289
+ data = {
290
+ contentType: alternative.contentType || mimeFuncs.detectMimeType(alternative.filename || alternative.path || alternative.href || 'txt'),
291
+ contentTransferEncoding: alternative.contentTransferEncoding
292
+ };
293
+
294
+ if (alternative.filename) {
295
+ data.filename = alternative.filename;
296
+ }
297
+
298
+ if (/^https?:\/\//i.test(alternative.path)) {
299
+ alternative.href = alternative.path;
300
+ alternative.path = undefined;
301
+ }
302
+
303
+ if (alternative.raw) {
304
+ data.raw = alternative.raw;
305
+ } else if (alternative.path) {
306
+ data.content = {
307
+ path: alternative.path
308
+ };
309
+ } else if (alternative.href) {
310
+ data.content = {
311
+ href: alternative.href
312
+ };
313
+ } else {
314
+ data.content = alternative.content || '';
315
+ }
316
+
317
+ if (alternative.encoding) {
318
+ data.encoding = alternative.encoding;
319
+ }
320
+
321
+ if (alternative.headers) {
322
+ data.headers = alternative.headers;
323
+ }
324
+
325
+ alternatives.push(data);
326
+ });
327
+
328
+ return alternatives;
329
+ }
330
+
331
+ /**
332
+ * Builds multipart/mixed node. It should always contain different type of elements on the same level
333
+ * eg. text + attachments
334
+ *
335
+ * @param {Object} parentNode Parent for this note. If it does not exist, a root node is created
336
+ * @returns {Object} MimeNode node element
337
+ */
338
+ _createMixed(parentNode) {
339
+ let node;
340
+
341
+ if (!parentNode) {
342
+ node = new MimeNode('multipart/mixed', {
343
+ baseBoundary: this.mail.baseBoundary,
344
+ textEncoding: this.mail.textEncoding,
345
+ boundaryPrefix: this.mail.boundaryPrefix,
346
+ disableUrlAccess: this.mail.disableUrlAccess,
347
+ disableFileAccess: this.mail.disableFileAccess,
348
+ normalizeHeaderKey: this.mail.normalizeHeaderKey,
349
+ newline: this.mail.newline
350
+ });
351
+ } else {
352
+ node = parentNode.createChild('multipart/mixed', {
353
+ disableUrlAccess: this.mail.disableUrlAccess,
354
+ disableFileAccess: this.mail.disableFileAccess,
355
+ normalizeHeaderKey: this.mail.normalizeHeaderKey,
356
+ newline: this.mail.newline
357
+ });
358
+ }
359
+
360
+ if (this._useAlternative) {
361
+ this._createAlternative(node);
362
+ } else if (this._useRelated) {
363
+ this._createRelated(node);
364
+ }
365
+
366
+ []
367
+ .concat((!this._useAlternative && this._alternatives) || [])
368
+ .concat(this._attachments.attached || [])
369
+ .forEach(element => {
370
+ // if the element is a html node from related subpart then ignore it
371
+ if (!this._useRelated || element !== this._htmlNode) {
372
+ this._createContentNode(node, element);
373
+ }
374
+ });
375
+
376
+ return node;
377
+ }
378
+
379
+ /**
380
+ * Builds multipart/alternative node. It should always contain same type of elements on the same level
381
+ * eg. text + html view of the same data
382
+ *
383
+ * @param {Object} parentNode Parent for this note. If it does not exist, a root node is created
384
+ * @returns {Object} MimeNode node element
385
+ */
386
+ _createAlternative(parentNode) {
387
+ let node;
388
+
389
+ if (!parentNode) {
390
+ node = new MimeNode('multipart/alternative', {
391
+ baseBoundary: this.mail.baseBoundary,
392
+ textEncoding: this.mail.textEncoding,
393
+ boundaryPrefix: this.mail.boundaryPrefix,
394
+ disableUrlAccess: this.mail.disableUrlAccess,
395
+ disableFileAccess: this.mail.disableFileAccess,
396
+ normalizeHeaderKey: this.mail.normalizeHeaderKey,
397
+ newline: this.mail.newline
398
+ });
399
+ } else {
400
+ node = parentNode.createChild('multipart/alternative', {
401
+ disableUrlAccess: this.mail.disableUrlAccess,
402
+ disableFileAccess: this.mail.disableFileAccess,
403
+ normalizeHeaderKey: this.mail.normalizeHeaderKey,
404
+ newline: this.mail.newline
405
+ });
406
+ }
407
+
408
+ this._alternatives.forEach(alternative => {
409
+ if (this._useRelated && this._htmlNode === alternative) {
410
+ this._createRelated(node);
411
+ } else {
412
+ this._createContentNode(node, alternative);
413
+ }
414
+ });
415
+
416
+ return node;
417
+ }
418
+
419
+ /**
420
+ * Builds multipart/related node. It should always contain html node with related attachments
421
+ *
422
+ * @param {Object} parentNode Parent for this note. If it does not exist, a root node is created
423
+ * @returns {Object} MimeNode node element
424
+ */
425
+ _createRelated(parentNode) {
426
+ let node;
427
+
428
+ if (!parentNode) {
429
+ node = new MimeNode('multipart/related; type="text/html"', {
430
+ baseBoundary: this.mail.baseBoundary,
431
+ textEncoding: this.mail.textEncoding,
432
+ boundaryPrefix: this.mail.boundaryPrefix,
433
+ disableUrlAccess: this.mail.disableUrlAccess,
434
+ disableFileAccess: this.mail.disableFileAccess,
435
+ normalizeHeaderKey: this.mail.normalizeHeaderKey,
436
+ newline: this.mail.newline
437
+ });
438
+ } else {
439
+ node = parentNode.createChild('multipart/related; type="text/html"', {
440
+ disableUrlAccess: this.mail.disableUrlAccess,
441
+ disableFileAccess: this.mail.disableFileAccess,
442
+ normalizeHeaderKey: this.mail.normalizeHeaderKey,
443
+ newline: this.mail.newline
444
+ });
445
+ }
446
+
447
+ this._createContentNode(node, this._htmlNode);
448
+
449
+ this._attachments.related.forEach(alternative => this._createContentNode(node, alternative));
450
+
451
+ return node;
452
+ }
453
+
454
+ /**
455
+ * Creates a regular node with contents
456
+ *
457
+ * @param {Object} parentNode Parent for this note. If it does not exist, a root node is created
458
+ * @param {Object} element Node data
459
+ * @returns {Object} MimeNode node element
460
+ */
461
+ _createContentNode(parentNode, element) {
462
+ element = element || {};
463
+ element.content = element.content || '';
464
+
465
+ let node;
466
+ let encoding = (element.encoding || 'utf8')
467
+ .toString()
468
+ .toLowerCase()
469
+ .replace(/[-_\s]/g, '');
470
+
471
+ if (!parentNode) {
472
+ node = new MimeNode(element.contentType, {
473
+ filename: element.filename,
474
+ baseBoundary: this.mail.baseBoundary,
475
+ textEncoding: this.mail.textEncoding,
476
+ boundaryPrefix: this.mail.boundaryPrefix,
477
+ disableUrlAccess: this.mail.disableUrlAccess,
478
+ disableFileAccess: this.mail.disableFileAccess,
479
+ normalizeHeaderKey: this.mail.normalizeHeaderKey,
480
+ newline: this.mail.newline
481
+ });
482
+ } else {
483
+ node = parentNode.createChild(element.contentType, {
484
+ filename: element.filename,
485
+ textEncoding: this.mail.textEncoding,
486
+ disableUrlAccess: this.mail.disableUrlAccess,
487
+ disableFileAccess: this.mail.disableFileAccess,
488
+ normalizeHeaderKey: this.mail.normalizeHeaderKey,
489
+ newline: this.mail.newline
490
+ });
491
+ }
492
+
493
+ // add custom headers
494
+ if (element.headers) {
495
+ node.addHeader(element.headers);
496
+ }
497
+
498
+ if (element.cid) {
499
+ node.setHeader('Content-Id', '<' + element.cid.replace(/[<>]/g, '') + '>');
500
+ }
501
+
502
+ if (element.contentTransferEncoding) {
503
+ node.setHeader('Content-Transfer-Encoding', element.contentTransferEncoding);
504
+ } else if (this.mail.encoding && /^text\//i.test(element.contentType)) {
505
+ node.setHeader('Content-Transfer-Encoding', this.mail.encoding);
506
+ }
507
+
508
+ if (!/^text\//i.test(element.contentType) || element.contentDisposition) {
509
+ node.setHeader('Content-Disposition', element.contentDisposition || (element.cid ? 'inline' : 'attachment'));
510
+ }
511
+
512
+ if (typeof element.content === 'string' && !['utf8', 'usascii', 'ascii'].includes(encoding)) {
513
+ element.content = Buffer.from(element.content, encoding);
514
+ }
515
+
516
+ // prefer pregenerated raw content
517
+ if (element.raw) {
518
+ node.setRaw(element.raw);
519
+ } else {
520
+ node.setContent(element.content);
521
+ }
522
+
523
+ return node;
524
+ }
525
+
526
+ /**
527
+ * Parses data uri and converts it to a Buffer
528
+ *
529
+ * @param {Object} element Content element
530
+ * @return {Object} Parsed element
531
+ */
532
+ _processDataUrl(element) {
533
+ let parts = (element.path || element.href).match(/^data:((?:[^;]*;)*(?:[^,]*)),(.*)$/i);
534
+ if (!parts) {
535
+ return element;
536
+ }
537
+
538
+ element.content = /\bbase64$/i.test(parts[1]) ? Buffer.from(parts[2], 'base64') : Buffer.from(decodeURIComponent(parts[2]));
539
+
540
+ if ('path' in element) {
541
+ element.path = false;
542
+ }
543
+
544
+ if ('href' in element) {
545
+ element.href = false;
546
+ }
547
+
548
+ parts[1].split(';').forEach(item => {
549
+ if (/^\w+\/[^/]+$/i.test(item)) {
550
+ element.contentType = element.contentType || item.toLowerCase();
551
+ }
552
+ });
553
+
554
+ return element;
555
+ }
556
+ }
557
+
558
+ module.exports = MailComposer;