@nocobase/plugin-workflow-mailer 2.2.17 → 2.2.18

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.
Files changed (53) hide show
  1. package/dist/externalVersion.js +6 -6
  2. package/dist/node_modules/joi/dist/joi-browser.min.js +1 -1
  3. package/dist/node_modules/joi/lib/index.js +1 -1
  4. package/dist/node_modules/joi/lib/messages.js +35 -6
  5. package/dist/node_modules/joi/lib/types/keys.js +18 -1
  6. package/dist/node_modules/joi/lib/types/link.js +18 -2
  7. package/dist/node_modules/joi/lib/types/string.js +2 -2
  8. package/dist/node_modules/joi/package.json +1 -1
  9. package/dist/node_modules/nodemailer/.ncurc.js +2 -0
  10. package/dist/node_modules/nodemailer/.prettierignore +8 -0
  11. package/dist/node_modules/nodemailer/.prettierrc +12 -0
  12. package/dist/node_modules/nodemailer/.prettierrc.js +2 -0
  13. package/dist/node_modules/nodemailer/.release-please-config.json +9 -0
  14. package/dist/node_modules/nodemailer/eslint.config.js +88 -0
  15. package/dist/node_modules/nodemailer/lib/addressparser/index.js +314 -71
  16. package/dist/node_modules/nodemailer/lib/base64/index.js +9 -13
  17. package/dist/node_modules/nodemailer/lib/dkim/index.js +17 -18
  18. package/dist/node_modules/nodemailer/lib/dkim/message-parser.js +12 -13
  19. package/dist/node_modules/nodemailer/lib/dkim/relaxed-body.js +3 -3
  20. package/dist/node_modules/nodemailer/lib/dkim/sign.js +22 -18
  21. package/dist/node_modules/nodemailer/lib/errors.js +59 -0
  22. package/dist/node_modules/nodemailer/lib/fetch/cookies.js +14 -19
  23. package/dist/node_modules/nodemailer/lib/fetch/index.js +164 -27
  24. package/dist/node_modules/nodemailer/lib/json-transport/index.js +4 -4
  25. package/dist/node_modules/nodemailer/lib/mail-composer/index.js +229 -155
  26. package/dist/node_modules/nodemailer/lib/mailer/index.js +106 -54
  27. package/dist/node_modules/nodemailer/lib/mailer/mail-message.js +106 -68
  28. package/dist/node_modules/nodemailer/lib/mime-funcs/index.js +105 -59
  29. package/dist/node_modules/nodemailer/lib/mime-funcs/mime-types.js +21 -14
  30. package/dist/node_modules/nodemailer/lib/mime-node/index.js +389 -137
  31. package/dist/node_modules/nodemailer/lib/mime-node/last-newline.js +1 -1
  32. package/dist/node_modules/nodemailer/lib/mime-node/le-unix.js +4 -7
  33. package/dist/node_modules/nodemailer/lib/mime-node/le-windows.js +1 -4
  34. package/dist/node_modules/nodemailer/lib/nodemailer.js +1 -1
  35. package/dist/node_modules/nodemailer/lib/punycode/index.js +1 -1
  36. package/dist/node_modules/nodemailer/lib/qp/index.js +33 -22
  37. package/dist/node_modules/nodemailer/lib/sendmail-transport/index.js +54 -44
  38. package/dist/node_modules/nodemailer/lib/ses-transport/index.js +110 -193
  39. package/dist/node_modules/nodemailer/lib/shared/index.js +299 -240
  40. package/dist/node_modules/nodemailer/lib/shared/objects.js +42 -0
  41. package/dist/node_modules/nodemailer/lib/shared/url.js +151 -0
  42. package/dist/node_modules/nodemailer/lib/smtp-connection/data-stream.js +3 -6
  43. package/dist/node_modules/nodemailer/lib/smtp-connection/http-proxy-client.js +50 -19
  44. package/dist/node_modules/nodemailer/lib/smtp-connection/index.js +415 -223
  45. package/dist/node_modules/nodemailer/lib/smtp-pool/index.js +27 -34
  46. package/dist/node_modules/nodemailer/lib/smtp-pool/pool-resource.js +19 -16
  47. package/dist/node_modules/nodemailer/lib/smtp-transport/index.js +66 -53
  48. package/dist/node_modules/nodemailer/lib/stream-transport/index.js +16 -7
  49. package/dist/node_modules/nodemailer/lib/well-known/index.js +7 -7
  50. package/dist/node_modules/nodemailer/lib/well-known/services.json +328 -38
  51. package/dist/node_modules/nodemailer/lib/xoauth2/index.js +105 -33
  52. package/dist/node_modules/nodemailer/package.json +1 -1
  53. package/package.json +4 -4
@@ -0,0 +1,42 @@
1
+ 'use strict';
2
+
3
+ // Safe copying of objects whose keys come from the caller.
4
+ //
5
+ // This lives in its own leaf module, like ./url.js, so that every layer can reach it.
6
+ // lib/shared/index.js requires lib/fetch, so lib/fetch can not require lib/shared back,
7
+ // and lib/mime-funcs is a leaf that would otherwise pull in dns/net/os/fs for a string
8
+ // comparison. lib/shared/index.js re-exports both functions for the callers that already
9
+ // depend on it.
10
+
11
+ /**
12
+ * Detects a key that can not be copied onto a plain object with `target[key] = value`.
13
+ *
14
+ * "__proto__" is the only one: assigning it runs the inherited setter and replaces the
15
+ * prototype of the target instead of adding a property to it, so a caller can smuggle
16
+ * values past validation that only inspects own keys. JSON.parse produces such a key
17
+ * where an object literal can not. "constructor" and "prototype" have no such setter and
18
+ * become ordinary own properties, so dropping them would only discard legitimate values.
19
+ *
20
+ * @param {String} key Key to check
21
+ * @returns {Boolean} true if the key must not be copied
22
+ */
23
+ module.exports.isProtoKey = key => key === '__proto__';
24
+
25
+ /**
26
+ * Copies own enumerable keys from a source object to a target object. Every copy that
27
+ * walks the keys of user supplied data goes through here, see isProtoKey.
28
+ *
29
+ * @param {Object} target Object to copy the keys to
30
+ * @param {Object} source Object to copy the keys from
31
+ * @param {Function} [skip] Optional predicate, return true to leave a key out
32
+ * @returns {Object} The target object
33
+ */
34
+ module.exports.copyOwnKeys = (target, source, skip) => {
35
+ Object.keys(source || {}).forEach(key => {
36
+ if (module.exports.isProtoKey(key) || (skip && skip(key))) {
37
+ return;
38
+ }
39
+ target[key] = source[key];
40
+ });
41
+ return target;
42
+ };
@@ -0,0 +1,151 @@
1
+ 'use strict';
2
+
3
+ // URL parsing wrapper. Prefers the WHATWG `URL` (a global on Node 10+, and
4
+ // available as `require('url').URL` since Node 6.13+) and only falls back to the
5
+ // legacy, deprecation-warning-emitting `url.parse()` / `url.resolve()` on ancient
6
+ // Node versions that predate the WHATWG implementation.
7
+ //
8
+ // The WHATWG `URL` exposes a different shape than the legacy parser, so results
9
+ // are normalized back into the legacy field names the rest of the codebase reads
10
+ // (`protocol`, `hostname`, `port`, `pathname`, `path`, `search`, `auth`, `query`,
11
+ // `href`). This keeps every existing call site unchanged.
12
+ //
13
+ // Known, accepted divergences from the legacy parser:
14
+ // - non-special schemes (smtp:/smtps:/direct:) are not host-lowercased by
15
+ // WHATWG; cosmetic only, SMTP/DNS hosts are case-insensitive. (IDNA mapping
16
+ // and IPv6 brackets are normalized back by normalizeHostname below.)
17
+ // - a literal unescaped ':' inside a password is percent-encoded by WHATWG;
18
+ // such passwords should be percent-encoded by the caller anyway.
19
+
20
+ const urllib = require('url');
21
+ const punycode = require('../punycode');
22
+
23
+ // WHATWG URL constructor if available, otherwise undefined (Node < 6.13).
24
+ const URLImpl = (typeof URL !== 'undefined' && URL) || urllib.URL;
25
+
26
+ // Matches a "scheme:" not followed by "//" (and with something after it), used
27
+ // to re-insert the authority separator the legacy parser did not require.
28
+ const SLASHLESS_AUTHORITY = /^([a-zA-Z][a-zA-Z0-9+.-]*:)(?!\/\/)(.+)$/;
29
+
30
+ // decodeURIComponent that never throws. Legacy url.parse() decodes the auth
31
+ // component but tolerates malformed percent sequences, so mirror that.
32
+ function safeDecode(str) {
33
+ try {
34
+ return decodeURIComponent(str);
35
+ } catch (_err) {
36
+ return str;
37
+ }
38
+ }
39
+
40
+ // Derives the legacy-shaped bare hostname from a WHATWG URL. WHATWG keeps IPv6
41
+ // literals bracketed ('[::1]') and, for non-special schemes (smtp:/smtps:/socks:),
42
+ // percent-encodes a non-ASCII host instead of IDNA-mapping it. Both forms are
43
+ // un-resolvable when handed to net/dns/http.request — which is what every call
44
+ // site does — so map them back to what legacy url.parse() returned: the bare
45
+ // address and the punycode form. Idempotent on plain ASCII and already-punycode
46
+ // hosts, so special-scheme hosts (already IDNA-mapped by WHATWG) pass through.
47
+ function normalizeHostname(raw) {
48
+ let hostname = raw || '';
49
+ if (!hostname) {
50
+ // Host-less URL (e.g. 'direct:'): legacy returned '' here, not null;
51
+ // consumers do `hostname.length` / `'.' + hostname`, so keep it a string.
52
+ return '';
53
+ }
54
+ if (hostname.charAt(0) === '[' && hostname.charAt(hostname.length - 1) === ']') {
55
+ return hostname.slice(1, -1);
56
+ }
57
+ return punycode.toASCII(safeDecode(hostname));
58
+ }
59
+
60
+ module.exports.parse = (input, parseQueryString) => {
61
+ input = input || '';
62
+
63
+ if (!URLImpl) {
64
+ // Node < 6.13: no WHATWG URL available, use the legacy parser.
65
+ return urllib.parse(input, parseQueryString);
66
+ }
67
+
68
+ // Legacy url.parse() parses a "user:pass@host:port" authority that follows
69
+ // the scheme even without the "//" separator, for schemes outside its
70
+ // built-in slashed-protocol list (smtp:/smtps:/socks:/...). The WHATWG
71
+ // parser instead treats a scheme not followed by "//" as an opaque path.
72
+ // Re-insert the "//" so slash-less connection/proxy URLs keep resolving to
73
+ // an authority, as they did before. This assumes a slash-authority scheme,
74
+ // which every consumer here uses (http/https/smtp/smtps/socks/direct); an
75
+ // opaque scheme like mailto:/data:/tel: would be mis-split, but none reach
76
+ // this module.
77
+ const slashless = SLASHLESS_AUTHORITY.exec(input);
78
+ const normalized = slashless ? slashless[1] + '//' + slashless[2] : input;
79
+
80
+ let u;
81
+ try {
82
+ u = new URLImpl(normalized);
83
+ } catch (_err) {
84
+ // WHATWG rejects some input the legacy parser tolerated (empty/relative
85
+ // strings, scheme-relative '//host/path', out-of-range ports, ...). Fall
86
+ // back to the legacy parser so behavior — including the downstream errors
87
+ // callers rely on — is preserved. This is the only path that can still
88
+ // emit a deprecation warning; it fires for anything WHATWG cannot
89
+ // represent, including legitimate relative URLs, not just malformed input.
90
+ return urllib.parse(input, parseQueryString);
91
+ }
92
+
93
+ const hostname = normalizeHostname(u.hostname);
94
+ const port = u.port || null;
95
+ const pathname = u.pathname || null;
96
+ const search = u.search || null;
97
+
98
+ // Legacy `.auth` is the decoded "user[:pass]" string; WHATWG keeps the
99
+ // username/password percent-encoded, so decode to stay byte-compatible with
100
+ // existing consumers (parseConnectionUrl, Basic/Proxy-Authorization headers).
101
+ let auth = null;
102
+ if (u.username || u.password) {
103
+ // Gate on password too: legacy url.parse('smtps://:pass@host').auth was
104
+ // ':pass'. Dropping it would silently connect unauthenticated.
105
+ auth = safeDecode(u.username) + (u.password ? ':' + safeDecode(u.password) : '');
106
+ }
107
+
108
+ let query;
109
+ if (parseQueryString) {
110
+ // Mirror querystring.parse(): null-prototype object, repeated keys → array.
111
+ query = Object.create(null);
112
+ u.searchParams.forEach((value, key) => {
113
+ if (Object.prototype.hasOwnProperty.call(query, key)) {
114
+ if (Array.isArray(query[key])) {
115
+ query[key].push(value);
116
+ } else {
117
+ query[key] = [query[key], value];
118
+ }
119
+ } else {
120
+ query[key] = value;
121
+ }
122
+ });
123
+ } else {
124
+ query = search ? search.slice(1) : null;
125
+ }
126
+
127
+ return {
128
+ protocol: u.protocol || null,
129
+ host: u.host || null,
130
+ hostname,
131
+ port,
132
+ pathname,
133
+ search,
134
+ path: (pathname || '') + (search || '') || null,
135
+ href: u.href,
136
+ auth,
137
+ query
138
+ };
139
+ };
140
+
141
+ module.exports.resolve = (from, to) => {
142
+ if (!URLImpl) {
143
+ return urllib.resolve(from, to);
144
+ }
145
+ try {
146
+ return new URLImpl(to, from).href;
147
+ } catch (_err) {
148
+ // Malformed target — fall back to the legacy resolver.
149
+ return urllib.resolve(from, to);
150
+ }
151
+ };
@@ -1,7 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const stream = require('stream');
4
- const Transform = stream.Transform;
3
+ const { Transform } = require('stream');
5
4
 
6
5
  /**
7
6
  * Escapes dots in the beginning of lines. Ends the stream with <CR><LF>.<CR><LF>
@@ -12,9 +11,7 @@ const Transform = stream.Transform;
12
11
  class DataStream extends Transform {
13
12
  constructor(options) {
14
13
  super(options);
15
- // init Transform
16
14
  this.options = options || {};
17
- this._curLine = '';
18
15
 
19
16
  this.inByteCount = 0;
20
17
  this.outByteCount = 0;
@@ -25,7 +22,7 @@ class DataStream extends Transform {
25
22
  * Escapes dots
26
23
  */
27
24
  _transform(chunk, encoding, done) {
28
- let chunks = [];
25
+ const chunks = [];
29
26
  let chunklen = 0;
30
27
  let i,
31
28
  len,
@@ -53,7 +50,7 @@ class DataStream extends Transform {
53
50
  lastPos = i + 1;
54
51
  }
55
52
  } else if (chunk[i] === 0x0a) {
56
- // .
53
+ // \n
57
54
  if ((i && chunk[i - 1] !== 0x0d) || (!i && this.lastByte !== 0x0d)) {
58
55
  if (i > lastPos) {
59
56
  buf = chunk.slice(lastPos, i);
@@ -6,7 +6,12 @@
6
6
 
7
7
  const net = require('net');
8
8
  const tls = require('tls');
9
- const urllib = require('url');
9
+ const urllib = require('../shared/url');
10
+ const errors = require('../errors');
11
+
12
+ // Cap the CONNECT response we buffer before the header terminator, so a proxy that
13
+ // never sends \r\n\r\n cannot grow memory unboundedly before the socket times out.
14
+ const MAX_RESPONSE_HEADER_BYTES = 64 * 1024;
10
15
 
11
16
  /**
12
17
  * Establishes proxied connection to destinationPort
@@ -18,57 +23,74 @@ const urllib = require('url');
18
23
  * @param {String} proxyUrl proxy configuration, etg "http://proxy.host:3128/"
19
24
  * @param {Number} destinationPort Port to open in destination host
20
25
  * @param {String} destinationHost Destination hostname
26
+ * @param {Object} [tlsOptions] Optional TLS options for an HTTPS proxy (e.g. { rejectUnauthorized: false })
21
27
  * @param {Function} callback Callback to run with the rocket object once connection is established
22
28
  */
23
- function httpProxyClient(proxyUrl, destinationPort, destinationHost, callback) {
24
- let proxy = urllib.parse(proxyUrl);
29
+ function httpProxyClient(proxyUrl, destinationPort, destinationHost, tlsOptions, callback) {
30
+ if (typeof tlsOptions === 'function') {
31
+ callback = tlsOptions;
32
+ tlsOptions = {};
33
+ }
34
+ tlsOptions = tlsOptions || {};
35
+
36
+ // Reject CRLF in the destination before it reaches the CONNECT request line
37
+ // and Host header. A tainted host/port could otherwise inject additional
38
+ // request headers into the proxy connection (HTTP request splitting).
39
+ destinationPort = Number(destinationPort) || 0;
40
+ if (!destinationPort || /[\r\n]/.test(destinationHost)) {
41
+ const err = new Error('Invalid proxy destination');
42
+ err.code = errors.EPROXY;
43
+ return setImmediate(() => callback(err));
44
+ }
25
45
 
26
- // create a socket connection to the proxy server
27
- let options;
28
- let connect;
29
- let socket;
46
+ const proxy = urllib.parse(proxyUrl);
30
47
 
31
- options = {
48
+ const connectOptions = {
32
49
  host: proxy.hostname,
33
50
  port: Number(proxy.port) ? Number(proxy.port) : proxy.protocol === 'https:' ? 443 : 80
34
51
  };
35
52
 
53
+ let connect;
36
54
  if (proxy.protocol === 'https:') {
37
- // we can use untrusted proxies as long as we verify actual SMTP certificates
38
- options.rejectUnauthorized = false;
55
+ // Validate the proxy's TLS certificate by default. A caller that uses a
56
+ // self-signed proxy (e.g. integration tests) opts out explicitly with
57
+ // tls.rejectUnauthorized === false.
58
+ connectOptions.rejectUnauthorized = tlsOptions.rejectUnauthorized !== false;
39
59
  connect = tls.connect.bind(tls);
40
60
  } else {
41
61
  connect = net.connect.bind(net);
42
62
  }
43
63
 
64
+ let socket;
65
+
44
66
  // Error harness for initial connection. Once connection is established, the responsibility
45
67
  // to handle errors is passed to whoever uses this socket
46
68
  let finished = false;
47
- let tempSocketErr = err => {
69
+ const tempSocketErr = err => {
48
70
  if (finished) {
49
71
  return;
50
72
  }
51
73
  finished = true;
52
74
  try {
53
75
  socket.destroy();
54
- } catch (E) {
76
+ } catch (_E) {
55
77
  // ignore
56
78
  }
57
79
  callback(err);
58
80
  };
59
81
 
60
- let timeoutErr = () => {
61
- let err = new Error('Proxy socket timed out');
82
+ const timeoutErr = () => {
83
+ const err = new Error('Proxy socket timed out');
62
84
  err.code = 'ETIMEDOUT';
63
85
  tempSocketErr(err);
64
86
  };
65
87
 
66
- socket = connect(options, () => {
88
+ socket = connect(connectOptions, () => {
67
89
  if (finished) {
68
90
  return;
69
91
  }
70
92
 
71
- let reqHeaders = {
93
+ const reqHeaders = {
72
94
  Host: destinationHost + ':' + destinationPort,
73
95
  Connection: 'close'
74
96
  };
@@ -92,7 +114,7 @@ function httpProxyClient(proxyUrl, destinationPort, destinationHost, callback) {
92
114
  );
93
115
 
94
116
  let headers = '';
95
- let onSocketData = chunk => {
117
+ const onSocketData = chunk => {
96
118
  let match;
97
119
  let remainder;
98
120
 
@@ -118,10 +140,12 @@ function httpProxyClient(proxyUrl, destinationPort, destinationHost, callback) {
118
140
  if (!match || (match[1] || '').charAt(0) !== '2') {
119
141
  try {
120
142
  socket.destroy();
121
- } catch (E) {
143
+ } catch (_E) {
122
144
  // ignore
123
145
  }
124
- return callback(new Error('Invalid response from proxy' + ((match && ': ' + match[1]) || '')));
146
+ const err = new Error('Invalid response from proxy' + ((match && ': ' + match[1]) || ''));
147
+ err.code = errors.EPROXY;
148
+ return callback(err);
125
149
  }
126
150
 
127
151
  socket.removeListener('error', tempSocketErr);
@@ -130,6 +154,13 @@ function httpProxyClient(proxyUrl, destinationPort, destinationHost, callback) {
130
154
 
131
155
  return callback(null, socket);
132
156
  }
157
+
158
+ if (headers.length > MAX_RESPONSE_HEADER_BYTES) {
159
+ socket.removeListener('data', onSocketData);
160
+ const err = new Error('Proxy response headers too large');
161
+ err.code = errors.EPROXY;
162
+ return tempSocketErr(err);
163
+ }
133
164
  };
134
165
  socket.on('data', onSocketData);
135
166
  });