Haraka 3.2.1 → 3.3.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 (82) hide show
  1. package/.githooks/pre-commit +41 -0
  2. package/.prettierignore +1 -0
  3. package/.qlty/.gitignore +7 -0
  4. package/.qlty/configs/.shellcheckrc +1 -0
  5. package/.qlty/qlty.toml +15 -0
  6. package/CHANGELOG.md +29 -5
  7. package/CONTRIBUTORS.md +5 -5
  8. package/README.md +6 -3
  9. package/bin/haraka +12 -4
  10. package/config/connection.ini +6 -0
  11. package/connection.js +67 -68
  12. package/contrib/bsd-rc.d/haraka +2 -0
  13. package/docs/CoreConfig.md +2 -0
  14. package/docs/HAProxy.md +4 -1
  15. package/eslint.config.mjs +2 -30
  16. package/haraka.js +2 -2
  17. package/line_socket.js +6 -33
  18. package/outbound/hmail.js +18 -29
  19. package/outbound/index.js +3 -3
  20. package/outbound/queue.js +8 -5
  21. package/package.json +49 -46
  22. package/plugins/auth/auth_proxy.js +7 -4
  23. package/plugins/block_me.js +1 -1
  24. package/plugins/delay_deny.js +1 -1
  25. package/plugins/queue/qmail-queue.js +1 -1
  26. package/plugins/queue/quarantine.js +5 -5
  27. package/plugins/queue/smtp_bridge.js +1 -1
  28. package/plugins/queue/smtp_proxy.js +2 -2
  29. package/plugins/status.js +2 -2
  30. package/plugins/toobusy.js +1 -1
  31. package/plugins.js +4 -3
  32. package/server.js +172 -28
  33. package/smtp_client.js +2 -1
  34. package/test/connection.js +119 -2
  35. package/test/fixtures/haproxy_allowed/config/connection.ini +3 -0
  36. package/test/fixtures/haproxy_disabled/config/connection.ini +3 -0
  37. package/test/fixtures/haproxy_untrusted/config/connection.ini +3 -0
  38. package/test/fixtures/line_socket.js +1 -1
  39. package/test/fixtures/util_hmailitem.js +2 -3
  40. package/test/outbound/index.js +6 -7
  41. package/test/outbound/qfile.js +1 -1
  42. package/test/outbound/queue.js +2 -2
  43. package/test/plugins/auth/auth_base.js +17 -17
  44. package/test/plugins/auth/auth_bridge.js +3 -3
  45. package/test/plugins/auth/auth_vpopmaild.js +3 -3
  46. package/test/plugins/auth/flat_file.js +16 -21
  47. package/test/plugins/block_me.js +7 -23
  48. package/test/plugins/data.signatures.js +17 -20
  49. package/test/plugins/delay_deny.js +3 -4
  50. package/test/plugins/prevent_credential_leaks.js +17 -21
  51. package/test/plugins/process_title.js +12 -6
  52. package/test/plugins/queue/deliver.js +7 -8
  53. package/test/plugins/queue/discard.js +3 -4
  54. package/test/plugins/queue/lmtp.js +5 -6
  55. package/test/plugins/queue/qmail-queue.js +7 -8
  56. package/test/plugins/queue/quarantine.js +3 -4
  57. package/test/plugins/queue/smtp_bridge.js +5 -7
  58. package/test/plugins/queue/smtp_forward.js +49 -60
  59. package/test/plugins/queue/smtp_proxy.js +6 -7
  60. package/test/plugins/rcpt_to.host_list_base.js +6 -9
  61. package/test/plugins/rcpt_to.in_host_list.js +6 -11
  62. package/test/plugins/record_envelope_addresses.js +33 -60
  63. package/test/plugins/reseed_rng.js +3 -3
  64. package/test/plugins/status.js +4 -5
  65. package/test/plugins/tarpit.js +3 -4
  66. package/test/plugins/tls.js +3 -5
  67. package/test/plugins/toobusy.js +186 -9
  68. package/test/plugins/xclient.js +7 -4
  69. package/test/server.js +425 -1
  70. package/test/smtp_client.js +11 -18
  71. package/test/tls_socket.js +3 -6
  72. package/tls_socket.js +3 -3
  73. package/transaction.js +3 -3
  74. package/address.js +0 -53
  75. package/endpoint.js +0 -96
  76. package/host_pool.js +0 -169
  77. package/outbound/fsync_writestream.js +0 -44
  78. package/outbound/timer_queue.js +0 -86
  79. package/rfc1869.js +0 -93
  80. package/test/endpoint.js +0 -128
  81. package/test/host_pool.js +0 -188
  82. package/test/rfc1869.js +0 -89
package/server.js CHANGED
@@ -4,15 +4,17 @@
4
4
  const cluster = require('node:cluster')
5
5
  const { spawn } = require('node:child_process')
6
6
  const fs = require('node:fs')
7
+ const net = require('node:net')
7
8
  const os = require('node:os')
8
9
  const path = require('node:path')
9
10
  const tls = require('node:tls')
10
11
  const constants = require('haraka-constants')
12
+ const net_utils = require('haraka-net-utils')
11
13
 
14
+ const { endpoint } = require('haraka-net-utils')
12
15
  const tls_socket = require('./tls_socket')
13
16
  const conn = require('./connection')
14
17
  const outbound = require('./outbound')
15
- const endpoint = require('./endpoint')
16
18
 
17
19
  const Server = exports
18
20
  Server.logger = require('./logger')
@@ -64,8 +66,16 @@ Server.load_http_ini = () => {
64
66
  }).main
65
67
  }
66
68
 
69
+ Server.load_connection_ini = () => {
70
+ Server.connection = {}
71
+ Server.connection.cfg = Server.config.get('connection.ini', {
72
+ booleans: ['+haproxy.enabled'],
73
+ })
74
+ }
75
+
67
76
  Server.load_smtp_ini()
68
77
  Server.load_http_ini()
78
+ Server.load_connection_ini()
69
79
 
70
80
  Server.daemonize = function () {
71
81
  const c = this.cfg.main
@@ -262,14 +272,7 @@ Server.receiveAsMaster = (command, params) => {
262
272
  Server[command].apply(Server, params)
263
273
  }
264
274
 
265
- function messageHandler(worker, msg, handle) {
266
- // sunset Haraka v3 (Node < 6)
267
- if (arguments.length === 2) {
268
- handle = msg
269
- msg = worker
270
- worker = undefined
271
- }
272
- // console.log("received cmd: ", msg);
275
+ function messageHandler(worker, msg) {
273
276
  if (msg?.cmd) {
274
277
  Server.receiveAsMaster(msg.cmd, msg.params)
275
278
  }
@@ -351,6 +354,142 @@ Server.load_default_tls_config = (done) => {
351
354
  })
352
355
  }
353
356
 
357
+ Server.create_smtps_server = (opts, onConnect) => {
358
+ let server
359
+ const socket_tls_state = new Map()
360
+ const proxyPrefix = Buffer.from('PROXY ')
361
+ // Defensive cap while waiting for a PROXY v1 line before TLS starts.
362
+ const proxyLineReadLimit = 512
363
+
364
+ const tlsServer = tls.createServer(opts, (cleartext) => {
365
+ const state_key = socket_tls_state_key(cleartext)
366
+ const smtps_state = socket_tls_state.get(state_key)
367
+ if (smtps_state) cleartext.haraka_smtps = smtps_state
368
+ socket_tls_state.delete(state_key)
369
+
370
+ onConnect(cleartext)
371
+ })
372
+
373
+ function close_with_proxy_error(socket, timer, msg) {
374
+ clearTimeout(timer)
375
+ socket.removeAllListeners('data')
376
+ socket.end(`421 ${msg}\r\n`, () => {
377
+ socket.destroy()
378
+ })
379
+ }
380
+
381
+ function socket_tls_state_key(socket) {
382
+ return JSON.stringify([socket.remoteAddress, socket.remotePort, socket.localAddress, socket.localPort])
383
+ }
384
+
385
+ function start_tls(socket, proxy, peer_allowed) {
386
+ if (proxy || peer_allowed) {
387
+ const smtps_state = { peer_allowed }
388
+ if (proxy) {
389
+ smtps_state.proxy = {
390
+ ...proxy,
391
+ proxy_ip: net_utils.normalize_ip(socket.remoteAddress) || socket.remoteAddress,
392
+ }
393
+ }
394
+ socket_tls_state.set(socket_tls_state_key(socket), smtps_state)
395
+ }
396
+
397
+ tlsServer.emit('connection', socket)
398
+ }
399
+
400
+ tlsServer.on('tlsClientError', (err, cleartext) => {
401
+ if (cleartext) socket_tls_state.delete(socket_tls_state_key(cleartext))
402
+ server.emit('tlsClientError', err, cleartext)
403
+ })
404
+
405
+ tlsServer.on('secureConnection', (cleartext) => {
406
+ server.emit('secureConnection', cleartext)
407
+ })
408
+
409
+ function starts_with_proxy_prefix(data) {
410
+ if (!data.length) return true
411
+ if (data.length > proxyPrefix.length) return data.subarray(0, proxyPrefix.length).equals(proxyPrefix)
412
+
413
+ return proxyPrefix.subarray(0, data.length).equals(data)
414
+ }
415
+
416
+ function start_tls_with_buffer(socket, data, proxy, peer_allowed) {
417
+ // Preserve bytes already read by the PROXY pre-parser, then hand the
418
+ // paused socket to TLS before letting it read again.
419
+ socket.pause()
420
+ if (data?.length) socket.unshift(data)
421
+ setImmediate(() => {
422
+ start_tls(socket, proxy, peer_allowed)
423
+ socket.resume()
424
+ })
425
+ }
426
+
427
+ server = net.createServer((socket) => {
428
+ const remote_ip = net_utils.normalize_ip(socket.remoteAddress) || socket.remoteAddress
429
+
430
+ if (!net_utils.is_haproxy_allowed(remote_ip)) {
431
+ start_tls(socket)
432
+ return
433
+ }
434
+
435
+ let current_data = null
436
+ const proxy_timer = setTimeout(() => {
437
+ close_with_proxy_error(socket, proxy_timer, 'PROXY timeout')
438
+ }, 30 * 1000)
439
+
440
+ function cleanup() {
441
+ clearTimeout(proxy_timer)
442
+ // Stop flowing before removing the pre-parser listener so TLS bytes
443
+ // cannot arrive between listener removal and TLS attachment.
444
+ socket.pause()
445
+ socket.removeListener('data', on_data)
446
+ socket.removeListener('close', cleanup)
447
+ socket.removeListener('error', cleanup)
448
+ }
449
+
450
+ function on_data(data) {
451
+ current_data = current_data ? Buffer.concat([current_data, data]) : data
452
+
453
+ if (!starts_with_proxy_prefix(current_data)) {
454
+ cleanup()
455
+ start_tls_with_buffer(socket, current_data, null, true)
456
+ return
457
+ }
458
+
459
+ const offset = current_data.indexOf(0x0a)
460
+ if (offset === -1) {
461
+ if (current_data.length > proxyLineReadLimit) {
462
+ close_with_proxy_error(socket, proxy_timer, 'Invalid PROXY format')
463
+ }
464
+ return
465
+ }
466
+ if (offset > proxyLineReadLimit) {
467
+ close_with_proxy_error(socket, proxy_timer, 'Invalid PROXY format')
468
+ return
469
+ }
470
+
471
+ cleanup()
472
+
473
+ const proxy = net_utils.parse_proxy_line(current_data.slice(0, offset + 1))
474
+ if (!proxy) {
475
+ close_with_proxy_error(socket, proxy_timer, 'Invalid PROXY format')
476
+ return
477
+ }
478
+
479
+ const rest = current_data.slice(offset + 1)
480
+ start_tls_with_buffer(socket, rest, proxy, true)
481
+ }
482
+
483
+ socket.once('close', cleanup)
484
+ socket.once('error', cleanup)
485
+ socket.on('data', on_data)
486
+ })
487
+
488
+ server.tlsServer = tlsServer
489
+
490
+ return server
491
+ }
492
+
354
493
  Server.get_smtp_server = async (ep, inactivity_timeout) => {
355
494
  let server
356
495
 
@@ -358,17 +497,19 @@ Server.get_smtp_server = async (ep, inactivity_timeout) => {
358
497
  client.setTimeout(inactivity_timeout)
359
498
  const connection = conn.createConnection(client, server, Server.cfg)
360
499
 
361
- if (!server.has_tls) return
500
+ if (server.has_tls) {
501
+ const cipher = client.getCipher()
502
+ cipher.version = client.getProtocol() // replace min with actual
362
503
 
363
- const cipher = client.getCipher()
364
- cipher.version = client.getProtocol() // replace min with actual
504
+ connection.setTLS({
505
+ cipher,
506
+ verified: client.authorized,
507
+ verifyError: client.authorizationError,
508
+ peerCertificate: client.getPeerCertificate(),
509
+ })
510
+ }
365
511
 
366
- connection.setTLS({
367
- cipher,
368
- verified: client.authorized,
369
- verifyError: client.authorizationError,
370
- peerCertificate: client.getPeerCertificate(),
371
- })
512
+ if (client.haraka_smtps?.proxy) connection.apply_proxy(client.haraka_smtps.proxy)
372
513
  }
373
514
 
374
515
  if (ep.port === parseInt(Server.cfg.main.smtps_port, 10)) {
@@ -382,10 +523,13 @@ Server.get_smtp_server = async (ep, inactivity_timeout) => {
382
523
  tls_socket.cfg.main.requireAuthorized,
383
524
  )
384
525
 
385
- server = tls.createServer(opts, onConnect)
386
- tls_socket.addOCSP(server)
526
+ server = Server.connection.cfg.haproxy.enabled
527
+ ? Server.create_smtps_server(opts, onConnect)
528
+ : tls.createServer(opts, onConnect)
529
+ const tls_event_server = server.tlsServer || server
530
+ tls_socket.addOCSP(tls_event_server)
387
531
  server.has_tls = true
388
- server.on('resumeSession', (id, rsDone) => {
532
+ tls_event_server.on('resumeSession', (id, rsDone) => {
389
533
  Server.loginfo('client requested TLS resumeSession')
390
534
  rsDone(null, null)
391
535
  })
@@ -394,7 +538,7 @@ Server.get_smtp_server = async (ep, inactivity_timeout) => {
394
538
  } else {
395
539
  server = tls_socket.createServer(onConnect)
396
540
  server.has_tls = false
397
- const opts = await tls_socket.getSocketOpts('*')
541
+ await tls_socket.getSocketOpts('*')
398
542
  Server.listeners.push(server)
399
543
  return server
400
544
  }
@@ -403,7 +547,7 @@ Server.get_smtp_server = async (ep, inactivity_timeout) => {
403
547
  Server.setup_smtp_listeners = async (plugins2, type, inactivity_timeout) => {
404
548
  const errors = []
405
549
 
406
- for (const [ifName, ifObj] of Object.entries(os.networkInterfaces())) {
550
+ for (const [, ifObj] of Object.entries(os.networkInterfaces())) {
407
551
  for (const addr of ifObj) {
408
552
  if (addr.family === 'IPv6') {
409
553
  if (!Server.notes.IPv6) Server.notes.IPv6 = true
@@ -476,7 +620,7 @@ Server.setup_http_listeners = async () => {
476
620
  try {
477
621
  Server.http.express = require('express')
478
622
  Server.loginfo('express loaded at Server.http.express')
479
- } catch (err) {
623
+ } catch {
480
624
  Server.logerror('express failed to load. No http server. Install express with: npm install -g express')
481
625
  return
482
626
  }
@@ -531,7 +675,7 @@ Server.init_master_respond = async (retval, msg) => {
531
675
  if (!(cluster && c.nodes)) {
532
676
  try {
533
677
  await outbound.init_queue()
534
- } catch (err) {
678
+ } catch {
535
679
  Server.logcrit('Loading queue failed. Shutting down.')
536
680
  return logger.dump_and_exit(1)
537
681
  }
@@ -566,7 +710,7 @@ Server.init_master_respond = async (retval, msg) => {
566
710
  Server.lognotice(`worker ${worker.id} listening on ${endpoint(address)}`)
567
711
  })
568
712
  cluster.on('exit', cluster_exit_listener)
569
- } catch (err) {
713
+ } catch {
570
714
  Server.logcrit('Scanning queue failed. Shutting down.')
571
715
  logger.dump_and_exit(1)
572
716
  }
@@ -605,7 +749,7 @@ Server.init_child_respond = (retval, msg) => {
605
749
  process.kill(pid)
606
750
  Server.logerror(`Killing master (pid=${pid})`)
607
751
  }
608
- } catch (err) {
752
+ } catch {
609
753
  Server.logerror('Terminating child')
610
754
  }
611
755
  logger.dump_and_exit(1)
@@ -635,7 +779,7 @@ Server.init_http_respond = () => {
635
779
  let WebSocketServer
636
780
  try {
637
781
  WebSocketServer = require('ws').Server
638
- } catch (e) {
782
+ } catch {
639
783
  Server.logerror(`unable to load ws.\n did you: npm install -g ws?`)
640
784
  return
641
785
  }
package/smtp_client.js CHANGED
@@ -15,7 +15,7 @@ const utils = require('haraka-utils')
15
15
 
16
16
  const tls_socket = require('./tls_socket')
17
17
  const logger = require('./logger')
18
- const HostPool = require('./host_pool')
18
+ const HostPool = net_utils.HostPool
19
19
 
20
20
  const smtp_regexp = /^(\d{3})([ -])(.*)/
21
21
  const STATE = {
@@ -486,6 +486,7 @@ function get_hostport(connection, cfg) {
486
486
  server.notes.host_pool = new HostPool(
487
487
  cfg.forwarding_host_pool, // 1.2.3.4:420, 5.6.7.8:420
488
488
  cfg.dead_forwarding_host_retry_secs,
489
+ { logger },
489
490
  )
490
491
  }
491
492
 
@@ -5,7 +5,7 @@ const assert = require('node:assert/strict')
5
5
 
6
6
  const constants = require('haraka-constants')
7
7
  const DSN = require('haraka-dsn')
8
- const { Address } = require('../address')
8
+ const { Address } = require('@haraka/email-address')
9
9
 
10
10
  const connection = require('../connection')
11
11
  const Server = require('../server')
@@ -508,7 +508,10 @@ describe('connection', () => {
508
508
  assert.equal(this.connection.msg_count.tempfail, 1)
509
509
  assert.equal(this.connection.transaction.msg_status, 'deferred')
510
510
  assert.equal(harness.calls.reset, 1)
511
- assert.deepEqual(harness.calls.results[0], { fail: 'Message denied temporarily' })
511
+ assert.deepEqual(harness.calls.results[0], {
512
+ fail: 'Message denied temporarily',
513
+ soft: true,
514
+ })
512
515
  } finally {
513
516
  harness.restore()
514
517
  }
@@ -654,6 +657,120 @@ describe('connection', () => {
654
657
  assert.equal(responses[2][0], 503)
655
658
  })
656
659
 
660
+ it('cmd_mail strips control chars from invalid address logs', () => {
661
+ const notices = []
662
+ const responses = []
663
+ this.connection.hello.host = 'example.test'
664
+ this.connection.lognotice = (msg) => notices.push(msg)
665
+ this.connection.respond = (code, msg) => {
666
+ responses.push({ code, msg })
667
+ }
668
+
669
+ this.connection.cmd_mail('FROM:<mail\x00@example.com>')
670
+
671
+ assert.equal(responses[0].code, 501)
672
+ assert.match(responses[0].msg, /^Invalid MAIL FROM address /)
673
+ assert.equal(responses[0].msg.includes('\r'), false)
674
+ assert.equal(responses[0].msg.includes('\n'), false)
675
+ assert.equal(responses[0].msg.includes('\\u0000'), false)
676
+ assert.equal(notices[0], responses[0].msg)
677
+ })
678
+
679
+ it('cmd_rcpt strips control chars from invalid address logs', () => {
680
+ const notices = []
681
+ const responses = []
682
+ this.connection.transaction = { mail_from: new Address('<from@example.com>'), rcpt_to: [] }
683
+ this.connection.lognotice = (msg) => notices.push(msg)
684
+ this.connection.respond = (code, msg) => {
685
+ responses.push({ code, msg })
686
+ }
687
+
688
+ this.connection.cmd_rcpt('TO:<rcpt\x00@example.com>')
689
+
690
+ assert.equal(responses[0].code, 501)
691
+ assert.match(responses[0].msg, /^Invalid RCPT TO address /)
692
+ assert.equal(responses[0].msg.includes('\r'), false)
693
+ assert.equal(responses[0].msg.includes('\n'), false)
694
+ assert.equal(responses[0].msg.includes('\\u0000'), false)
695
+ assert.equal(notices[0], responses[0].msg)
696
+ })
697
+
698
+ it('cmd_mail rejects a postel-only address when main.postel is false', () => {
699
+ const responses = []
700
+ this.connection.hello.host = 'example.test'
701
+ this.connection.lognotice = () => {}
702
+ this.connection.respond = (code, msg) => responses.push({ code, msg })
703
+
704
+ this.connection.cmd_mail('FROM:<foo@[IPv6:bogus::xyz]>')
705
+
706
+ assert.equal(responses[0].code, 501)
707
+ assert.match(responses[0].msg, /^Invalid MAIL FROM address /)
708
+ })
709
+
710
+ it('cmd_mail accepts a postel-only address when main.postel is true', () => {
711
+ const responses = []
712
+ let started = false
713
+ this.connection.hello.host = 'example.test'
714
+ this.connection.respond = (code, msg) => responses.push({ code, msg })
715
+ this.connection.init_transaction = () => {
716
+ started = true
717
+ }
718
+
719
+ connection.cfg.main.postel = true
720
+ try {
721
+ this.connection.cmd_mail('FROM:<foo@[IPv6:bogus::xyz]>')
722
+ } finally {
723
+ connection.cfg.main.postel = false
724
+ }
725
+
726
+ assert.equal(started, true)
727
+ assert.equal(
728
+ responses.some((r) => r.code === 501),
729
+ false,
730
+ )
731
+ })
732
+
733
+ it('cmd_rcpt rejects a postel-only address when main.postel is false', () => {
734
+ const responses = []
735
+ this.connection.transaction = {
736
+ mail_from: new Address('<from@example.com>'),
737
+ rcpt_to: [],
738
+ }
739
+ this.connection.lognotice = () => {}
740
+ this.connection.respond = (code, msg) => responses.push({ code, msg })
741
+
742
+ this.connection.cmd_rcpt('TO:<foo@[IPv6:bogus::xyz]>')
743
+
744
+ assert.equal(responses[0].code, 501)
745
+ assert.match(responses[0].msg, /^Invalid RCPT TO address /)
746
+ })
747
+
748
+ it('cmd_rcpt accepts a postel-only address when main.postel is true', () => {
749
+ const plugins = require('../plugins')
750
+ const originalRunHooks = plugins.run_hooks
751
+ const responses = []
752
+ this.connection.transaction = {
753
+ mail_from: new Address('<from@example.com>'),
754
+ rcpt_to: [],
755
+ }
756
+ this.connection.respond = (code, msg) => responses.push({ code, msg })
757
+ plugins.run_hooks = () => {}
758
+
759
+ connection.cfg.main.postel = true
760
+ try {
761
+ this.connection.cmd_rcpt('TO:<foo@[IPv6:bogus::xyz]>')
762
+ } finally {
763
+ connection.cfg.main.postel = false
764
+ plugins.run_hooks = originalRunHooks
765
+ }
766
+
767
+ assert.equal(this.connection.transaction.rcpt_to.length, 1)
768
+ assert.equal(
769
+ responses.some((r) => r.code === 501),
770
+ false,
771
+ )
772
+ })
773
+
657
774
  it('data_respond denysoftdisconnect disconnects and default enters DATA', () => {
658
775
  const responses = []
659
776
  let disconnected = 0
@@ -0,0 +1,3 @@
1
+ [haproxy]
2
+ enabled=true
3
+ hosts[] = 127.0.0.1
@@ -0,0 +1,3 @@
1
+ [haproxy]
2
+ enabled=false
3
+ hosts[] = 127.0.0.1
@@ -0,0 +1,3 @@
1
+ [haproxy]
2
+ enabled=true
3
+ hosts[] = 192.0.2.1
@@ -18,4 +18,4 @@ class Socket extends events.EventEmitter {
18
18
 
19
19
  exports.Socket = Socket
20
20
 
21
- exports.connect = (port, host, cb) => new Socket(port, host)
21
+ exports.connect = (port, host) => new Socket(port, host)
@@ -2,7 +2,7 @@
2
2
 
3
3
  const assert = require('node:assert')
4
4
 
5
- const { Address } = require('../../address')
5
+ const { Address } = require('@haraka/email-address')
6
6
  const fixtures = require('haraka-test-fixtures')
7
7
 
8
8
  /**
@@ -44,8 +44,7 @@ exports.createHMailItem = (outbound_context, options, callback) => {
44
44
  const delivery_domain = options.delivery_domain || 'domain'
45
45
  const mail_recipients = options.mail_recipients || [new Address('recipient@domain')]
46
46
 
47
- const conn = fixtures.connection.createConnection()
48
- conn.init_transaction()
47
+ const conn = fixtures.makeConnection({ withTxn: true })
49
48
  conn.transaction.mail_from = new Address(mail_from)
50
49
 
51
50
  const todo = new outbound_context.TODOItem(delivery_domain, mail_recipients, conn.transaction)
@@ -6,7 +6,6 @@ const fs = require('node:fs')
6
6
  const path = require('node:path')
7
7
 
8
8
  const constants = require('haraka-constants')
9
- const logger = require('../../logger')
10
9
 
11
10
  const lines = [
12
11
  'From: John Johnson <john@example.com>',
@@ -211,7 +210,7 @@ describe('outbound', () => {
211
210
  it('yields to setImmediate before opening process_delivery pipes', async () => {
212
211
  const stream = require('node:stream')
213
212
  const Transaction = require('../../transaction')
214
- const Address = require('../../address').Address
213
+ const Address = require('@haraka/email-address').Address
215
214
  const outbound = require('../../outbound')
216
215
  const plugins = require('../../plugins')
217
216
 
@@ -271,7 +270,7 @@ describe('outbound', () => {
271
270
 
272
271
  it('adds missing Message-Id/Date and prepends Received before queueing', async () => {
273
272
  process.env.HARAKA_TEST_DIR = path.resolve('test')
274
- const Address = require('../../address').Address
273
+ const Address = require('@haraka/email-address').Address
275
274
  const outbound = require('../../outbound')
276
275
  const plugins = require('../../plugins')
277
276
 
@@ -281,7 +280,7 @@ describe('outbound', () => {
281
280
  const transaction = {
282
281
  uuid: 'txn-add-headers',
283
282
  header: {
284
- get_all(_name) {
283
+ get_all() {
285
284
  return []
286
285
  },
287
286
  get() {
@@ -344,12 +343,12 @@ describe('outbound', () => {
344
343
  })
345
344
 
346
345
  describe('timer_queue', () => {
347
- let outbound, ob_timer_queue
346
+ let ob_timer_queue
348
347
 
349
348
  beforeEach(() => {
350
349
  process.env.HARAKA_TEST_DIR = path.resolve('test')
351
- outbound = require('../../outbound')
352
- const TimerQueue = require('../../outbound/timer_queue')
350
+ require('../../outbound')
351
+ const { TimerQueue } = require('haraka-utils')
353
352
  ob_timer_queue = new TimerQueue(500)
354
353
  })
355
354
 
@@ -1,6 +1,6 @@
1
1
  'use strict'
2
2
 
3
- const { describe, it, beforeEach } = require('node:test')
3
+ const { describe, it } = require('node:test')
4
4
  const assert = require('node:assert')
5
5
  const os = require('node:os')
6
6
 
@@ -96,7 +96,7 @@ describe('outbound/queue', () => {
96
96
  let renameAttempts = 0
97
97
 
98
98
  const originalRename = queue.rename_to_actual_pid
99
- queue.rename_to_actual_pid = (_file, _parts) => {
99
+ queue.rename_to_actual_pid = () => {
100
100
  renameAttempts++
101
101
  throw new Error('test skip')
102
102
  }
@@ -107,7 +107,7 @@ describe('outbound/queue', () => {
107
107
  '1507509981169_1507509981169_0_61403_e0Y0Ym_1_haraka',
108
108
  '1508455115683_1508455115683_0_90253_9Q4o4V_1_haraka',
109
109
  ],
110
- (_file) => {},
110
+ () => {},
111
111
  )
112
112
  queue.rename_to_actual_pid = originalRename
113
113
  assert.equal(renameAttempts, 1)