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/eslint.config.mjs CHANGED
@@ -1,30 +1,2 @@
1
- import globals from 'globals'
2
- import path from 'node:path'
3
- import { fileURLToPath } from 'node:url'
4
- import js from '@eslint/js'
5
- import { FlatCompat } from '@eslint/eslintrc'
6
-
7
- const __filename = fileURLToPath(import.meta.url)
8
- const __dirname = path.dirname(__filename)
9
- const compat = new FlatCompat({
10
- baseDirectory: __dirname,
11
- recommendedConfig: js.configs.recommended,
12
- allConfig: js.configs.all,
13
- })
14
-
15
- export default [
16
- ...compat.extends('@haraka'),
17
- {
18
- languageOptions: {
19
- globals: {
20
- ...globals.node,
21
- },
22
- },
23
-
24
- rules: {
25
- 'prefer-template': 'warn',
26
- 'no-unneeded-ternary': 1,
27
- 'no-unused-vars': 0,
28
- },
29
- },
30
- ]
1
+ import haraka from '@haraka/eslint-config'
2
+ export default [...haraka]
package/haraka.js CHANGED
@@ -12,7 +12,7 @@ if (!process.env.HARAKA) {
12
12
  process.env.HARAKA = process.env.HARAKA || path.resolve('.')
13
13
  try {
14
14
  require.paths.push(makePathJoin())
15
- } catch (e) {
15
+ } catch {
16
16
  process.env.NODE_PATH = process.env.NODE_PATH ? `${process.env.NODE_PATH}:${makePathJoin()}` : makePathJoin()
17
17
  require('module')._initPaths() // Horrible hack
18
18
  }
@@ -60,7 +60,7 @@ process.on('SIGHUP', () => {
60
60
  server.flushQueue()
61
61
  })
62
62
 
63
- process.on('exit', (code) => {
63
+ process.on('exit', () => {
64
64
  if (shutting_down) return
65
65
  const [, filename] = process.argv
66
66
  process.title = path.basename(filename, '.js')
package/line_socket.js CHANGED
@@ -1,40 +1,13 @@
1
1
  'use strict'
2
- // A subclass of Socket which reads data by line
2
+ // Back-compat shim. The Socket class lives in haraka-net-utils as LineSocket;
3
+ // the line-processing helper is `add_line_processor` there. The connect()
4
+ // helper stays here because it depends on Haraka's tls_socket.
3
5
 
4
- const net = require('node:net')
5
- const utils = require('haraka-utils')
6
+ const { LineSocket, add_line_processor } = require('haraka-net-utils')
6
7
 
7
8
  const tls_socket = require('./tls_socket')
8
9
 
9
- class Socket extends net.Socket {
10
- constructor(options) {
11
- super(options)
12
- setup_line_processor(this)
13
- }
14
- }
15
-
16
- function setup_line_processor(socket) {
17
- let current_data = ''
18
-
19
- socket.on('data', function on_socket_data(data) {
20
- current_data += data
21
- let results
22
- while ((results = utils.line_regexp.exec(current_data))) {
23
- const this_line = results[1]
24
- current_data = current_data.slice(this_line.length)
25
- socket.emit('line', this_line)
26
- }
27
- })
28
-
29
- socket.on('end', function on_socket_end() {
30
- if (current_data.length) {
31
- socket.emit('line', current_data)
32
- }
33
- current_data = ''
34
- })
35
- }
36
-
37
- exports.Socket = Socket
10
+ exports.Socket = LineSocket
38
11
 
39
12
  // New interface - uses TLS
40
13
  exports.connect = (port, host) => {
@@ -46,6 +19,6 @@ exports.connect = (port, host) => {
46
19
  options.host = host
47
20
  }
48
21
  const sock = tls_socket.connect(options)
49
- setup_line_processor(sock)
22
+ add_line_processor(sock)
50
23
  return sock
51
24
  }
package/outbound/hmail.js CHANGED
@@ -7,7 +7,7 @@ const dns = require('node:dns')
7
7
  const net = require('node:net')
8
8
  const path = require('node:path')
9
9
 
10
- const { Address } = require('../address')
10
+ const { Address } = require('@haraka/email-address')
11
11
  const config = require('haraka-config')
12
12
  const constants = require('haraka-constants')
13
13
  const DSN = require('haraka-dsn')
@@ -24,7 +24,7 @@ const _qfile = require('./qfile')
24
24
  const outbound = require('./index')
25
25
  const obtls = require('./tls')
26
26
 
27
- const FsyncWriteStream = require('./fsync_writestream')
27
+ const FsyncWriteStream = utils.FsyncWriteStream
28
28
 
29
29
  let queue_dir
30
30
  let temp_fail_queue
@@ -713,7 +713,7 @@ class HMailItem extends events.EventEmitter {
713
713
  break
714
714
  case 'CRAM-MD5':
715
715
  // The response is our challenge
716
- return send_command(cram_md5_response(mx.auth_user, mx.auth_pass, resp))
716
+ return send_command(utils.cram_md5_response(mx.auth_user, mx.auth_pass, resp))
717
717
  default:
718
718
  // This shouldn't happen...
719
719
  }
@@ -975,7 +975,7 @@ class HMailItem extends events.EventEmitter {
975
975
  data_stream.on('error', (err) => {
976
976
  cb(err)
977
977
  })
978
- } catch (err) {
978
+ } catch {
979
979
  this.populate_bounce_message_with_headers(from, to, reason, header, cb)
980
980
  }
981
981
  }
@@ -1247,7 +1247,7 @@ class HMailItem extends events.EventEmitter {
1247
1247
  plugins.run_hooks('bounce', this, err)
1248
1248
  }
1249
1249
 
1250
- bounce_respond(retval, msg) {
1250
+ bounce_respond(retval) {
1251
1251
  if (retval !== constants.cont) {
1252
1252
  this.loginfo(`Plugin responded with: ${retval}. Not sending bounce.`)
1253
1253
  return this.discard() // calls next_cb
@@ -1272,7 +1272,7 @@ class HMailItem extends events.EventEmitter {
1272
1272
  from,
1273
1273
  recip,
1274
1274
  data_lines.join(''),
1275
- (code, msg2) => {
1275
+ (code) => {
1276
1276
  if (code === constants.deny) {
1277
1277
  // failed to even queue the mail
1278
1278
  return self.double_bounce('Unable to queue the bounce message. Not sending bounce!')
@@ -1466,20 +1466,18 @@ class HMailItem extends events.EventEmitter {
1466
1466
  rs.on('error', (err) => {
1467
1467
  err_handler(err, 'hmail.data_stream reader')
1468
1468
  })
1469
- rs.on('end', () => {
1470
- ws.on('close', async () => {
1471
- try {
1472
- const dest_path = path.join(queue_dir, fname)
1473
- await fs.rename(tmp_path, dest_path)
1474
- const split_mail = new HMailItem(fname, dest_path, hmail.notes)
1475
- split_mail.once('ready', () => {
1476
- cb(split_mail)
1477
- })
1478
- } catch (err) {
1479
- err_handler(err, 'tmp file rename')
1480
- }
1481
- })
1482
- ws.destroySoon()
1469
+ rs.on('end', async () => {
1470
+ try {
1471
+ await ws.close()
1472
+ const dest_path = path.join(queue_dir, fname)
1473
+ await fs.rename(tmp_path, dest_path)
1474
+ const split_mail = new HMailItem(fname, dest_path, hmail.notes)
1475
+ split_mail.once('ready', () => {
1476
+ cb(split_mail)
1477
+ })
1478
+ } catch (err) {
1479
+ err_handler(err, 'tmp file close/rename')
1480
+ }
1483
1481
  })
1484
1482
  }
1485
1483
 
@@ -1504,12 +1502,3 @@ module.exports.obtls = obtls
1504
1502
  logger.add_log_methods(HMailItem)
1505
1503
 
1506
1504
  const smtp_regexp = /^([2345]\d\d)([ -])#?(?:(\d\.\d\.\d)\s)?(.*)/
1507
-
1508
- function cram_md5_response(username, password, challenge) {
1509
- const crypto = require('crypto')
1510
- const c = utils.unbase64(challenge)
1511
- const hmac = crypto.createHmac('md5', password)
1512
- hmac.update(c)
1513
- const digest = hmac.digest('hex')
1514
- return utils.base64(`${username} ${digest}`)
1515
- }
package/outbound/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  const fs = require('node:fs/promises')
4
4
  const path = require('node:path')
5
5
 
6
- const { Address } = require('../address')
6
+ const { Address } = require('@haraka/email-address')
7
7
  const config = require('haraka-config')
8
8
  const constants = require('haraka-constants')
9
9
  const net_utils = require('haraka-net-utils')
@@ -13,7 +13,7 @@ const ResultStore = require('haraka-results')
13
13
  const logger = require('../logger')
14
14
  const trans = require('../transaction')
15
15
  const plugins = require('../plugins')
16
- const FsyncWriteStream = require('./fsync_writestream')
16
+ const FsyncWriteStream = utils.FsyncWriteStream
17
17
 
18
18
  const obc = require('./config')
19
19
  const queuelib = require('./queue')
@@ -241,7 +241,7 @@ exports.send_trans_email = function (transaction, next) {
241
241
  transaction.results = new ResultStore(connection)
242
242
  }
243
243
 
244
- connection.pre_send_trans_email_respond = async (retval) => {
244
+ connection.pre_send_trans_email_respond = async () => {
245
245
  const deliveries = get_deliveries(transaction)
246
246
  const hmails = []
247
247
  const ok_paths = []
package/outbound/queue.js CHANGED
@@ -4,11 +4,12 @@ const child_process = require('node:child_process')
4
4
  const fs = require('node:fs/promises')
5
5
  const path = require('node:path')
6
6
 
7
- const { Address } = require('../address')
7
+ const { Address } = require('@haraka/email-address')
8
8
  const config = require('haraka-config')
9
+ const utils = require('haraka-utils')
9
10
 
10
11
  const logger = require('../logger')
11
- const TimerQueue = require('./timer_queue')
12
+ const TimerQueue = utils.TimerQueue
12
13
  const HMailItem = require('./hmail')
13
14
  const obc = require('./config')
14
15
  const _qfile = require('./qfile')
@@ -101,7 +102,7 @@ const delivery_queue = (exports.delivery_queue = new Queue(async (hmail) => {
101
102
  })
102
103
  }))
103
104
 
104
- const temp_fail_queue = (exports.temp_fail_queue = new TimerQueue())
105
+ const temp_fail_queue = (exports.temp_fail_queue = new TimerQueue(1000, { logger }))
105
106
 
106
107
  let queue_count = 0
107
108
 
@@ -111,7 +112,7 @@ exports.list_queue = async () => {
111
112
  return exports._load_cur_queue(null, exports._list_file)
112
113
  }
113
114
 
114
- exports._stat_file = async (file) => {
115
+ exports._stat_file = async () => {
115
116
  queue_count++
116
117
  }
117
118
 
@@ -180,7 +181,9 @@ exports.rename_to_actual_pid = async (file, parts) => {
180
181
  await fs.rename(path.join(exports.queue_dir, file), path.join(exports.queue_dir, new_filename))
181
182
  return new_filename
182
183
  } catch (err) {
183
- throw new Error(`Unable to rename queue file: ${file} to ${new_filename} : ${err}`)
184
+ throw new Error(`Unable to rename queue file: ${file} to ${new_filename}`, {
185
+ cause: err,
186
+ })
184
187
  }
185
188
  }
186
189
 
package/package.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "author": "Matt Sergeant <helpme@gmail.com> (http://baudehlo.com/)",
2
+ "author": "Matt Sergeant <helpme@gmail.com>",
3
3
  "name": "Haraka",
4
4
  "license": "MIT",
5
5
  "description": "An SMTP Server project.",
@@ -9,7 +9,7 @@
9
9
  "server",
10
10
  "email"
11
11
  ],
12
- "version": "3.2.1",
12
+ "version": "3.3.1",
13
13
  "homepage": "http://haraka.github.io",
14
14
  "repository": {
15
15
  "type": "git",
@@ -20,77 +20,80 @@
20
20
  "node": ">=20"
21
21
  },
22
22
  "dependencies": {
23
- "@haraka/email-address": "~3.1.3",
24
- "haraka-config": "~1.6.0",
25
- "haraka-constants": "~1.0.7",
23
+ "@haraka/email-address": "~3.1.6",
24
+ "haraka-config": "~1.6.3",
25
+ "haraka-constants": "~1.0.8",
26
26
  "haraka-dsn": "~1.2.0",
27
- "haraka-email-message": "~1.3.3",
28
- "haraka-net-utils": "~1.8.2",
27
+ "haraka-email-message": "~1.4.0",
28
+ "haraka-net-utils": "~1.9.2",
29
29
  "haraka-notes": "~1.1.3",
30
- "haraka-plugin-redis": "~2.0.11",
31
- "haraka-results": "~2.3.0",
32
- "haraka-tld": "~1.3.4",
33
- "haraka-utils": "~1.1.4",
30
+ "haraka-plugin-redis": "~2.1.0",
31
+ "haraka-results": "~2.4.0",
32
+ "haraka-tld": "~1.3.6",
33
+ "haraka-utils": "~2.2.1",
34
34
  "ipaddr.js": "~2.4.0",
35
- "node-gyp": "~12.3.0",
36
- "nopt": "~10.0.0",
37
- "redis": "~5.12.1",
38
- "semver": "~7.8.0"
35
+ "node-gyp": "~12.4.0",
36
+ "nopt": "~10.0.1",
37
+ "redis": "~6.0.0",
38
+ "semver": "~7.8.4"
39
39
  },
40
40
  "optionalDependencies": {
41
41
  "@haraka/ocsp": "~1.2.0",
42
- "haraka-plugin-access": "~1.2.0",
43
- "haraka-plugin-aliases": "~1.0.3",
44
- "haraka-plugin-asn": "~2.1.0",
45
- "haraka-plugin-attachment": "~1.2.0",
46
- "haraka-plugin-bounce": "~2.1.2",
47
- "haraka-plugin-clamd": "~1.0.2",
42
+ "haraka-plugin-access": "~1.4.0",
43
+ "haraka-plugin-aliases": "~1.1.0",
44
+ "haraka-plugin-asn": "~2.2.0",
45
+ "haraka-plugin-attachment": "~1.2.1",
46
+ "haraka-plugin-bounce": "~2.2.1",
47
+ "haraka-plugin-clamd": "~1.0.3",
48
48
  "haraka-plugin-dcc": "~1.0.3",
49
49
  "haraka-plugin-dkim": "~1.2.0",
50
- "haraka-plugin-dns-list": "~1.2.4",
50
+ "haraka-plugin-dns-list": "~1.3.0",
51
51
  "haraka-plugin-early_talker": "~1.0.2",
52
- "haraka-plugin-fcrdns": "~1.1.2",
52
+ "haraka-plugin-fcrdns": "~1.2.1",
53
53
  "haraka-plugin-geoip": "~1.1.2",
54
- "haraka-plugin-greylist": "~1.1.1",
55
- "haraka-plugin-headers": "~1.1.2",
56
- "haraka-plugin-helo.checks": "~1.1.1",
57
- "haraka-plugin-karma": "~2.4.1",
58
- "haraka-plugin-known-senders": "~1.1.4",
59
- "haraka-plugin-limit": "~1.2.7",
60
- "haraka-plugin-mail_from.is_resolvable": "~1.2.0",
61
- "haraka-plugin-messagesniffer": "~1.0.1",
62
- "haraka-plugin-qmail-deliverable": "~1.3.5",
54
+ "haraka-plugin-greylist": "~1.2.1",
55
+ "haraka-plugin-headers": "~1.2.0",
56
+ "haraka-plugin-helo.checks": "~1.1.3",
57
+ "haraka-plugin-karma": "~2.5.2",
58
+ "haraka-plugin-known-senders": "~1.2.0",
59
+ "haraka-plugin-limit": "~1.3.2",
60
+ "haraka-plugin-mail_from.is_resolvable": "~1.3.0",
61
+ "haraka-plugin-messagesniffer": "~1.0.2",
62
+ "haraka-plugin-qmail-deliverable": "~1.4.0",
63
63
  "haraka-plugin-relay": "~1.0.2",
64
64
  "haraka-plugin-rspamd": "~1.6.0",
65
- "haraka-plugin-spamassassin": "~1.0.4",
66
- "haraka-plugin-spf": "~1.2.11",
67
- "haraka-plugin-syslog": "~1.1.0",
68
- "haraka-plugin-uribl": "~1.0.10"
65
+ "haraka-plugin-spamassassin": "~1.1.0",
66
+ "haraka-plugin-spf": "~1.3.0",
67
+ "haraka-plugin-syslog": "~1.1.2",
68
+ "haraka-plugin-uribl": "~2.0.0"
69
69
  },
70
70
  "devDependencies": {
71
- "@haraka/eslint-config": "~2.0.4",
72
- "haraka-test-fixtures": "~1.6.0",
73
- "mock-require": "~3.0.3"
71
+ "@haraka/eslint-config": "~3.0.0",
72
+ "haraka-test-fixtures": "^1.7.1",
73
+ "mock-require": "~3.0.3",
74
+ "toobusy-js": "^0.5.1"
74
75
  },
75
76
  "bugs": {
76
77
  "mail": "haraka.mail@gmail.com",
77
78
  "url": "https://github.com/haraka/Haraka/issues"
78
79
  },
79
80
  "bin": {
80
- "haraka": "./bin/haraka",
81
- "haraka_grep": "./bin/haraka_grep"
81
+ "haraka": "bin/haraka",
82
+ "haraka_grep": "bin/haraka_grep"
82
83
  },
83
84
  "scripts": {
85
+ "prepare": "git rev-parse --git-dir >/dev/null 2>&1 && git config core.hooksPath .githooks || true",
84
86
  "format": "npm run prettier:fix && npm run lint:fix",
85
- "lint": "npx eslint *.js outbound plugins plugins/*/*.js test test/*/*.js test/*/*/*.js bin/haraka",
86
- "lint:fix": "npx eslint --fix *.js outbound plugins plugins/*/*.js test test/*/*.js test/*/*/*.js bin/haraka",
87
+ "lint": "npx eslint *.js outbound plugins plugins/*/*.js test test/*/*.js test/*/*/*.js",
88
+ "lint:fix": "npx eslint --fix *.js outbound plugins plugins/*/*.js test test/*/*.js test/*/*/*.js",
87
89
  "prettier": "npx prettier . --check",
88
90
  "prettier:fix": "npx prettier . --write --log-level=warn",
91
+ "qlty": "qlty smells --all",
89
92
  "test": "sh ./run_tests",
93
+ "test:coverage": "node --test --test-concurrency=1 --experimental-test-coverage --test-coverage-include=*.js --test-coverage-include=plugins/**/*.js --test-coverage-include=outbound/*.js",
94
+ "test:coverage:lcov": "mkdir -p coverage && node --test --test-concurrency=1 --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=coverage/lcov.info --test-coverage-include=*.js --test-coverage-include=plugins/**/*.js --test-coverage-include=outbound/*.js",
90
95
  "versions": "npx npm-dep-mgr check",
91
- "versions:fix": "npx npm-dep-mgr update",
92
- "test:coverage": "node --test --test-concurrency=1 --experimental-test-coverage",
93
- "test:coverage:lcov": "mkdir -p coverage && node --test --test-concurrency=1 --experimental-test-coverage --test-reporter=lcov --test-reporter-destination=coverage/lcov.info"
96
+ "versions:fix": "npx npm-dep-mgr update"
94
97
  },
95
98
  "prettier": {
96
99
  "singleQuote": true,
@@ -1,7 +1,5 @@
1
1
  // Proxy AUTH requests selectively by domain
2
2
 
3
- const net = require('node:net')
4
-
5
3
  const utils = require('haraka-utils')
6
4
  const net_utils = require('haraka-net-utils')
7
5
 
@@ -56,8 +54,12 @@ exports.try_auth_proxy = function (connection, hosts, user, passwd, cb) {
56
54
  }
57
55
 
58
56
  const self = this
59
- let [host, port] = hosts.shift().split(':') /* eslint prefer-const: 0 */
60
- if (!port) port = 25
57
+ const ep = net_utils.endpoint(hosts.shift(), 25)
58
+ if (ep instanceof Error) {
59
+ connection.logerror(this, `invalid host: ${ep.message}`)
60
+ return this.try_auth_proxy(connection, hosts, user, passwd, cb)
61
+ }
62
+ const { host, port } = ep
61
63
  let methods = []
62
64
  let auth_complete = false
63
65
  let auth_success = false
@@ -134,6 +136,7 @@ exports.try_auth_proxy = function (connection, hosts, user, passwd, cb) {
134
136
  // certificate to negotiate TLS, so always STARTTLS when
135
137
  // the backend offers it. The local key/cert are only
136
138
  // attached if configured (mutual TLS), not required.
139
+ /* eslint no-useless-assignment: 0 */
137
140
  key = self.config.get(self.tls_cfg.main.key || 'tls_key.pem', 'binary')
138
141
  cert = self.config.get(self.tls_cfg.main.cert || 'tls_cert.pem', 'binary')
139
142
  this.on('secure', () => {
@@ -53,7 +53,7 @@ exports.hook_data_post = function (next, connection) {
53
53
  connection.logerror(this, `Unable to append to mail_from.blocklist: ${err}`)
54
54
  return
55
55
  }
56
- fs.write(fd, `${to_block}\n`, null, 'UTF-8', (err2, written) => {
56
+ fs.write(fd, `${to_block}\n`, null, 'UTF-8', () => {
57
57
  fs.close(fd)
58
58
  })
59
59
  })
@@ -101,7 +101,7 @@ exports.hook_deny = function (next, connection, params) {
101
101
  }
102
102
  }
103
103
 
104
- exports.hook_rcpt_ok = function (next, connection, rcpt) {
104
+ exports.hook_rcpt_ok = function (next, connection) {
105
105
  const transaction = connection?.transaction
106
106
  if (!transaction) return next()
107
107
 
@@ -87,7 +87,7 @@ exports.hook_queue = function (next, connection) {
87
87
  }
88
88
  plugin.loginfo('Message Stream sent to qmail. Now sending envelope')
89
89
  const buf = plugin.build_envelope(connection.transaction)
90
- qmail_queue.stdout.on('error', (err) => {}) // stdout throws an error on close
90
+ qmail_queue.stdout.on('error', () => {}) // stdout throws an error on close
91
91
  qmail_queue.stdout.end(buf)
92
92
  })
93
93
  }
@@ -10,7 +10,7 @@ exports.register = function () {
10
10
  this.register_hook('queue_outbound', 'quarantine')
11
11
  }
12
12
 
13
- exports.hook_init_master = function (next, server) {
13
+ exports.hook_init_master = function (next) {
14
14
  this.init_quarantine_dir(() => {
15
15
  this.clean_tmp_directory(next)
16
16
  })
@@ -62,8 +62,8 @@ exports.init_quarantine_dir = function (done) {
62
62
  const tmp_dir = path.join(this.get_base_dir(), 'tmp')
63
63
  fs.promises
64
64
  .mkdir(tmp_dir, { recursive: true })
65
- .then((made) => this.loginfo(`created ${tmp_dir}`))
66
- .catch((err) => this.logerror(`Unable to create ${tmp_dir}`))
65
+ .then(() => this.loginfo(`created ${tmp_dir}`))
66
+ .catch(() => this.logerror(`Unable to create ${tmp_dir}`))
67
67
  .finally(done)
68
68
  }
69
69
 
@@ -98,11 +98,11 @@ exports.quarantine = function (next, connection) {
98
98
  // final destination.
99
99
  fs.promises
100
100
  .mkdir(msg_dir, { recursive: true })
101
- .catch((err) => {
101
+ .catch(() => {
102
102
  connection.logerror(this, `Error creating directory: ${msg_dir}`)
103
103
  next()
104
104
  })
105
- .then((ok) => {
105
+ .then(() => {
106
106
  const ws = fs.createWriteStream(tmp_path)
107
107
 
108
108
  ws.on('error', (err) => {
@@ -21,7 +21,7 @@ exports.hook_data_post = (next, connection) => {
21
21
  return next()
22
22
  }
23
23
 
24
- exports.hook_get_mx = function (next, hmail, domain) {
24
+ exports.hook_get_mx = function (next, hmail) {
25
25
  let priority = 10
26
26
  if (this.cfg.main.priority) {
27
27
  priority = this.cfg.main.priority
@@ -41,7 +41,7 @@ exports.load_smtp_proxy_ini = function () {
41
41
  }
42
42
  }
43
43
 
44
- exports.hook_mail = function (next, connection, params) {
44
+ exports.hook_mail = function (next, connection) {
45
45
  const c = this.cfg.main
46
46
  connection.loginfo(
47
47
  this,
@@ -70,7 +70,7 @@ exports.hook_mail = function (next, connection, params) {
70
70
  delete connection.notes.smtp_client
71
71
  })
72
72
 
73
- smtp_client.on('bad_code', (code, msg) => {
73
+ smtp_client.on('bad_code', (code) => {
74
74
  smtp_client.call_next(code.match(/^4/) ? DENYSOFT : DENY, smtp_client.response.slice())
75
75
 
76
76
  if (smtp_client.command !== 'rcpt') {
package/plugins/status.js CHANGED
@@ -136,8 +136,8 @@ exports.queue_inspect = function (cb) {
136
136
  exports.queue_discard = function (file, cb) {
137
137
  try {
138
138
  this.outbound.temp_fail_queue.discard(file)
139
- } catch (e) {
140
- // we ignore not found error
139
+ } catch {
140
+ // ignore not found error
141
141
  }
142
142
 
143
143
  fs.unlink(path.join(this.queue_dir || '', file), () => {
@@ -29,7 +29,7 @@ exports.loadConfig = function () {
29
29
  }
30
30
  }
31
31
 
32
- exports.check_busy = function (next, connection) {
32
+ exports.check_busy = function (next) {
33
33
  if (!toobusy()) {
34
34
  was_busy = false
35
35
  return next()
package/plugins.js CHANGED
@@ -197,11 +197,12 @@ class Plugin {
197
197
  __filename: pp,
198
198
  __dirname: path.dirname(pp),
199
199
  exports: this,
200
- setTimeout,
200
+ fetch,
201
201
  clearTimeout,
202
- setInterval,
203
202
  clearInterval,
204
203
  process,
204
+ setInterval,
205
+ setTimeout,
205
206
  Buffer,
206
207
  Math,
207
208
  server: plugins.server,
@@ -585,7 +586,7 @@ function get_denyfn(object, hook, params, retval, msg, respond_method) {
585
586
  switch (deny_retval) {
586
587
  case constants.ok:
587
588
  // Override rejection
588
- object.loginfo(`deny(soft?) overriden by deny hook${deny_msg ? ': deny_msg' : ''}`)
589
+ object.loginfo(`deny(soft?) overridden by deny hook${deny_msg ? ': deny_msg' : ''}`)
589
590
  // Restore hooks_to_run with saved copy so that
590
591
  // any other plugins on this hook can also run.
591
592
  if (object.saved_hooks_to_run.length > 0) {