nodemailer 10.1.2 → 10.1.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.
@@ -26,6 +26,35 @@ const QUOTED_STRING = /^"(?:[^"\\]|\\[\s\S])*"$/;
26
26
  // else goes into angle brackets so that the header can not be read as more addresses than
27
27
  // the envelope carries
28
28
  const PLAIN_ADDRESS = /^[^\s"(),:;<>@[\\\]]+@[^\s"(),:;<>@[\\\]]+$/;
29
+ /**
30
+ * A domain literal that ends an address, see _normalizeAddress
31
+ */
32
+ const DOMAIN_LITERAL_TAIL = /@(\[[^[\]\\]*\])$/;
33
+ /**
34
+ * Removes the whitespace inside every <...> of a References value. A "<" with no ">" after
35
+ * it is left as it is. An index scan, the regex /<[^>]*>/g rescans the rest of the value
36
+ * from every such "<"
37
+ *
38
+ * @param value References header value
39
+ * @returns The value with the msg-ids closed up
40
+ */
41
+ function stripWhitespaceInAngleBrackets(value) {
42
+ let result = '';
43
+ let pos = 0;
44
+ for (;;) {
45
+ const open = value.indexOf('<', pos);
46
+ if (open < 0) {
47
+ break;
48
+ }
49
+ const close = value.indexOf('>', open + 1);
50
+ if (close < 0) {
51
+ break;
52
+ }
53
+ result += value.slice(pos, open) + value.slice(open, close + 1).replace(/\s/g, '');
54
+ pos = close + 1;
55
+ }
56
+ return result + value.slice(pos);
57
+ }
29
58
  // domainToASCII and domainToUnicode are WHATWG host parsers rather than plain IDNA
30
59
  // mappers, so they do more than map: they cut the host at '/', '\\', '?' and '#', drop C0
31
60
  // controls, and percent-decode. Handing them 'evil.example/mail.corp.example' returns the
@@ -1319,26 +1348,26 @@ class MimeNode {
1319
1348
  }
1320
1349
  return value;
1321
1350
  // space separated list of values enclosed in <>
1322
- case 'References':
1323
- value = [].concat
1324
- .apply([], [].concat(value || '').map(elm => {
1325
- elm = (elm || '')
1351
+ case 'References': {
1352
+ const ids = [];
1353
+ for (const entry of [].concat(value || '')) {
1354
+ const elm = (entry || '')
1326
1355
  .toString()
1327
1356
  .replace(/\r?\n|\r/g, ' ')
1328
1357
  .replace(/[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/g, '')
1329
1358
  .trim();
1330
- return elm.replace(/<[^>]*>/g, str => str.replace(/\s/g, '')).split(/\s+/);
1331
- }))
1332
- .map(elm => {
1333
- if (elm.charAt(0) !== '<') {
1334
- elm = '<' + elm;
1335
- }
1336
- if (elm.charAt(elm.length - 1) !== '>') {
1337
- elm = elm + '>';
1359
+ for (let id of stripWhitespaceInAngleBrackets(elm).split(/\s+/)) {
1360
+ if (id.charAt(0) !== '<') {
1361
+ id = '<' + id;
1362
+ }
1363
+ if (id.charAt(id.length - 1) !== '>') {
1364
+ id = id + '>';
1365
+ }
1366
+ ids.push(id);
1338
1367
  }
1339
- return elm;
1340
- });
1341
- return value.join(' ').trim();
1368
+ }
1369
+ return ids.join(' ').trim();
1370
+ }
1342
1371
  case 'Date':
1343
1372
  if (Object.prototype.toString.call(value) === '[object Date]') {
1344
1373
  return value.toUTCString().replace(/GMT/, '+0000');
@@ -1417,7 +1446,10 @@ class MimeNode {
1417
1446
  // callers use an empty value to detect a missing address
1418
1447
  return address;
1419
1448
  }
1420
- const lastAt = address.lastIndexOf('@');
1449
+ // dtext includes '@', so a domain literal is split off at the '@' in front of it and
1450
+ // not at the last one, which delivered 'a@[x@evil.com]' to evil.com
1451
+ const literal = address.charAt(address.length - 1) === ']' ? DOMAIN_LITERAL_TAIL.exec(address) : null;
1452
+ const lastAt = literal ? address.length - literal[1].length - 1 : address.lastIndexOf('@');
1421
1453
  if (lastAt < 0) {
1422
1454
  // Bare username, there is no domain to split off
1423
1455
  return this._normalizeLocalPart(address);
@@ -1,3 +1,3 @@
1
1
  export declare const name = "nodemailer";
2
- export declare const version = "10.1.2";
2
+ export declare const version = "10.1.4";
3
3
  export declare const homepage = "https://nodemailer.com/";
@@ -1,4 +1,4 @@
1
1
  // Generated by scripts/build.js from package.json. Do not edit by hand.
2
2
  export const name = 'nodemailer';
3
- export const version = '10.1.2';
3
+ export const version = '10.1.4';
4
4
  export const homepage = 'https://nodemailer.com/';
@@ -19,10 +19,27 @@ import * as punycode from '../punycode/index.js';
19
19
  // Matches a "scheme:" not followed by "//" (and with something after it), used
20
20
  // to re-insert the authority separator the legacy parser did not require.
21
21
  const SLASHLESS_AUTHORITY = /^([a-zA-Z][a-zA-Z0-9+.-]*:)(?!\/\/)([\s\S]+)$/;
22
- // Leading and trailing C0 controls and spaces, which the WHATWG parser strips before it
23
- // looks at the input. Stripped up front so that the slash-less form is recognized in a
24
- // value read from a file with a trailing newline as well.
25
- const SURROUNDING_WHITESPACE = /^[\x00-\x20]+|[\x00-\x20]+$/g;
22
+ /**
23
+ * Drops the leading and trailing C0 controls and spaces, which the WHATWG parser strips
24
+ * before it looks at the input. Stripped up front so that the slash-less form is recognized
25
+ * in a value read from a file with a trailing newline as well. An index scan, the regex
26
+ * /^[\x00-\x20]+|[\x00-\x20]+$/g retried a run of spaces inside the value from every
27
+ * position in it
28
+ *
29
+ * @param input URL string
30
+ * @returns The string without the surrounding controls and spaces
31
+ */
32
+ function stripSurroundingWhitespace(input) {
33
+ let start = 0;
34
+ let end = input.length;
35
+ while (start < end && input.charCodeAt(start) <= 0x20) {
36
+ start++;
37
+ }
38
+ while (end > start && input.charCodeAt(end - 1) <= 0x20) {
39
+ end--;
40
+ }
41
+ return input.slice(start, end);
42
+ }
26
43
  // Leading characters legacy url.parse() skips before it reads the scheme
27
44
  const LEGACY_TRIM = /^[\x00-\x20\u00a0\ufeff]+/;
28
45
  // The authority of a "scheme://authority/..." or a scheme-relative "//authority/..."
@@ -117,7 +134,7 @@ function normalizeHostname(raw, href) {
117
134
  return mapped;
118
135
  }
119
136
  export const parse = (input, parseQueryString) => {
120
- input = (input || '').replace(SURROUNDING_WHITESPACE, '');
137
+ input = stripSurroundingWhitespace(input || '');
121
138
  // Legacy url.parse() parses a "user:pass@host:port" authority that follows
122
139
  // the scheme even without the "//" separator, for schemes outside its
123
140
  // built-in slashed-protocol list (smtp:/smtps:/socks:/...). The WHATWG
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodemailer",
3
- "version": "10.1.2",
3
+ "version": "10.1.4",
4
4
  "description": "Easy as cake e-mail sending from your Node.js applications",
5
5
  "type": "module",
6
6
  "main": "./dist/cjs/nodemailer.js",