Haraka 3.1.0 → 3.1.2

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 (160) hide show
  1. package/.prettierignore +4 -0
  2. package/CONTRIBUTORS.md +5 -5
  3. package/Changes.md +69 -50
  4. package/Plugins.md +3 -1
  5. package/README.md +1 -1
  6. package/bin/haraka +475 -478
  7. package/config/outbound.ini +3 -0
  8. package/connection.js +1072 -1108
  9. package/docs/Connection.md +29 -30
  10. package/docs/CoreConfig.md +38 -39
  11. package/docs/CustomReturnCodes.md +0 -1
  12. package/docs/HAProxy.md +2 -2
  13. package/docs/Header.md +1 -1
  14. package/docs/Logging.md +29 -5
  15. package/docs/Outbound.md +93 -78
  16. package/docs/Plugins.md +103 -108
  17. package/docs/Transaction.md +49 -51
  18. package/docs/Tutorial.md +127 -143
  19. package/docs/deprecated/access.md +0 -1
  20. package/docs/deprecated/backscatterer.md +2 -3
  21. package/docs/deprecated/connect.rdns_access.md +18 -27
  22. package/docs/deprecated/data.headers.md +0 -1
  23. package/docs/deprecated/data.nomsgid.md +1 -2
  24. package/docs/deprecated/data.noreceived.md +1 -2
  25. package/docs/deprecated/data.rfc5322_header_checks.md +1 -2
  26. package/docs/deprecated/dkim_sign.md +13 -17
  27. package/docs/deprecated/dkim_verify.md +9 -17
  28. package/docs/deprecated/dnsbl.md +36 -38
  29. package/docs/deprecated/dnswl.md +41 -43
  30. package/docs/deprecated/lookup_rdns.strict.md +21 -34
  31. package/docs/deprecated/mail_from.access.md +17 -25
  32. package/docs/deprecated/mail_from.blocklist.md +9 -12
  33. package/docs/deprecated/mail_from.nobounces.md +1 -2
  34. package/docs/deprecated/rcpt_to.access.md +20 -27
  35. package/docs/deprecated/rcpt_to.blocklist.md +10 -13
  36. package/docs/deprecated/rcpt_to.routes.md +0 -1
  37. package/docs/deprecated/rdns.regexp.md +13 -15
  38. package/docs/plugins/aliases.md +89 -89
  39. package/docs/plugins/auth/auth_bridge.md +5 -7
  40. package/docs/plugins/auth/auth_ldap.md +11 -14
  41. package/docs/plugins/auth/auth_proxy.md +10 -12
  42. package/docs/plugins/auth/auth_vpopmaild.md +5 -6
  43. package/docs/plugins/auth/flat_file.md +4 -4
  44. package/docs/plugins/block_me.md +3 -3
  45. package/docs/plugins/data.signatures.md +1 -2
  46. package/docs/plugins/delay_deny.md +3 -4
  47. package/docs/plugins/max_unrecognized_commands.md +4 -4
  48. package/docs/plugins/prevent_credential_leaks.md +6 -6
  49. package/docs/plugins/process_title.md +18 -18
  50. package/docs/plugins/queue/deliver.md +2 -3
  51. package/docs/plugins/queue/discard.md +4 -4
  52. package/docs/plugins/queue/lmtp.md +1 -3
  53. package/docs/plugins/queue/qmail-queue.md +7 -9
  54. package/docs/plugins/queue/quarantine.md +16 -21
  55. package/docs/plugins/queue/rabbitmq.md +8 -11
  56. package/docs/plugins/queue/rabbitmq_amqplib.md +43 -39
  57. package/docs/plugins/queue/smtp_bridge.md +7 -10
  58. package/docs/plugins/queue/smtp_forward.md +42 -34
  59. package/docs/plugins/queue/smtp_proxy.md +30 -29
  60. package/docs/plugins/queue/test.md +1 -3
  61. package/docs/plugins/rcpt_to.in_host_list.md +6 -6
  62. package/docs/plugins/rcpt_to.max_count.md +1 -1
  63. package/docs/plugins/record_envelope_addresses.md +3 -3
  64. package/docs/plugins/reseed_rng.md +6 -6
  65. package/docs/plugins/status.md +9 -8
  66. package/docs/plugins/tarpit.md +7 -11
  67. package/docs/plugins/tls.md +12 -17
  68. package/docs/plugins/toobusy.md +4 -4
  69. package/docs/plugins/xclient.md +3 -3
  70. package/docs/tutorials/Migrating_from_v1_to_v2.md +19 -41
  71. package/docs/tutorials/SettingUpOutbound.md +6 -9
  72. package/endpoint.js +35 -38
  73. package/eslint.config.mjs +22 -19
  74. package/haraka.js +42 -47
  75. package/host_pool.js +75 -79
  76. package/http/html/404.html +45 -49
  77. package/http/html/index.html +39 -28
  78. package/http/package.json +2 -4
  79. package/line_socket.js +27 -28
  80. package/logger.js +182 -201
  81. package/outbound/client_pool.js +34 -27
  82. package/outbound/config.js +64 -59
  83. package/outbound/fsync_writestream.js +24 -25
  84. package/outbound/hmail.js +888 -835
  85. package/outbound/index.js +194 -187
  86. package/outbound/qfile.js +49 -52
  87. package/outbound/queue.js +197 -190
  88. package/outbound/timer_queue.js +41 -43
  89. package/outbound/tls.js +68 -61
  90. package/outbound/todo.js +11 -11
  91. package/package.json +38 -33
  92. package/plugins/.eslintrc.yaml +0 -1
  93. package/plugins/auth/auth_base.js +123 -127
  94. package/plugins/auth/auth_bridge.js +7 -7
  95. package/plugins/auth/auth_proxy.js +121 -126
  96. package/plugins/auth/auth_vpopmaild.js +84 -85
  97. package/plugins/auth/flat_file.js +18 -17
  98. package/plugins/block_me.js +31 -31
  99. package/plugins/data.signatures.js +13 -13
  100. package/plugins/delay_deny.js +65 -61
  101. package/plugins/prevent_credential_leaks.js +23 -23
  102. package/plugins/process_title.js +125 -128
  103. package/plugins/profile.js +5 -5
  104. package/plugins/queue/deliver.js +3 -3
  105. package/plugins/queue/discard.js +13 -14
  106. package/plugins/queue/lmtp.js +16 -17
  107. package/plugins/queue/qmail-queue.js +54 -55
  108. package/plugins/queue/quarantine.js +68 -70
  109. package/plugins/queue/rabbitmq.js +80 -87
  110. package/plugins/queue/rabbitmq_amqplib.js +75 -54
  111. package/plugins/queue/smtp_bridge.js +16 -16
  112. package/plugins/queue/smtp_forward.js +175 -179
  113. package/plugins/queue/smtp_proxy.js +69 -71
  114. package/plugins/queue/test.js +9 -9
  115. package/plugins/rcpt_to.host_list_base.js +30 -34
  116. package/plugins/rcpt_to.in_host_list.js +19 -19
  117. package/plugins/record_envelope_addresses.js +4 -4
  118. package/plugins/reseed_rng.js +4 -4
  119. package/plugins/status.js +90 -97
  120. package/plugins/tarpit.js +25 -14
  121. package/plugins/tls.js +68 -68
  122. package/plugins/toobusy.js +21 -23
  123. package/plugins/xclient.js +51 -53
  124. package/plugins.js +276 -293
  125. package/rfc1869.js +30 -35
  126. package/server.js +308 -299
  127. package/smtp_client.js +244 -228
  128. package/test/.eslintrc.yaml +0 -1
  129. package/test/connection.js +127 -134
  130. package/test/endpoint.js +53 -47
  131. package/test/fixtures/line_socket.js +12 -12
  132. package/test/fixtures/util_hmailitem.js +89 -85
  133. package/test/host_pool.js +90 -92
  134. package/test/installation/plugins/base_plugin.js +2 -2
  135. package/test/installation/plugins/folder_plugin/index.js +2 -3
  136. package/test/installation/plugins/inherits.js +3 -3
  137. package/test/installation/plugins/load_first.js +2 -3
  138. package/test/installation/plugins/plugin.js +1 -3
  139. package/test/installation/plugins/tls.js +2 -4
  140. package/test/logger.js +135 -116
  141. package/test/outbound/hmail.js +49 -35
  142. package/test/outbound/index.js +118 -101
  143. package/test/outbound/qfile.js +51 -53
  144. package/test/outbound_bounce_net_errors.js +84 -69
  145. package/test/outbound_bounce_rfc3464.js +235 -165
  146. package/test/plugins/auth/auth_base.js +420 -279
  147. package/test/plugins/auth/auth_vpopmaild.js +38 -39
  148. package/test/plugins/queue/smtp_forward.js +126 -104
  149. package/test/plugins/rcpt_to.host_list_base.js +85 -67
  150. package/test/plugins/rcpt_to.in_host_list.js +159 -112
  151. package/test/plugins/status.js +71 -64
  152. package/test/plugins/tls.js +37 -34
  153. package/test/plugins.js +97 -92
  154. package/test/rfc1869.js +19 -26
  155. package/test/server.js +293 -272
  156. package/test/smtp_client.js +180 -176
  157. package/test/tls_socket.js +62 -66
  158. package/test/transaction.js +159 -160
  159. package/tls_socket.js +331 -333
  160. package/transaction.js +129 -137
package/logger.js CHANGED
@@ -1,305 +1,287 @@
1
- 'use strict';
1
+ 'use strict'
2
2
  // Log class
3
3
 
4
- const util = require('node:util');
5
- const tty = require('node:tty');
4
+ const util = require('node:util')
5
+ const tty = require('node:tty')
6
6
 
7
- const config = require('haraka-config');
8
- const constants = require('haraka-constants');
7
+ const config = require('haraka-config')
8
+ const constants = require('haraka-constants')
9
9
 
10
- let plugins;
10
+ let plugins
11
11
 
12
- const regex = /(^$|[ ="\\])/;
13
- const escape_replace_regex = /["\\]/g;
12
+ const regex = /(^$|[ ="\\])/
13
+ const escape_replace_regex = /["\\]/g
14
14
 
15
- function stringify (obj) {
16
- let str = '';
17
- let key;
15
+ function stringify(obj) {
16
+ let str = ''
17
+ let key
18
18
  for (key in obj) {
19
- let v = obj[key];
19
+ let v = obj[key]
20
20
  if (v == null) {
21
- str += `${key}="" `;
22
- continue;
21
+ str += `${key}="" `
22
+ continue
23
23
  }
24
- v = v.toString();
24
+ v = v.toString()
25
25
  if (regex.test(v)) {
26
- str += `${key}="${v.replace(escape_replace_regex, '\\$&')}" `;
27
- }
28
- else {
29
- str += `${key}=${v} `;
26
+ str += `${key}="${v.replace(escape_replace_regex, '\\$&')}" `
27
+ } else {
28
+ str += `${key}=${v} `
30
29
  }
31
30
  }
32
- return str.trim();
31
+ return str.trim()
33
32
  }
34
33
 
35
- const logger = exports;
34
+ const logger = exports
36
35
 
37
36
  logger.levels = {
38
- DATA: 9,
37
+ DATA: 9,
39
38
  PROTOCOL: 8,
40
- DEBUG: 7,
41
- INFO: 6,
42
- NOTICE: 5,
43
- WARN: 4,
44
- ERROR: 3,
45
- CRIT: 2,
46
- ALERT: 1,
47
- EMERG: 0,
39
+ DEBUG: 7,
40
+ INFO: 6,
41
+ NOTICE: 5,
42
+ WARN: 4,
43
+ ERROR: 3,
44
+ CRIT: 2,
45
+ ALERT: 1,
46
+ EMERG: 0,
48
47
  }
49
48
  const level_names = Object.keys(logger.levels)
50
49
 
51
50
  for (const le in logger.levels) {
52
- logger.levels[`LOG${le}`] = logger.levels[le];
53
- logger[`LOG${le}`] = logger.levels[le];
51
+ logger.levels[`LOG${le}`] = logger.levels[le]
52
+ logger[`LOG${le}`] = logger.levels[le]
54
53
  }
55
54
 
56
55
  logger.formats = {
57
- DEFAULT: "DEFAULT",
58
- LOGFMT: "LOGFMT",
59
- JSON: "JSON",
56
+ DEFAULT: 'DEFAULT',
57
+ LOGFMT: 'LOGFMT',
58
+ JSON: 'JSON',
60
59
  }
61
60
 
62
- logger.loglevel = logger.levels.WARN;
63
- logger.format = logger.formats.DEFAULT;
64
- logger.timestamps = false;
65
- logger.deferred_logs = [];
66
- logger.name = 'logger'
61
+ logger.loglevel = logger.levels.WARN
62
+ logger.format = logger.formats.DEFAULT
63
+ logger.timestamps = false
64
+ logger.deferred_logs = []
65
+ logger.name = 'logger'
67
66
 
68
67
  logger.colors = {
69
- "DATA" : "green",
70
- "PROTOCOL" : "green",
71
- "DEBUG" : "grey",
72
- "INFO" : "cyan",
73
- "NOTICE" : "blue",
74
- "WARN" : "red",
75
- "ERROR" : "red",
76
- "CRIT" : "red",
77
- "ALERT" : "red",
78
- "EMERG" : "red",
68
+ DATA: 'green',
69
+ PROTOCOL: 'green',
70
+ DEBUG: 'grey',
71
+ INFO: 'cyan',
72
+ NOTICE: 'blue',
73
+ WARN: 'red',
74
+ ERROR: 'red',
75
+ CRIT: 'red',
76
+ ALERT: 'red',
77
+ EMERG: 'red',
79
78
  }
80
79
 
81
- const stdout_is_tty = tty.isatty(process.stdout.fd);
80
+ const stdout_is_tty = tty.isatty(process.stdout.fd)
82
81
 
83
82
  logger._init = function () {
84
- this.load_log_ini();
85
- this._init_loglevel();
86
- this._init_timestamps();
83
+ this.load_log_ini()
84
+ this._init_loglevel()
85
+ this._init_timestamps()
87
86
  }
88
87
 
89
88
  logger.load_log_ini = function () {
90
- this.cfg = config.get('log.ini', {
91
- booleans: [
92
- '+main.timestamps',
93
- ]
94
- },
95
- () => {
96
- this.load_log_ini();
97
- });
98
-
99
- this.set_loglevel(this.cfg.main.level);
100
- this.set_timestamps(this.cfg.main.timestamps);
101
- this.set_format(this.cfg.main.format);
89
+ this.cfg = config.get(
90
+ 'log.ini',
91
+ {
92
+ booleans: ['+main.timestamps'],
93
+ },
94
+ () => {
95
+ this.load_log_ini()
96
+ },
97
+ )
98
+
99
+ this.set_loglevel(this.cfg.main.level)
100
+ this.set_timestamps(this.cfg.main.timestamps)
101
+ this.set_format(this.cfg.main.format)
102
102
  }
103
103
 
104
104
  logger.colorize = (color, str) => {
105
- if (!util.inspect.colors[color]) { return str; } // unknown color
106
- return `\u001b[${util.inspect.colors[color][0]}m${str}\u001b[${util.inspect.colors[color][1]}m`;
105
+ if (!util.inspect.colors[color]) {
106
+ return str
107
+ } // unknown color
108
+ return `\u001b[${util.inspect.colors[color][0]}m${str}\u001b[${util.inspect.colors[color][1]}m`
107
109
  }
108
110
 
109
- logger.dump_logs = cb => {
111
+ logger.dump_logs = (cb) => {
110
112
  while (logger.deferred_logs.length > 0) {
111
- const log_item = logger.deferred_logs.shift();
112
- plugins.run_hooks('log', logger, log_item);
113
+ const log_item = logger.deferred_logs.shift()
114
+ plugins.run_hooks('log', logger, log_item)
113
115
  }
114
116
  // Run callback after flush
115
- if (cb) process.stdout.write('', cb);
116
- return true;
117
+ if (cb) process.stdout.write('', cb)
118
+ return true
117
119
  }
118
120
 
119
121
  logger.dump_and_exit = function (code) {
120
122
  this.dump_logs(() => {
121
- if (typeof code === 'function') return code();
122
- process.exit(code);
123
- });
123
+ if (typeof code === 'function') return code()
124
+ process.exit(code)
125
+ })
124
126
  }
125
127
 
126
128
  logger.log = (level, data, logobj) => {
127
129
  if (level === 'PROTOCOL') {
128
- data = data.replace(/\n/g, '\\n');
130
+ data = data.replace(/\n/g, '\\n')
129
131
  }
130
- data = data.replace(/\r/g, '\\r').replace(/\n$/, '');
132
+ data = data.replace(/\r/g, '\\r').replace(/\n$/, '')
131
133
 
132
- const item = { level, data, obj: logobj};
134
+ const item = { level, data, obj: logobj }
133
135
 
134
136
  // buffer until plugins are loaded
135
- const emptyPluginList = !plugins || Array.isArray(plugins.plugin_list) && !plugins.plugin_list.length;
137
+ const emptyPluginList = !plugins || (Array.isArray(plugins.plugin_list) && !plugins.plugin_list.length)
136
138
  if (emptyPluginList) {
137
- logger.deferred_logs.push(item);
138
- return true;
139
+ logger.deferred_logs.push(item)
140
+ return true
139
141
  }
140
142
 
141
143
  // process buffered logs
142
144
  while (logger.deferred_logs.length > 0) {
143
- const log_item = logger.deferred_logs.shift();
144
- plugins.run_hooks('log', logger, log_item);
145
+ const log_item = logger.deferred_logs.shift()
146
+ plugins.run_hooks('log', logger, log_item)
145
147
  }
146
148
 
147
- plugins.run_hooks('log', logger, item);
148
- return true;
149
+ plugins.run_hooks('log', logger, item)
150
+ return true
149
151
  }
150
152
 
151
153
  logger.log_respond = (retval, msg, data) => {
152
154
  // any other return code is irrelevant
153
- if (retval !== constants.cont) return false;
155
+ if (retval !== constants.cont) return false
154
156
 
155
- let timestamp_string = '';
156
- if (logger.timestamps) timestamp_string = `${new Date().toISOString()} `;
157
+ let timestamp_string = ''
158
+ if (logger.timestamps) timestamp_string = `${new Date().toISOString()} `
157
159
 
158
- const color = logger.colors[data.level];
160
+ const color = logger.colors[data.level]
159
161
  if (color && stdout_is_tty) {
160
- process.stdout.write(`${timestamp_string}${logger.colorize(color,data.data)}\n`);
161
- }
162
- else {
163
- process.stdout.write(`${timestamp_string}${data.data}\n`);
162
+ process.stdout.write(`${timestamp_string}${logger.colorize(color, data.data)}\n`)
163
+ } else {
164
+ process.stdout.write(`${timestamp_string}${data.data}\n`)
164
165
  }
165
166
 
166
- return true;
167
+ return true
167
168
  }
168
169
 
169
170
  logger.set_loglevel = function (level) {
170
- if (level === undefined || level === null) return;
171
+ if (level === undefined || level === null) return
171
172
 
172
- const loglevel_num = parseInt(level);
173
+ const loglevel_num = parseInt(level)
173
174
  if (typeof level === 'string') {
174
- this.log('INFO', `loglevel: ${level.toUpperCase()}`);
175
- logger.loglevel = logger.levels[level.toUpperCase()];
176
- }
177
- else {
178
- logger.loglevel = loglevel_num;
175
+ this.log('INFO', `loglevel: ${level.toUpperCase()}`)
176
+ logger.loglevel = logger.levels[level.toUpperCase()]
177
+ } else {
178
+ logger.loglevel = loglevel_num
179
179
  }
180
180
 
181
181
  if (!Number.isInteger(logger.loglevel)) {
182
- this.log('WARN', `invalid loglevel: ${level} defaulting to LOGWARN`);
183
- logger.loglevel = logger.levels.WARN;
182
+ this.log('WARN', `invalid loglevel: ${level} defaulting to LOGWARN`)
183
+ logger.loglevel = logger.levels.WARN
184
184
  }
185
185
  }
186
186
 
187
187
  logger.set_format = function (format) {
188
188
  if (format) {
189
- logger.format = logger.formats[format.toUpperCase()];
190
- this.log('INFO', `log format: ${format.toUpperCase()}`);
191
- }
192
- else {
193
- logger.format = null;
189
+ logger.format = logger.formats[format.toUpperCase()]
190
+ this.log('INFO', `log format: ${format.toUpperCase()}`)
191
+ } else {
192
+ logger.format = null
194
193
  }
195
194
  if (!logger.format) {
196
- this.log('WARN', `invalid log format: ${format} defaulting to DEFAULT`);
197
- logger.format = logger.formats.DEFAULT;
195
+ this.log('WARN', `invalid log format: ${format} defaulting to DEFAULT`)
196
+ logger.format = logger.formats.DEFAULT
198
197
  }
199
198
  }
200
199
 
201
200
  logger._init_loglevel = function () {
202
-
203
201
  const _loglevel = config.get('loglevel', 'value', () => {
204
- this._init_loglevel();
205
- });
202
+ this._init_loglevel()
203
+ })
206
204
 
207
- this.set_loglevel(_loglevel);
205
+ this.set_loglevel(_loglevel)
208
206
  }
209
207
 
210
- logger.would_log = level => {
211
- if (logger.loglevel < level) return false;
212
- return true;
208
+ logger.would_log = (level) => {
209
+ if (logger.loglevel < level) return false
210
+ return true
213
211
  }
214
212
 
215
- logger.set_timestamps = value => {
216
- logger.timestamps = !!value;
213
+ logger.set_timestamps = (value) => {
214
+ logger.timestamps = !!value
217
215
  }
218
216
 
219
217
  logger._init_timestamps = function () {
220
-
221
218
  const _timestamps = config.get('log_timestamps', 'value', () => {
222
- this._init_timestamps();
223
- });
219
+ this._init_timestamps()
220
+ })
224
221
 
225
222
  // If we've already been toggled to true by the cfg, we should respect this.
226
- this.set_timestamps(logger.timestamps || _timestamps);
223
+ this.set_timestamps(logger.timestamps || _timestamps)
227
224
  }
228
225
 
229
- logger._init();
230
-
231
- logger.log_if_level = (level, key, origin) => function () {
232
- if (logger.loglevel < logger[key]) return;
226
+ logger._init()
233
227
 
234
- let logobj = {
235
- level,
236
- uuid: '-',
237
- origin: (origin || 'core'),
238
- message: ''
239
- };
228
+ logger.log_if_level = (level, key, origin) =>
229
+ function () {
230
+ if (logger.loglevel < logger[key]) return
240
231
 
241
- for (const data of arguments) {
242
- if (typeof data !== 'object') {
243
- logobj.message += (data);
244
- continue;
232
+ let logobj = {
233
+ level,
234
+ uuid: '-',
235
+ origin: origin || 'core',
236
+ message: '',
245
237
  }
246
- if (!data) continue;
247
238
 
248
- // if the object is a connection, add the connection id
249
- if (data.constructor?.name === 'Connection') {
250
- logobj.uuid = data.uuid;
251
- if (data.tran_count > 0) logobj.uuid += `.${data.tran_count}`;
252
- }
253
- else if (data instanceof plugins.Plugin) {
254
- logobj.origin = data.name;
255
- }
256
- else if (Object.hasOwn(data, 'name')) { // outbound
257
- logobj.origin = data.name;
258
- if (Object.hasOwn(data, 'uuid')) logobj.uuid = data.uuid;
259
- if (data.todo?.uuid) logobj.uuid = data.todo.uuid; // outbound/hmail
260
- }
261
- else if (
262
- logger.format === logger.formats.LOGFMT && data.constructor === Object) {
263
- logobj = Object.assign(logobj, data);
264
- }
265
- else if (
266
- logger.format === logger.formats.JSON && data.constructor === Object) {
267
- logobj = Object.assign(logobj, data);
268
- }
269
- else if (Object.hasOwn(data, 'uuid')) { // outbound/client_pool
270
- logobj.uuid = data.uuid;
271
- }
272
- else if (data.constructor === Object) {
273
- if (!logobj.message.endsWith(' ')) logobj.message += ' ';
274
- logobj.message += (stringify(data));
275
- }
276
- else {
277
- logobj.message += (util.inspect(data));
239
+ for (const data of arguments) {
240
+ if (typeof data !== 'object') {
241
+ logobj.message += data
242
+ continue
243
+ }
244
+ if (!data) continue
245
+
246
+ // if the object is a connection, add the connection id
247
+ if (data.constructor?.name === 'Connection') {
248
+ logobj.uuid = data.uuid
249
+ if (data.tran_count > 0) logobj.uuid += `.${data.tran_count}`
250
+ } else if (data instanceof plugins.Plugin) {
251
+ logobj.origin = data.name
252
+ } else if (Object.hasOwn(data, 'name')) {
253
+ // outbound
254
+ logobj.origin = data.name
255
+ if (Object.hasOwn(data, 'uuid')) logobj.uuid = data.uuid
256
+ if (data.todo?.uuid) logobj.uuid = data.todo.uuid // outbound/hmail
257
+ } else if (logger.format === logger.formats.LOGFMT && data.constructor === Object) {
258
+ logobj = Object.assign(logobj, data)
259
+ } else if (logger.format === logger.formats.JSON && data.constructor === Object) {
260
+ logobj = Object.assign(logobj, data)
261
+ } else if (Object.hasOwn(data, 'uuid')) {
262
+ // outbound/client_pool
263
+ logobj.uuid = data.uuid
264
+ } else if (data.constructor === Object) {
265
+ if (!logobj.message.endsWith(' ')) logobj.message += ' '
266
+ logobj.message += stringify(data)
267
+ } else {
268
+ logobj.message += util.inspect(data)
269
+ }
278
270
  }
279
- }
280
271
 
281
- switch (logger.format) {
282
- case logger.formats.LOGFMT:
283
- logger.log(
284
- level,
285
- stringify(logobj)
286
- );
287
- break
288
- case logger.formats.JSON:
289
- logger.log(
290
- level,
291
- JSON.stringify(logobj)
292
- );
293
- break
294
- case logger.formats.DEFAULT:
295
- default:
296
- logger.log(
297
- level,
298
- `[${logobj.level}] [${logobj.uuid}] [${logobj.origin}] ${logobj.message}`
299
- );
272
+ switch (logger.format) {
273
+ case logger.formats.LOGFMT:
274
+ logger.log(level, stringify(logobj))
275
+ break
276
+ case logger.formats.JSON:
277
+ logger.log(level, JSON.stringify(logobj))
278
+ break
279
+ case logger.formats.DEFAULT:
280
+ default:
281
+ logger.log(level, `[${logobj.level}] [${logobj.uuid}] [${logobj.origin}] ${logobj.message}`)
282
+ }
283
+ return true
300
284
  }
301
- return true;
302
- }
303
285
 
304
286
  logger.add_log_methods = (object, logName) => {
305
287
  if (!object) return
@@ -307,15 +289,14 @@ logger.add_log_methods = (object, logName) => {
307
289
  if (typeof object === 'function') {
308
290
  // add logging methods to class prototypes (Connection, Plugin, etc.)
309
291
 
310
- for (const level of level_names.map(l => l.toLowerCase())) {
292
+ for (const level of level_names.map((l) => l.toLowerCase())) {
311
293
  object.prototype[`log${level}`] = (function (level) {
312
294
  return function () {
313
- logger[level].apply(logger, [ this, ...arguments ]);
314
- };
315
- })(`log${level}`);
295
+ logger[level].apply(logger, [this, ...arguments])
296
+ }
297
+ })(`log${level}`)
316
298
  }
317
- }
318
- else if (typeof object === 'object') {
299
+ } else if (typeof object === 'object') {
319
300
  // add logging methods to objects
320
301
 
321
302
  for (const level of level_names) {
@@ -328,14 +309,14 @@ logger.add_log_methods = (object, logName) => {
328
309
  }
329
310
 
330
311
  for (const fnName of fnNames) {
331
- if (Object.hasOwn(object, fnName)) continue; // already added
332
- object[fnName] = logger.log_if_level(level, `LOG${level}`, logName);
312
+ if (Object.hasOwn(object, fnName)) continue // already added
313
+ object[fnName] = logger.log_if_level(level, `LOG${level}`, logName)
333
314
  }
334
315
  }
335
316
  }
336
317
  }
337
318
 
338
- logger.add_log_methods(logger);
319
+ logger.add_log_methods(logger)
339
320
 
340
321
  // load these down here so it sees all the logger methods compiled above
341
- plugins = require('./plugins');
322
+ plugins = require('./plugins')
@@ -1,52 +1,59 @@
1
- 'use strict';
1
+ 'use strict'
2
2
 
3
- const utils = require('haraka-utils');
3
+ const util = require('node:util')
4
+
5
+ const utils = require('haraka-utils')
4
6
  const net_utils = require('haraka-net-utils')
5
7
 
6
- const tls_socket = require('../tls_socket');
7
- const logger = require('../logger');
8
- const obc = require('./config');
8
+ const tls_socket = require('../tls_socket')
9
+ const logger = require('../logger')
10
+ const obc = require('./config')
9
11
 
10
12
  exports.name = 'outbound'
11
13
 
12
14
  // Get a socket for the given attributes.
13
15
  exports.get_client = function (mx, callback) {
14
- const socketArgs = mx.path ? { path: mx.path } : { port: mx.port, host: mx.exchange, localAddress: mx.bind };
16
+ const socketArgs = mx.path ? { path: mx.path } : { port: mx.port, host: mx.exchange, localAddress: mx.bind }
15
17
 
16
- const socket = tls_socket.connect(socketArgs);
17
- net_utils.add_line_processor(socket);
18
+ const socket = tls_socket.connect(socketArgs)
19
+ net_utils.add_line_processor(socket)
18
20
 
19
- socket.name = `outbound::${JSON.stringify(socketArgs)}`;
20
- socket.__uuid = utils.uuid();
21
- socket.setTimeout(obc.cfg.connect_timeout * 1000);
21
+ socket.name = `outbound::${JSON.stringify(socketArgs)}`
22
+ socket.__uuid = utils.uuid()
23
+ socket.setTimeout(obc.cfg.connect_timeout * 1000)
22
24
 
23
- logger.debug(exports, `created ${socket.name}`, { uuid: socket.__uuid });
25
+ logger.debug(exports, `created ${socket.name}`, { uuid: socket.__uuid })
24
26
 
25
27
  socket.once('connect', () => {
26
- socket.removeAllListeners('error'); // these get added after callback
27
- socket.removeAllListeners('timeout');
28
- callback(null, socket);
28
+ socket.removeAllListeners('error') // these get added after callback
29
+ socket.removeAllListeners('timeout')
30
+ callback(null, socket)
29
31
  })
30
32
 
31
- socket.once('error', err => {
32
- socket.end();
33
- socket.removeAllListeners();
34
- socket.destroy();
35
- callback(err.message, null);
33
+ socket.once('error', (err) => {
34
+ socket.end()
35
+ socket.removeAllListeners()
36
+ socket.destroy()
37
+ const errMsg = err.message
38
+ ? err.message
39
+ : err instanceof AggregateError
40
+ ? err.map((e) => e.message).join(', ')
41
+ : util.inspect(err, { depth: 3 })
42
+ callback(errMsg, null)
36
43
  })
37
44
 
38
45
  socket.once('timeout', () => {
39
- socket.end();
40
- socket.removeAllListeners();
41
- socket.destroy();
42
- callback(`connection timed out to ${socket.name}`, null);
46
+ socket.end()
47
+ socket.removeAllListeners()
48
+ socket.destroy()
49
+ callback(`connection timed out to ${socket.name}`, null)
43
50
  })
44
51
  }
45
52
 
46
53
  exports.release_client = (socket, mx) => {
47
54
  let logMsg = `release_client: ${socket.name}`
48
55
  if (mx.bind) logMsg += ` from ${mx.bind}`
49
- logger.debug(exports, logMsg);
50
- socket.removeAllListeners();
51
- socket.destroy();
56
+ logger.debug(exports, logMsg)
57
+ socket.removeAllListeners()
58
+ socket.destroy()
52
59
  }