@nocobase/plugin-workflow-mailer 2.2.16 → 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.
- package/dist/externalVersion.js +6 -6
- package/dist/node_modules/joi/dist/joi-browser.min.js +1 -1
- package/dist/node_modules/joi/lib/index.js +1 -1
- package/dist/node_modules/joi/lib/messages.js +35 -6
- package/dist/node_modules/joi/lib/types/keys.js +18 -1
- package/dist/node_modules/joi/lib/types/link.js +18 -2
- package/dist/node_modules/joi/lib/types/string.js +2 -2
- package/dist/node_modules/joi/package.json +1 -1
- package/dist/node_modules/nodemailer/.ncurc.js +2 -0
- package/dist/node_modules/nodemailer/.prettierignore +8 -0
- package/dist/node_modules/nodemailer/.prettierrc +12 -0
- package/dist/node_modules/nodemailer/.prettierrc.js +2 -0
- package/dist/node_modules/nodemailer/.release-please-config.json +9 -0
- package/dist/node_modules/nodemailer/eslint.config.js +88 -0
- package/dist/node_modules/nodemailer/lib/addressparser/index.js +314 -71
- package/dist/node_modules/nodemailer/lib/base64/index.js +9 -13
- package/dist/node_modules/nodemailer/lib/dkim/index.js +17 -18
- package/dist/node_modules/nodemailer/lib/dkim/message-parser.js +12 -13
- package/dist/node_modules/nodemailer/lib/dkim/relaxed-body.js +3 -3
- package/dist/node_modules/nodemailer/lib/dkim/sign.js +22 -18
- package/dist/node_modules/nodemailer/lib/errors.js +59 -0
- package/dist/node_modules/nodemailer/lib/fetch/cookies.js +14 -19
- package/dist/node_modules/nodemailer/lib/fetch/index.js +164 -27
- package/dist/node_modules/nodemailer/lib/json-transport/index.js +4 -4
- package/dist/node_modules/nodemailer/lib/mail-composer/index.js +229 -155
- package/dist/node_modules/nodemailer/lib/mailer/index.js +106 -54
- package/dist/node_modules/nodemailer/lib/mailer/mail-message.js +106 -68
- package/dist/node_modules/nodemailer/lib/mime-funcs/index.js +105 -59
- package/dist/node_modules/nodemailer/lib/mime-funcs/mime-types.js +21 -14
- package/dist/node_modules/nodemailer/lib/mime-node/index.js +389 -137
- package/dist/node_modules/nodemailer/lib/mime-node/last-newline.js +1 -1
- package/dist/node_modules/nodemailer/lib/mime-node/le-unix.js +4 -7
- package/dist/node_modules/nodemailer/lib/mime-node/le-windows.js +1 -4
- package/dist/node_modules/nodemailer/lib/nodemailer.js +1 -1
- package/dist/node_modules/nodemailer/lib/punycode/index.js +1 -1
- package/dist/node_modules/nodemailer/lib/qp/index.js +33 -22
- package/dist/node_modules/nodemailer/lib/sendmail-transport/index.js +54 -44
- package/dist/node_modules/nodemailer/lib/ses-transport/index.js +110 -193
- package/dist/node_modules/nodemailer/lib/shared/index.js +299 -240
- package/dist/node_modules/nodemailer/lib/shared/objects.js +42 -0
- package/dist/node_modules/nodemailer/lib/shared/url.js +151 -0
- package/dist/node_modules/nodemailer/lib/smtp-connection/data-stream.js +3 -6
- package/dist/node_modules/nodemailer/lib/smtp-connection/http-proxy-client.js +50 -19
- package/dist/node_modules/nodemailer/lib/smtp-connection/index.js +415 -223
- package/dist/node_modules/nodemailer/lib/smtp-pool/index.js +27 -34
- package/dist/node_modules/nodemailer/lib/smtp-pool/pool-resource.js +19 -16
- package/dist/node_modules/nodemailer/lib/smtp-transport/index.js +66 -53
- package/dist/node_modules/nodemailer/lib/stream-transport/index.js +16 -7
- package/dist/node_modules/nodemailer/lib/well-known/index.js +7 -7
- package/dist/node_modules/nodemailer/lib/well-known/services.json +328 -38
- package/dist/node_modules/nodemailer/lib/xoauth2/index.js +105 -33
- package/dist/node_modules/nodemailer/package.json +1 -1
- package/package.json +4 -4
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const Stream = require('stream')
|
|
3
|
+
const { Stream } = require('stream');
|
|
4
4
|
const nmfetch = require('../fetch');
|
|
5
5
|
const crypto = require('crypto');
|
|
6
6
|
const shared = require('../shared');
|
|
7
|
+
const errors = require('../errors');
|
|
7
8
|
|
|
8
9
|
/**
|
|
9
10
|
* XOAUTH2 access_token generator for Gmail.
|
|
@@ -32,6 +33,7 @@ const shared = require('../shared');
|
|
|
32
33
|
* @param {Number} options.expires Optional Access Token expire time in ms
|
|
33
34
|
* @param {Number} options.timeout Optional TTL for Access Token in seconds
|
|
34
35
|
* @param {Function} options.provisionCallback Function to run when a new access token is required
|
|
36
|
+
* @param {Object} options.tls Optional TLS options forwarded to the HTTPS token request. Defaults to strict cert validation; supply { rejectUnauthorized: false } only for self-hosted OAuth providers on private CAs.
|
|
35
37
|
*/
|
|
36
38
|
class XOAuth2 extends Stream {
|
|
37
39
|
constructor(options, logger) {
|
|
@@ -41,11 +43,13 @@ class XOAuth2 extends Stream {
|
|
|
41
43
|
|
|
42
44
|
if (options && options.serviceClient) {
|
|
43
45
|
if (!options.privateKey || !options.user) {
|
|
44
|
-
|
|
46
|
+
const err = new Error('Options "privateKey" and "user" are required for service account!');
|
|
47
|
+
err.code = errors.EOAUTH2;
|
|
48
|
+
setImmediate(() => this.emit('error', err));
|
|
45
49
|
return;
|
|
46
50
|
}
|
|
47
51
|
|
|
48
|
-
|
|
52
|
+
const serviceRequestTimeout = Math.min(Math.max(Number(this.options.serviceRequestTimeout) || 0, 0), 3600);
|
|
49
53
|
this.options.serviceRequestTimeout = serviceRequestTimeout || 5 * 60;
|
|
50
54
|
}
|
|
51
55
|
|
|
@@ -69,9 +73,12 @@ class XOAuth2 extends Stream {
|
|
|
69
73
|
if (this.options.expires && Number(this.options.expires)) {
|
|
70
74
|
this.expires = this.options.expires;
|
|
71
75
|
} else {
|
|
72
|
-
|
|
76
|
+
const timeout = Math.max(Number(this.options.timeout) || 0, 0);
|
|
73
77
|
this.expires = (timeout && Date.now() + timeout * 1000) || 0;
|
|
74
78
|
}
|
|
79
|
+
|
|
80
|
+
this.renewing = false; // Track if renewal is in progress
|
|
81
|
+
this.renewalQueue = []; // Queue for pending requests during renewal
|
|
75
82
|
}
|
|
76
83
|
|
|
77
84
|
/**
|
|
@@ -82,14 +89,63 @@ class XOAuth2 extends Stream {
|
|
|
82
89
|
*/
|
|
83
90
|
getToken(renew, callback) {
|
|
84
91
|
if (!renew && this.accessToken && (!this.expires || this.expires > Date.now())) {
|
|
92
|
+
this.logger.debug(
|
|
93
|
+
{
|
|
94
|
+
tnx: 'OAUTH2',
|
|
95
|
+
user: this.options.user,
|
|
96
|
+
action: 'reuse'
|
|
97
|
+
},
|
|
98
|
+
'Reusing existing access token for %s',
|
|
99
|
+
this.options.user
|
|
100
|
+
);
|
|
85
101
|
return callback(null, this.accessToken);
|
|
86
102
|
}
|
|
87
103
|
|
|
88
|
-
|
|
89
|
-
|
|
104
|
+
// check if it is possible to renew, if not, return the current token or error
|
|
105
|
+
if (!this.provisionCallback && !this.options.refreshToken && !this.options.serviceClient) {
|
|
106
|
+
if (this.accessToken) {
|
|
107
|
+
this.logger.debug(
|
|
108
|
+
{
|
|
109
|
+
tnx: 'OAUTH2',
|
|
110
|
+
user: this.options.user,
|
|
111
|
+
action: 'reuse'
|
|
112
|
+
},
|
|
113
|
+
'Reusing existing access token (no refresh capability) for %s',
|
|
114
|
+
this.options.user
|
|
115
|
+
);
|
|
116
|
+
return callback(null, this.accessToken);
|
|
117
|
+
}
|
|
118
|
+
this.logger.error(
|
|
119
|
+
{
|
|
120
|
+
tnx: 'OAUTH2',
|
|
121
|
+
user: this.options.user,
|
|
122
|
+
action: 'renew'
|
|
123
|
+
},
|
|
124
|
+
'Cannot renew access token for %s: No refresh mechanism available',
|
|
125
|
+
this.options.user
|
|
126
|
+
);
|
|
127
|
+
const err = new Error("Can't create new access token for user");
|
|
128
|
+
err.code = errors.EOAUTH2;
|
|
129
|
+
return callback(err);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// If renewal already in progress, queue this request instead of starting another
|
|
133
|
+
if (this.renewing) {
|
|
134
|
+
return this.renewalQueue.push({ renew, callback });
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
this.renewing = true;
|
|
138
|
+
|
|
139
|
+
// Handles token renewal completion - processes queued requests and cleans up
|
|
140
|
+
const generateCallback = (err, accessToken) => {
|
|
141
|
+
this.renewalQueue.forEach(item => item.callback(err, accessToken));
|
|
142
|
+
this.renewalQueue = [];
|
|
143
|
+
this.renewing = false;
|
|
144
|
+
|
|
145
|
+
if (err) {
|
|
90
146
|
this.logger.error(
|
|
91
147
|
{
|
|
92
|
-
err
|
|
148
|
+
err,
|
|
93
149
|
tnx: 'OAUTH2',
|
|
94
150
|
user: this.options.user,
|
|
95
151
|
action: 'renew'
|
|
@@ -108,7 +164,8 @@ class XOAuth2 extends Stream {
|
|
|
108
164
|
this.options.user
|
|
109
165
|
);
|
|
110
166
|
}
|
|
111
|
-
|
|
167
|
+
// Complete original request
|
|
168
|
+
callback(err, accessToken);
|
|
112
169
|
};
|
|
113
170
|
|
|
114
171
|
if (this.provisionCallback) {
|
|
@@ -154,8 +211,8 @@ class XOAuth2 extends Stream {
|
|
|
154
211
|
let loggedUrlOptions;
|
|
155
212
|
if (this.options.serviceClient) {
|
|
156
213
|
// service account - https://developers.google.com/identity/protocols/OAuth2ServiceAccount
|
|
157
|
-
|
|
158
|
-
|
|
214
|
+
const iat = Math.floor(Date.now() / 1000); // unix time
|
|
215
|
+
const tokenData = {
|
|
159
216
|
iss: this.options.serviceClient,
|
|
160
217
|
scope: this.options.scope || 'https://mail.google.com/',
|
|
161
218
|
sub: this.options.user,
|
|
@@ -166,8 +223,10 @@ class XOAuth2 extends Stream {
|
|
|
166
223
|
let token;
|
|
167
224
|
try {
|
|
168
225
|
token = this.jwtSignRS256(tokenData);
|
|
169
|
-
} catch (
|
|
170
|
-
|
|
226
|
+
} catch (_err) {
|
|
227
|
+
const err = new Error("Can't generate token. Check your auth options");
|
|
228
|
+
err.code = errors.EOAUTH2;
|
|
229
|
+
return callback(err);
|
|
171
230
|
}
|
|
172
231
|
|
|
173
232
|
urlOptions = {
|
|
@@ -181,7 +240,9 @@ class XOAuth2 extends Stream {
|
|
|
181
240
|
};
|
|
182
241
|
} else {
|
|
183
242
|
if (!this.options.refreshToken) {
|
|
184
|
-
|
|
243
|
+
const err = new Error("Can't create new access token for user");
|
|
244
|
+
err.code = errors.EOAUTH2;
|
|
245
|
+
return callback(err);
|
|
185
246
|
}
|
|
186
247
|
|
|
187
248
|
// web app - https://developers.google.com/identity/protocols/OAuth2WebServer
|
|
@@ -200,10 +261,8 @@ class XOAuth2 extends Stream {
|
|
|
200
261
|
};
|
|
201
262
|
}
|
|
202
263
|
|
|
203
|
-
Object.
|
|
204
|
-
|
|
205
|
-
loggedUrlOptions[key] = this.options.customParams[key];
|
|
206
|
-
});
|
|
264
|
+
Object.assign(urlOptions, this.options.customParams);
|
|
265
|
+
Object.assign(loggedUrlOptions, this.options.customParams);
|
|
207
266
|
|
|
208
267
|
this.logger.debug(
|
|
209
268
|
{
|
|
@@ -238,17 +297,15 @@ class XOAuth2 extends Stream {
|
|
|
238
297
|
'Response: %s',
|
|
239
298
|
(body || '').toString()
|
|
240
299
|
);
|
|
241
|
-
|
|
300
|
+
const err = new Error('Invalid authentication response');
|
|
301
|
+
err.code = errors.EOAUTH2;
|
|
302
|
+
return callback(err);
|
|
242
303
|
}
|
|
243
304
|
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
} else {
|
|
249
|
-
logData[key] = (data[key] || '').toString().substr(0, 6) + '...';
|
|
250
|
-
}
|
|
251
|
-
});
|
|
305
|
+
const logData = Object.assign({}, data);
|
|
306
|
+
if (logData.access_token) {
|
|
307
|
+
logData.access_token = (logData.access_token || '').toString().substr(0, 6) + '...';
|
|
308
|
+
}
|
|
252
309
|
|
|
253
310
|
this.logger.debug(
|
|
254
311
|
{
|
|
@@ -269,7 +326,9 @@ class XOAuth2 extends Stream {
|
|
|
269
326
|
if (data.error_uri) {
|
|
270
327
|
errorMessage += ' (' + data.error_uri + ')';
|
|
271
328
|
}
|
|
272
|
-
|
|
329
|
+
const err = new Error(errorMessage);
|
|
330
|
+
err.code = errors.EOAUTH2;
|
|
331
|
+
return callback(err);
|
|
273
332
|
}
|
|
274
333
|
|
|
275
334
|
if (data.access_token) {
|
|
@@ -277,7 +336,9 @@ class XOAuth2 extends Stream {
|
|
|
277
336
|
return callback(null, this.accessToken);
|
|
278
337
|
}
|
|
279
338
|
|
|
280
|
-
|
|
339
|
+
const err = new Error('No access token');
|
|
340
|
+
err.code = errors.EOAUTH2;
|
|
341
|
+
return callback(err);
|
|
281
342
|
});
|
|
282
343
|
}
|
|
283
344
|
|
|
@@ -288,7 +349,7 @@ class XOAuth2 extends Stream {
|
|
|
288
349
|
* @return {String} Base64 encoded token for IMAP or SMTP login
|
|
289
350
|
*/
|
|
290
351
|
buildXOAuth2Token(accessToken) {
|
|
291
|
-
|
|
352
|
+
const authData = ['user=' + (this.options.user || ''), 'auth=Bearer ' + (accessToken || this.accessToken), '', ''];
|
|
292
353
|
return Buffer.from(authData.join('\x01'), 'utf-8').toString('base64');
|
|
293
354
|
}
|
|
294
355
|
|
|
@@ -307,15 +368,26 @@ class XOAuth2 extends Stream {
|
|
|
307
368
|
postRequest(url, payload, params, callback) {
|
|
308
369
|
let returned = false;
|
|
309
370
|
|
|
310
|
-
|
|
371
|
+
const chunks = [];
|
|
311
372
|
let chunklen = 0;
|
|
312
373
|
|
|
313
|
-
|
|
374
|
+
const fetchOptions = {
|
|
314
375
|
method: 'post',
|
|
315
376
|
headers: params.customHeaders,
|
|
316
377
|
body: payload,
|
|
317
378
|
allowErrorResponse: true
|
|
318
|
-
}
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
// OAuth2 token endpoints are credential-bearing. lib/fetch already
|
|
382
|
+
// validates certs by default; pin rejectUnauthorized:true here so the
|
|
383
|
+
// token fetch stays strict, while still layering params.tls (the
|
|
384
|
+
// user's options.tls) on top so callers with a self-hosted provider on
|
|
385
|
+
// a private CA can override.
|
|
386
|
+
if (/^https:/i.test(url)) {
|
|
387
|
+
fetchOptions.tls = Object.assign({ rejectUnauthorized: true }, params.tls || {});
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
const req = nmfetch(url, fetchOptions);
|
|
319
391
|
|
|
320
392
|
req.on('readable', () => {
|
|
321
393
|
let chunk;
|
|
@@ -368,7 +440,7 @@ class XOAuth2 extends Stream {
|
|
|
368
440
|
*/
|
|
369
441
|
jwtSignRS256(payload) {
|
|
370
442
|
payload = ['{"alg":"RS256","typ":"JWT"}', JSON.stringify(payload)].map(val => this.toBase64URL(val)).join('.');
|
|
371
|
-
|
|
443
|
+
const signature = crypto.createSign('RSA-SHA256').update(payload).sign(this.options.privateKey);
|
|
372
444
|
return payload + '.' + this.toBase64URL(signature);
|
|
373
445
|
}
|
|
374
446
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name":"nodemailer","version":"
|
|
1
|
+
{"name":"nodemailer","version":"9.1.1","description":"Easy as cake e-mail sending from your Node.js applications","main":"lib/nodemailer.js","scripts":{"test":"node --test --test-concurrency=1 $(find test \\( -name '*-test.js' -o -name '*.test.js' \\))","test:coverage":"c8 node --test --test-concurrency=1 $(find test \\( -name '*-test.js' -o -name '*.test.js' \\))","format":"prettier --write \"**/*.{js,json,md}\"","format:check":"prettier --check \"**/*.{js,json,md}\"","lint":"eslint .","lint:fix":"eslint . --fix","update":"rm -rf node_modules/ package-lock.json && ncu -u && npm install","test:syntax":"docker run --rm -v \"$PWD:/app:ro\" -w /app node:6-alpine node test/syntax-compat.js"},"repository":{"type":"git","url":"https://github.com/nodemailer/nodemailer.git"},"keywords":["Nodemailer"],"author":"Andris Reinman","license":"MIT-0","bugs":{"url":"https://github.com/nodemailer/nodemailer/issues"},"homepage":"https://nodemailer.com/","devDependencies":{"@aws-sdk/client-sesv2":"3.1121.0","bunyan":"1.8.15","c8":"12.0.0","eslint":"10.9.1","eslint-config-prettier":"10.1.8","globals":"17.11.0","libbase64":"1.3.0","libmime":"5.4.2","libqp":"2.1.1","prettier":"3.9.6","proxy":"1.0.2","proxy-test-server":"1.0.0","smtp-server":"3.19.4"},"engines":{"node":">=6.0.0"},"_lastModified":"2026-09-25T14:54:18.536Z"}
|
package/package.json
CHANGED
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
"description": "Send email in workflow.",
|
|
7
7
|
"description.ru-RU": "Отправляет электронное письмо в рамках рабочего процесса.",
|
|
8
8
|
"description.zh-CN": "可用于在工作流中发送电子邮件。",
|
|
9
|
-
"version": "2.2.
|
|
9
|
+
"version": "2.2.18",
|
|
10
10
|
"license": "Apache-2.0",
|
|
11
11
|
"main": "./dist/server/index.js",
|
|
12
12
|
"homepage": "https://docs.nocobase.com/handbook/workflow-smtp-mailer",
|
|
@@ -14,8 +14,8 @@
|
|
|
14
14
|
"homepage.ru-RU": "https://docs-ru.nocobase.com/handbook/workflow-smtp-mailer",
|
|
15
15
|
"devDependencies": {
|
|
16
16
|
"antd": "5.x",
|
|
17
|
-
"joi": "^17.13.
|
|
18
|
-
"nodemailer": "
|
|
17
|
+
"joi": "^17.13.6",
|
|
18
|
+
"nodemailer": "^9.1.1",
|
|
19
19
|
"react": "18.x"
|
|
20
20
|
},
|
|
21
21
|
"peerDependencies": {
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"@nocobase/server": "2.x",
|
|
28
28
|
"@nocobase/test": "2.x"
|
|
29
29
|
},
|
|
30
|
-
"gitHead": "
|
|
30
|
+
"gitHead": "0c464cd27b2c1ccdf10b00d339bf6599b18bee22",
|
|
31
31
|
"keywords": [
|
|
32
32
|
"NocoBase",
|
|
33
33
|
"Workflow",
|