Haraka 2.8.28 → 3.0.1

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 (135) hide show
  1. package/.eslintrc.yaml +2 -10
  2. package/Changes.md +84 -2
  3. package/Dockerfile +1 -1
  4. package/Plugins.md +9 -4
  5. package/README.md +2 -6
  6. package/bin/haraka +5 -4
  7. package/config/outbound.ini +0 -7
  8. package/config/plugins +1 -1
  9. package/config/smtp.ini +1 -1
  10. package/config/smtp_forward.ini +2 -8
  11. package/config/smtp_proxy.ini +0 -6
  12. package/connection.js +178 -204
  13. package/coverage/lcov.info +13863 -0
  14. package/coverage/tmp/coverage-42958-1658373250585-0.json +1 -0
  15. package/coverage/tmp/coverage-42961-1658373250529-0.json +1 -0
  16. package/dkim.js +66 -73
  17. package/docs/Body.md +1 -22
  18. package/docs/CoreConfig.md +2 -2
  19. package/docs/Header.md +1 -47
  20. package/docs/Outbound.md +8 -36
  21. package/endpoint.js +1 -1
  22. package/haraka.js +1 -1
  23. package/host_pool.js +8 -12
  24. package/logger.js +25 -32
  25. package/outbound/client_pool.js +11 -153
  26. package/outbound/config.js +5 -11
  27. package/outbound/hmail.js +109 -143
  28. package/outbound/index.js +13 -25
  29. package/outbound/mx_lookup.js +10 -7
  30. package/outbound/queue.js +8 -12
  31. package/outbound/timer_queue.js +2 -4
  32. package/outbound/tls.js +17 -18
  33. package/outbound/todo.js +1 -0
  34. package/package.json +57 -55
  35. package/plugins/auth/auth_base.js +39 -63
  36. package/plugins/auth/auth_bridge.js +3 -4
  37. package/plugins/auth/auth_proxy.js +16 -16
  38. package/plugins/auth/auth_vpopmaild.js +30 -37
  39. package/plugins/auth/flat_file.js +9 -13
  40. package/plugins/avg.js +9 -11
  41. package/plugins/backscatterer.js +1 -1
  42. package/plugins/block_me.js +2 -6
  43. package/plugins/bounce.js +106 -124
  44. package/plugins/clamd.js +59 -63
  45. package/plugins/data.signatures.js +6 -6
  46. package/plugins/data.uribl.js +1 -415
  47. package/plugins/delay_deny.js +19 -20
  48. package/plugins/dkim_sign.js +56 -62
  49. package/plugins/dkim_verify.js +9 -8
  50. package/plugins/dns_list_base.js +43 -42
  51. package/plugins/dnsbl.js +41 -46
  52. package/plugins/dnswl.js +23 -26
  53. package/plugins/early_talker.js +24 -28
  54. package/plugins/esets.js +8 -11
  55. package/plugins/greylist.js +161 -190
  56. package/plugins/helo.checks.js +175 -197
  57. package/plugins/mail_from.is_resolvable.js +38 -38
  58. package/plugins/messagesniffer.js +33 -40
  59. package/plugins/prevent_credential_leaks.js +7 -5
  60. package/plugins/process_title.js +16 -17
  61. package/plugins/queue/deliver.js +2 -2
  62. package/plugins/queue/lmtp.js +5 -6
  63. package/plugins/queue/qmail-queue.js +11 -13
  64. package/plugins/queue/quarantine.js +25 -34
  65. package/plugins/queue/rabbitmq.js +3 -2
  66. package/plugins/queue/rabbitmq_amqplib.js +9 -9
  67. package/plugins/queue/smtp_bridge.js +5 -4
  68. package/plugins/queue/smtp_forward.js +81 -89
  69. package/plugins/queue/smtp_proxy.js +21 -22
  70. package/plugins/queue/test.js +2 -1
  71. package/plugins/rcpt_to.host_list_base.js +20 -30
  72. package/plugins/rcpt_to.in_host_list.js +12 -14
  73. package/plugins/rcpt_to.max_count.js +7 -5
  74. package/plugins/record_envelope_addresses.js +4 -6
  75. package/plugins/relay.js +64 -74
  76. package/plugins/reseed_rng.js +1 -2
  77. package/plugins/spamassassin.js +56 -68
  78. package/plugins/status.js +2 -3
  79. package/plugins/tarpit.js +8 -11
  80. package/plugins/tls.js +14 -17
  81. package/plugins/toobusy.js +6 -8
  82. package/plugins/xclient.js +14 -25
  83. package/plugins.js +24 -29
  84. package/rfc1869.js +2 -2
  85. package/server.js +3 -13
  86. package/smtp_client.js +138 -215
  87. package/tests/config/smtp_forward.ini +0 -6
  88. package/tests/fixtures/line_socket.js +1 -1
  89. package/tests/fixtures/util_hmailitem.js +5 -7
  90. package/tests/fixtures/vm_harness.js +2 -2
  91. package/tests/host_pool.js +13 -14
  92. package/tests/installation/plugins/inherits.js +1 -2
  93. package/tests/logger.js +2 -2
  94. package/tests/plugins/bounce.js +6 -8
  95. package/tests/plugins/dkim_signer.js +7 -7
  96. package/tests/plugins/dns_list_base.js +7 -7
  97. package/tests/plugins/helo.checks.js +1 -1
  98. package/tests/plugins/mail_from.is_resolvable.js +10 -54
  99. package/tests/plugins/queue/smtp_forward.js +11 -11
  100. package/tests/plugins/rcpt_to.host_list_base.js +1 -1
  101. package/tests/plugins/rcpt_to.in_host_list.js +1 -1
  102. package/tests/plugins/spamassassin.js +1 -1
  103. package/tests/queue/multibyte +0 -0
  104. package/tests/queue/plain +0 -0
  105. package/tests/rfc1869.js +4 -1
  106. package/tests/server.js +15 -9
  107. package/tests/smtp_client/auth.js +4 -14
  108. package/tests/smtp_client/basic.js +5 -15
  109. package/tests/smtp_client.js +7 -3
  110. package/tests/transaction.js +72 -19
  111. package/tls_socket.js +75 -85
  112. package/transaction.js +7 -9
  113. package/attachment_stream.js +0 -118
  114. package/bin/spf +0 -48
  115. package/chunkemitter.js +0 -75
  116. package/config/data.uribl.excludes +0 -202
  117. package/config/data.uribl.ini +0 -37
  118. package/config/spf.ini +0 -1
  119. package/docs/plugins/attachment.md +0 -92
  120. package/docs/plugins/data.uribl.md +0 -120
  121. package/docs/plugins/spf.md +0 -142
  122. package/mailbody.js +0 -502
  123. package/mailheader.js +0 -304
  124. package/messagestream.js +0 -441
  125. package/plugins/aliases.js +0 -120
  126. package/plugins/attachment.js +0 -503
  127. package/plugins/connect.p0f.js +0 -5
  128. package/plugins/spf.js +0 -327
  129. package/spf.js +0 -689
  130. package/tests/mailbody.js +0 -348
  131. package/tests/mailheader.js +0 -138
  132. package/tests/messagestream.js +0 -34
  133. package/tests/plugins/aliases.js +0 -376
  134. package/tests/plugins/spf.js +0 -251
  135. package/tests/spf.js +0 -96
package/smtp_client.js CHANGED
@@ -11,7 +11,6 @@
11
11
  const events = require('events');
12
12
 
13
13
  // npm deps
14
- const generic_pool = require('generic-pool');
15
14
  const ipaddr = require('ipaddr.js');
16
15
  const net_utils = require('haraka-net-utils');
17
16
  const utils = require('haraka-utils');
@@ -21,7 +20,7 @@ const line_socket = require('./line_socket');
21
20
  const logger = require('./logger');
22
21
  const HostPool = require('./host_pool');
23
22
 
24
- const smtp_regexp = /^([0-9]{3})([ -])(.*)/;
23
+ const smtp_regexp = /^(\d{3})([ -])(.*)/;
25
24
  const STATE = {
26
25
  IDLE: 1,
27
26
  ACTIVE: 2,
@@ -30,11 +29,11 @@ const STATE = {
30
29
  }
31
30
 
32
31
  class SMTPClient extends events.EventEmitter {
33
- constructor (port, host, connect_timeout, idle_timeout, socket) {
32
+ constructor (opts = {}) {
34
33
  super();
35
34
  this.uuid = utils.uuid();
36
- this.connect_timeout = parseInt(connect_timeout) || 30;
37
- this.socket = socket || line_socket.connect(port, host);
35
+ this.connect_timeout = parseInt(opts.connect_timeout) || 30;
36
+ this.socket = opts.socket || line_socket.connect(opts.port, opts.host);
38
37
  this.socket.setTimeout(this.connect_timeout * 1000);
39
38
  this.socket.setKeepAlive(true);
40
39
  this.state = STATE.IDLE;
@@ -44,8 +43,8 @@ class SMTPClient extends events.EventEmitter {
44
43
  this.authenticating= false;
45
44
  this.authenticated = false;
46
45
  this.auth_capabilities = [];
47
- this.host = host;
48
- this.port = port;
46
+ this.host = opts.host;
47
+ this.port = opts.port;
49
48
  this.smtputf8 = false;
50
49
 
51
50
  const client = this;
@@ -68,7 +67,10 @@ class SMTPClient extends events.EventEmitter {
68
67
 
69
68
  if (client.command === 'auth' || client.authenticating) {
70
69
  logger.loginfo(`SERVER RESPONSE, CLIENT ${client.command}, authenticating=${client.authenticating},code=${code},cont=${cont},msg=${msg}`);
71
- if (/^3/.test(code) && msg === 'VXNlcm5hbWU6') {
70
+ if (/^3/.test(code) && (
71
+ msg === 'VXNlcm5hbWU6' ||
72
+ msg === 'dXNlcm5hbWU6' // Workaround ill-mannered SMTP servers (namely smtp.163.com)
73
+ )) {
72
74
  client.emit('auth_username');
73
75
  return;
74
76
  }
@@ -150,7 +152,7 @@ class SMTPClient extends events.EventEmitter {
150
152
 
151
153
  client.socket.on('connect', () => {
152
154
  // Replace connection timeout with idle timeout
153
- client.socket.setTimeout((idle_timeout || 300) * 1000);
155
+ client.socket.setTimeout((opts.idle_timeout || 300) * 1000);
154
156
  if (!client.socket.remoteAddress) {
155
157
  // "Value may be undefined if the socket is destroyed"
156
158
  logger.logdebug('socket.remoteAddress undefined');
@@ -161,28 +163,28 @@ class SMTPClient extends events.EventEmitter {
161
163
 
162
164
  function closed (msg) {
163
165
  return error => {
164
- if (!error) {
165
- error = '';
166
- }
167
- // msg is e.g. "errored" or "timed out"
166
+ if (!error) error = '';
167
+
168
168
  // error is e.g. "Error: connect ECONNREFUSED"
169
169
  const errMsg = `${client.uuid}: [${client.host}:${client.port}] SMTP connection ${msg} ${error}`;
170
- if (client.state === STATE.ACTIVE) {
171
- client.emit('error', errMsg);
172
- }
170
+
171
+ /* eslint-disable no-fallthrough */
173
172
  switch (client.state) {
174
173
  case STATE.ACTIVE:
174
+ client.emit('error', errMsg);
175
175
  case STATE.IDLE:
176
176
  case STATE.RELEASED:
177
177
  client.destroy();
178
178
  break;
179
+ case STATE.DESTROYED:
180
+ if (msg === 'errored' || msg === 'timed out') {
181
+ client.emit('connection-error', errMsg);
182
+ }
183
+ break
179
184
  default:
180
185
  }
181
- if ((msg === 'errored' || msg === 'timed out') && client.state === STATE.DESTROYED) {
182
- client.emit('connection-error', errMsg);
183
- } // don't return, continue (original behavior)
184
186
 
185
- logger.logdebug(`[smtp_client_pool] ${errMsg} (state=${client.state})`);
187
+ logger.logdebug(`[smtp_client] ${errMsg} (state=${client.state})`);
186
188
  }
187
189
  }
188
190
 
@@ -217,17 +219,8 @@ class SMTPClient extends events.EventEmitter {
217
219
  }
218
220
 
219
221
  release () {
220
- if (!this.connected || this.command === 'data' || this.command === 'mailbody') {
221
- // Destroy here, we can't reuse a connection that was mid-data.
222
- this.destroy();
223
- return;
224
- }
225
-
226
- logger.logdebug(`[smtp_client_pool] ${this.uuid} resetting, state=${this.state}`);
227
- if (this.state === STATE.DESTROYED) {
228
- return;
229
- }
230
- this.state = STATE.RELEASED;
222
+ if (this.state === STATE.DESTROYED) return;
223
+ logger.logdebug(`[smtp_client] ${this.uuid} releasing, state=${this.state}`);
231
224
 
232
225
  [
233
226
  'auth', 'bad_code', 'capabilities', 'client_protocol', 'connection-error',
@@ -237,47 +230,33 @@ class SMTPClient extends events.EventEmitter {
237
230
  this.removeAllListeners(l);
238
231
  })
239
232
 
240
- this.on('bad_code', (code, msg) => {
241
- this.destroy();
242
- });
243
-
244
- this.on('rset', () => {
245
- logger.logdebug(`[smtp_client_pool] ${this.uuid} releasing, state=${this.state}`);
246
- if (this.state === STATE.DESTROYED) return;
247
-
248
- this.state = STATE.IDLE;
249
- this.removeAllListeners('rset');
250
- this.removeAllListeners('bad_code');
251
- this.pool.release(this);
252
- });
253
-
254
- this.send_command('RSET');
233
+ if (this.connected) this.send_command('QUIT');
234
+ this.destroy()
255
235
  }
256
236
 
257
237
  destroy () {
258
- if (this.state !== STATE.DESTROYED) {
259
- this.pool.destroy(this);
260
- }
238
+ if (this.state === STATE.DESTROYED) return
239
+ this.state = STATE.DESTROYED;
240
+ this.socket.destroy();
261
241
  }
262
242
 
263
243
  upgrade (tls_options) {
264
- const this_logger = logger;
265
244
 
266
245
  this.socket.upgrade(tls_options, (verified, verifyError, cert, cipher) => {
267
- this_logger.loginfo(`secured:${
246
+ logger.loginfo(`secured:${
247
+
268
248
  (cipher) ? ` cipher=${cipher.name} version=${cipher.version}` : ''
269
249
  } verified=${verified}${
270
250
  (verifyError) ? ` error="${verifyError}"` : ''
271
- }${(cert && cert.subject) ? ` cn="${cert.subject.CN}" organization="${cert.subject.O}"` : ''
272
- }${(cert && cert.issuer) ? ` issuer="${cert.issuer.O}"` : ''
273
- }${(cert && cert.valid_to) ? ` expires="${cert.valid_to}"` : ''
274
- }${(cert && cert.fingerprint) ? ` fingerprint=${cert.fingerprint}` : ''}`);
251
+ }${(cert?.subject) ? ` cn="${cert.subject.CN}" organization="${cert.subject.O}"` : ''
252
+ }${(cert?.issuer) ? ` issuer="${cert.issuer.O}"` : ''
253
+ }${(cert?.valid_to) ? ` expires="${cert.valid_to}"` : ''
254
+ }${(cert?.fingerprint) ? ` fingerprint=${cert.fingerprint}` : ''}`);
275
255
  });
276
256
  }
277
257
 
278
-
279
258
  is_dead_sender (plugin, connection) {
280
- if (connection.transaction) return false;
259
+ if (connection?.transaction) return false;
281
260
 
282
261
  // This likely means the sender went away on us, cleanup.
283
262
  connection.logwarn(plugin, "transaction went away, releasing smtp_client");
@@ -288,64 +267,14 @@ class SMTPClient extends events.EventEmitter {
288
267
 
289
268
  exports.smtp_client = SMTPClient;
290
269
 
291
- // Separate pools are kept for each set of server attributes.
292
- exports.get_pool = (server, port, host, cfg) => {
293
- port = port || 25;
294
- host = host || 'localhost';
295
- if (cfg === undefined) cfg = {};
296
- const connect_timeout = cfg.connect_timeout || 30;
297
- const pool_timeout = cfg.pool_timeout || cfg.timeout || 300;
298
- const auth_user = cfg.auth_user || 'no_user';
299
- const name = `${port}:${host}:${pool_timeout}:${auth_user}`;
300
- if (!server.notes.pool) server.notes.pool = {};
301
- if (server.notes.pool[name]) return server.notes.pool[name];
302
-
303
- const pool = generic_pool.Pool({
304
- name,
305
- create: callback => {
306
- const smtp_client = new SMTPClient(port, host, connect_timeout, pool_timeout);
307
- logger.logdebug(`[smtp_client_pool] uuid=${smtp_client.uuid} host=${host}` +
308
- ` port=${port} pool_timeout=${pool_timeout} created`);
309
- callback(null, smtp_client);
310
- },
311
- destroy: smtp_client => {
312
- logger.logdebug(`[smtp_client_pool] ${smtp_client.uuid} destroyed, state={smtp_client.state}`);
313
- smtp_client.state = STATE.DESTROYED;
314
- smtp_client.socket.destroy();
315
- // Remove pool object from server notes once empty
316
- const size = pool.getPoolSize();
317
- if (size === 0) {
318
- delete server.notes.pool[name];
319
- }
320
- },
321
- max: cfg.max_connections || 1000,
322
- idleTimeoutMillis: (pool_timeout - 1) * 1000,
323
- log: (str, level) => {
324
- level = (level === 'verbose') ? 'debug' : level;
325
- logger[`log${level}`](`[smtp_client_pool] [${name}] ${str}`);
326
- }
327
- });
328
-
329
- const acquire = pool.acquire;
330
- pool.acquire = (callback, priority) => {
331
- function callback_wrapper (err, smtp_client) {
332
- smtp_client.pool = pool;
333
- smtp_client.state = STATE.ACTIVE;
334
- callback(err, smtp_client);
335
- }
336
- acquire.call(pool, callback_wrapper, priority);
337
- };
338
- server.notes.pool[name] = pool;
339
- return pool;
340
- }
341
-
342
270
  // Get a smtp_client for the given attributes.
343
- exports.get_client = (server, callback, port, host, cfg) => {
344
- const pool = exports.get_pool(server, port, host, cfg);
345
- pool.acquire(callback);
271
+ // used only in testing
272
+ exports.get_client = (server, callback, opts = {}) => {
273
+ const smtp_client = new SMTPClient(opts)
274
+ logger.logdebug(`[smtp_client] uuid=${smtp_client.uuid} host=${opts.host} port=${opts.port} created`)
275
+ callback(smtp_client)
346
276
  }
347
277
 
348
-
349
278
  exports.onCapabilitiesOutbound = (smtp_client, secured, connection, config, on_secured) => {
350
279
  for (const line in smtp_client.response) {
351
280
  if (/^XCLIENT/.test(smtp_client.response[line])) {
@@ -383,8 +312,8 @@ exports.onCapabilitiesOutbound = (smtp_client, secured, connection, config, on_s
383
312
  if (auth_matches) {
384
313
  smtp_client.auth_capabilities = [];
385
314
  auth_matches = auth_matches[1].split(' ');
386
- for (let i = 0; i < auth_matches.length; i++) {
387
- smtp_client.auth_capabilities.push(auth_matches[i].toLowerCase());
315
+ for (const authMatch of auth_matches) {
316
+ smtp_client.auth_capabilities.push(authMatch.toLowerCase());
388
317
  }
389
318
  }
390
319
  }
@@ -406,122 +335,119 @@ exports.get_client_plugin = (plugin, connection, c, callback) => {
406
335
  }
407
336
 
408
337
  const hostport = get_hostport(connection, connection.server, c);
338
+ const smtp_client = new SMTPClient(hostport)
339
+ logger.loginfo(`[smtp_client] uuid=${smtp_client.uuid} host=${hostport.host} port=${hostport.port} created`);
409
340
 
410
- const pool = exports.get_pool(connection.server, hostport.port, hostport.host, c);
341
+ connection.logdebug(plugin, `Got smtp_client: ${smtp_client.uuid}`);
411
342
 
412
- pool.acquire((err, smtp_client) => {
413
- connection.logdebug(plugin, `Got smtp_client: ${smtp_client.uuid}`);
343
+ let secured = false;
414
344
 
415
- let secured = false;
345
+ smtp_client.load_tls_config(plugin.tls_options);
416
346
 
417
- smtp_client.load_tls_config(plugin.tls_options);
418
-
419
- smtp_client.call_next = function (retval, msg) {
420
- if (this.next) {
421
- const next = this.next;
422
- delete this.next;
423
- next(retval, msg);
424
- }
347
+ smtp_client.call_next = function (retval, msg) {
348
+ if (this.next) {
349
+ const { next } = this;
350
+ delete this.next;
351
+ next(retval, msg);
425
352
  }
353
+ }
426
354
 
427
- smtp_client.on('client_protocol', (line) => {
428
- connection.logprotocol(plugin, `C: ${line}`);
429
- })
355
+ smtp_client.on('client_protocol', (line) => {
356
+ connection.logprotocol(plugin, `C: ${line}`);
357
+ })
430
358
 
431
- smtp_client.on('server_protocol', (line) => {
432
- connection.logprotocol(plugin, `S: ${line}`);
433
- })
359
+ smtp_client.on('server_protocol', (line) => {
360
+ connection.logprotocol(plugin, `S: ${line}`);
361
+ })
434
362
 
435
- function helo (command) {
436
- if (smtp_client.xclient) {
437
- smtp_client.send_command(command, connection.hello.host);
438
- }
439
- else {
440
- smtp_client.send_command(command, connection.local.host);
441
- }
363
+ function helo (command) {
364
+ if (smtp_client.xclient) {
365
+ smtp_client.send_command(command, connection.hello.host);
442
366
  }
443
- smtp_client.on('greeting', helo);
444
- smtp_client.on('xclient', helo);
445
-
446
- function on_secured () {
447
- secured = true;
448
- smtp_client.secured = true;
449
- smtp_client.emit('greeting', 'EHLO');
367
+ else {
368
+ smtp_client.send_command(command, connection.local.host);
450
369
  }
370
+ }
371
+ smtp_client.on('greeting', helo);
372
+ smtp_client.on('xclient', helo);
373
+
374
+ function on_secured () {
375
+ if (secured) return;
376
+ secured = true;
377
+ smtp_client.secured = true;
378
+ smtp_client.emit('greeting', 'EHLO');
379
+ }
451
380
 
452
- smtp_client.on('capabilities', () => {
453
- exports.onCapabilitiesOutbound(smtp_client, secured, connection, c, on_secured);
454
- });
381
+ smtp_client.on('capabilities', () => {
382
+ exports.onCapabilitiesOutbound(smtp_client, secured, connection, c, on_secured);
383
+ });
455
384
 
456
- smtp_client.on('helo', () => {
457
- if (!c.auth || smtp_client.authenticated) {
458
- if (smtp_client.is_dead_sender(plugin, connection)) {
459
- return;
460
- }
461
- smtp_client.send_command('MAIL', `FROM:${connection.transaction.mail_from.format(!smtp_client.smtp_utf8)}`);
462
- return;
463
- }
385
+ smtp_client.on('helo', () => {
386
+ if (!c.auth || smtp_client.authenticated) {
387
+ if (smtp_client.is_dead_sender(plugin, connection)) return;
464
388
 
465
- if (c.auth.type === null || typeof (c.auth.type) === 'undefined') return; // Ignore blank
466
- const auth_type = c.auth.type.toLowerCase();
467
- if (!smtp_client.auth_capabilities.includes(auth_type)) {
468
- throw new Error(`Auth type "${auth_type}" not supported by server (supports: ${smtp_client.auth_capabilities.join(',')})`);
469
- }
470
- switch (auth_type) {
471
- case 'plain':
472
- if (!c.auth.user || !c.auth.pass) {
473
- throw new Error("Must include auth.user and auth.pass for PLAIN auth.");
474
- }
475
- logger.logdebug(`[smtp_client_pool] uuid=${smtp_client.uuid} authenticating as "${c.auth.user}"`);
476
- smtp_client.send_command('AUTH',
477
- `PLAIN ${utils.base64(`${c.auth.user}\0${c.auth.user}\0${c.auth.pass}`)}`);
478
- break;
479
- case 'cram-md5':
480
- throw new Error("Not implemented");
481
- default:
482
- throw new Error(`Unknown AUTH type: ${auth_type}`);
483
- }
484
- });
389
+ smtp_client.send_command('MAIL', `FROM:${connection.transaction.mail_from.format(!smtp_client.smtp_utf8)}`);
390
+ return;
391
+ }
392
+
393
+ if (c.auth.type === null || typeof (c.auth.type) === 'undefined') return; // Ignore blank
394
+ const auth_type = c.auth.type.toLowerCase();
395
+ if (!smtp_client.auth_capabilities.includes(auth_type)) {
396
+ throw new Error(`Auth type "${auth_type}" not supported by server (supports: ${smtp_client.auth_capabilities.join(',')})`);
397
+ }
398
+ switch (auth_type) {
399
+ case 'plain':
400
+ if (!c.auth.user || !c.auth.pass) {
401
+ throw new Error("Must include auth.user and auth.pass for PLAIN auth.");
402
+ }
403
+ logger.logdebug(`[smtp_client] uuid=${smtp_client.uuid} authenticating as "${c.auth.user}"`);
404
+ smtp_client.send_command('AUTH', `PLAIN ${utils.base64(`${c.auth.user}\0${c.auth.user}\0${c.auth.pass}`)}`);
405
+ break;
406
+ case 'cram-md5':
407
+ throw new Error("Not implemented");
408
+ default:
409
+ throw new Error(`Unknown AUTH type: ${auth_type}`);
410
+ }
411
+ });
485
412
 
486
- smtp_client.on('auth', () => {
487
- // if authentication has been handled by plugin(s)
488
- if (smtp_client.authenticating) return;
413
+ smtp_client.on('auth', () => {
414
+ // if authentication has been handled by plugin(s)
415
+ if (smtp_client.authenticating) return;
489
416
 
490
- if (smtp_client.is_dead_sender(plugin, connection)) return;
417
+ if (smtp_client.is_dead_sender(plugin, connection)) return;
491
418
 
492
- smtp_client.authenticated = true;
493
- smtp_client.send_command('MAIL', `FROM:${connection.transaction.mail_from.format(!smtp_client.smtp_utf8)}`);
494
- });
419
+ smtp_client.authenticated = true;
420
+ smtp_client.send_command('MAIL', `FROM:${connection.transaction.mail_from.format(!smtp_client.smtp_utf8)}`);
421
+ });
495
422
 
496
- // these errors only get thrown when the connection is still active
497
- smtp_client.on('error', (msg) => {
498
- connection.logwarn(plugin, msg);
499
- smtp_client.call_next();
500
- });
423
+ // these errors only get thrown when the connection is still active
424
+ smtp_client.on('error', (msg) => {
425
+ connection.logwarn(plugin, msg);
426
+ smtp_client.call_next();
427
+ });
501
428
 
502
- // these are the errors thrown when the connection is dead
503
- smtp_client.on('connection-error', (error) => {
504
- // error contains e.g. "Error: connect ECONNREFUSE"
505
- logger.logerror(`backend failure: ${smtp_client.host}:${smtp_client.port} - ${error}`);
506
- const host_pool = connection.server.notes.host_pool;
507
- // only exists for if forwarding_host_pool is set in the config
508
- if (host_pool) {
509
- host_pool.failed(smtp_client.host, smtp_client.port);
510
- }
511
- smtp_client.call_next();
512
- });
429
+ // these are the errors thrown when the connection is dead
430
+ smtp_client.on('connection-error', (error) => {
431
+ // error contains e.g. "Error: connect ECONNREFUSE"
432
+ logger.logerror(`backend failure: ${smtp_client.host}:${smtp_client.port} - ${error}`);
433
+ const { host_pool } = connection.server.notes;
434
+ // only exists for if forwarding_host_pool is set in the config
435
+ if (host_pool) {
436
+ host_pool.failed(smtp_client.host, smtp_client.port);
437
+ }
438
+ smtp_client.call_next();
439
+ });
513
440
 
514
- if (smtp_client.connected) {
515
- if (smtp_client.xclient) {
516
- smtp_client.send_command('XCLIENT', `ADDR=${connection.remote.ip}`);
517
- }
518
- else {
519
- smtp_client.emit('helo');
520
- }
441
+ if (smtp_client.connected) {
442
+ if (smtp_client.xclient) {
443
+ smtp_client.send_command('XCLIENT', `ADDR=${connection.remote.ip}`);
521
444
  }
445
+ else {
446
+ smtp_client.emit('helo');
447
+ }
448
+ }
522
449
 
523
- callback(err, smtp_client);
524
- });
450
+ callback(null, smtp_client);
525
451
  }
526
452
 
527
453
  function get_hostport (connection, server, cfg) {
@@ -539,15 +465,12 @@ function get_hostport (connection, server, cfg) {
539
465
  const host = server.notes.host_pool.get_host();
540
466
  if (host) return host; // { host: 1.2.3.4, port: 567 }
541
467
 
542
- logger.logerror('[smtp_client_pool] no backend hosts in pool!');
468
+ logger.logerror('[smtp_client] no backend hosts in pool!');
543
469
  throw new Error("no backend hosts found in pool!");
544
470
  }
545
471
 
546
- if (cfg.host && cfg.port) {
547
- return { host: cfg.host, port: cfg.port };
548
- }
472
+ if (cfg.host && cfg.port) return { host: cfg.host, port: cfg.port };
549
473
 
550
- logger.logwarn("[smtp_client_pool] forwarding_host_pool or host and port " +
551
- "were not found in config file");
474
+ logger.logwarn("[smtp_client] forwarding_host_pool or host and port were not found in config file");
552
475
  throw new Error("You must specify either forwarding_host_pool or host and port");
553
476
  }
@@ -4,12 +4,6 @@ host=localhost
4
4
  ; port to connect to
5
5
  port=2555
6
6
  ;
7
- ; timeout backend connection from pool
8
- ;timeout=300
9
- ;
10
- ; max connections in pool
11
- ;max_connections=1000
12
- ;
13
7
  ; uncomment to enable TLS to the backend SMTP server
14
8
  enable_tls=true
15
9
  ;
@@ -2,7 +2,7 @@
2
2
 
3
3
  const events = require('events');
4
4
  const fixtures = require('haraka-test-fixtures');
5
- const stub = fixtures.stub.stub;
5
+ const { stub } = fixtures.stub;
6
6
 
7
7
  class Socket extends events.EventEmitter {
8
8
  constructor (port, host) {
@@ -1,10 +1,10 @@
1
1
  'use strict';
2
2
 
3
- const Address = require('address-rfc2821').Address;
3
+ const { Address } = require('address-rfc2821');
4
4
  const fixtures = require('haraka-test-fixtures');
5
5
  const stub_connection = fixtures.connection;
6
- // var transaction = fixtures.transaction; // not yet sufficient
7
- const transaction = require('../../transaction');
6
+ // const transaction = fixtures.transaction; // not yet sufficient
7
+ const transaction = require('../../transaction');
8
8
 
9
9
 
10
10
  /**
@@ -91,8 +91,7 @@ exports.createHMailItem = (outbound_context, options, callback) => {
91
91
  callback('No hmail producted');
92
92
  return;
93
93
  }
94
- for (let j=0; j<hmails.length; j++) {
95
- const hmail = hmails[j];
94
+ for (const hmail of hmails) {
96
95
  hmail.hostlist = [ delivery_domain ];
97
96
  callback(null, hmail);
98
97
  }
@@ -153,8 +152,7 @@ function getNextEntryFromPlaybook (ofType, playbook) {
153
152
  return false;
154
153
  }
155
154
  if (playbook[0].from == ofType) {
156
- const entry = playbook.shift();
157
- return entry;
155
+ return playbook.shift();
158
156
  }
159
157
  return false;
160
158
  }
@@ -53,7 +53,7 @@ function make_test (module_path, test_path, additional_sandbox) {
53
53
  exports.add_tests = (module_path, tests_path, test_exports, add_to_sandbox) => {
54
54
  const additional_sandbox = add_to_sandbox || {};
55
55
  const tests = fs.readdirSync(tests_path).filter(dot_files);
56
- for (let x = 0; x < tests.length; x++) {
57
- test_exports[tests[x]] = make_test(module_path, tests_path + tests[x], additional_sandbox);
56
+ for (const test of tests) {
57
+ test_exports[test] = make_test(module_path, tests_path + test, additional_sandbox);
58
58
  }
59
59
  }
@@ -105,34 +105,33 @@ exports.HostPool = {
105
105
 
106
106
  let num_reqs = 0;
107
107
  const MockSocket = function MockSocket (pool) {
108
- const self = this;
109
108
 
110
109
  // these are the methods called from probe_dead_host
111
110
 
112
111
  // setTimeout on the socket
113
- self.pretendTimeout = () => {};
114
- self.setTimeout = (ms, cb) => {
115
- self.pretendTimeout = cb;
112
+ this.pretendTimeout = () => {};
113
+ this.setTimeout = (ms, cb) => {
114
+ this.pretendTimeout = cb;
116
115
  };
117
116
  // handle socket.on('error', ....
118
- self.listeners = {};
119
- self.on = (eventname, cb) => {
120
- self.listeners[eventname] = cb;
117
+ this.listeners = {};
118
+ this.on = (eventname, cb) => {
119
+ this.listeners[eventname] = cb;
121
120
  };
122
- self.emit = eventname => {
123
- self.listeners[eventname]();
121
+ this.emit = eventname => {
122
+ this.listeners[eventname]();
124
123
  };
125
124
  // handle socket.connect(...
126
- self.connected = () => {};
127
- self.connect = (port, host, cb) => {
125
+ this.connected = () => {};
126
+ this.connect = (port, host, cb) => {
128
127
  switch (++num_reqs) {
129
128
  case 1:
130
129
  // the first time through we pretend it timed out
131
- self.pretendTimeout();
130
+ this.pretendTimeout();
132
131
  break;
133
132
  case 2:
134
133
  // the second time through, pretend socket error
135
- self.emit('error');
134
+ this.emit('error');
136
135
  break;
137
136
  case 3:
138
137
  // the third time around, the socket connected
@@ -144,7 +143,7 @@ exports.HostPool = {
144
143
  process.exit(1);
145
144
  }
146
145
  };
147
- self.destroy = () => {};
146
+ this.destroy = () => {};
148
147
 
149
148
  };
150
149
 
@@ -1,8 +1,7 @@
1
1
  "use strict";
2
2
 
3
3
  exports.register = function () {
4
- const plugin = this;
5
- plugin.inherits('base_plugin');
4
+ this.inherits('base_plugin');
6
5
  }
7
6
 
8
7
  exports.main_plugin_method = () => "main"
package/tests/logger.js CHANGED
@@ -319,8 +319,8 @@ exports.add_log_methods = {
319
319
  this.logger.add_log_methods(testObj);
320
320
  const levels = ['DATA','PROTOCOL','DEBUG','INFO','NOTICE','WARN','ERROR','CRIT','ALERT','EMERG'];
321
321
  test.expect(levels.length);
322
- for (let i=0; i<levels.length; i++) {
323
- test.ok('function' === typeof(testObj[`log${levels[i].toLowerCase()}`]));
322
+ for (const level of levels) {
323
+ test.ok('function' === typeof(testObj[`log${level.toLowerCase()}`]));
324
324
  }
325
325
  test.done();
326
326
  },