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
@@ -24,7 +24,7 @@ exports.lookup_mx = function lookup_mx (domain, cb) {
24
24
 
25
25
  // default wrap_mx just returns our object with "priority" and "exchange" keys
26
26
  let wrap_mx = a => a;
27
- function process_dns (err, addresses) {
27
+ async function process_dns (err, addresses) {
28
28
  if (err) {
29
29
  if (err.code === 'ENODATA' || err.code === 'ENOTFOUND') {
30
30
  // Most likely this is a hostname with no MX record
@@ -33,9 +33,12 @@ exports.lookup_mx = function lookup_mx (domain, cb) {
33
33
  }
34
34
  cb(err);
35
35
  }
36
- else if (addresses && addresses.length) {
36
+ else if (addresses?.length) {
37
37
  for (let i=0,l=addresses.length; i < l; i++) {
38
- if (obc.cfg.local_mx_ok || !net_utils.is_local_ip(addresses[i].exchange)) {
38
+ if (
39
+ obc.cfg.local_mx_ok ||
40
+ await net_utils.is_local_host(addresses[i].exchange).catch(() => null) === false
41
+ ) {
39
42
  const mx = wrap_mx(addresses[i]);
40
43
  mxs.push(mx);
41
44
  }
@@ -49,15 +52,15 @@ exports.lookup_mx = function lookup_mx (domain, cb) {
49
52
  return 1;
50
53
  }
51
54
 
52
- net_utils.get_mx(domain, (err, addresses) => {
53
- if (process_dns(err, addresses)) return;
55
+ net_utils.get_mx(domain, async (err, addresses) => {
56
+ if (await process_dns(err, addresses)) return;
54
57
 
55
58
  // if MX lookup failed, we lookup an A record. To do that we change
56
59
  // wrap_mx() to return same thing as resolveMx() does.
57
60
  wrap_mx = a => ({priority:0,exchange:a});
58
61
  // IS: IPv6 compatible
59
- dns.resolve(domain, (err2, addresses2) => {
60
- if (process_dns(err2, addresses2)) return;
62
+ dns.resolve(domain, async (err2, addresses2) => {
63
+ if (await process_dns(err2, addresses2)) return;
61
64
 
62
65
  err2 = new Error("Found nowhere to deliver to");
63
66
  err2.code = 'NOMX';
package/outbound/queue.js CHANGED
@@ -4,7 +4,7 @@ const async = require('async');
4
4
  const fs = require('fs');
5
5
  const path = require('path');
6
6
 
7
- const Address = require('address-rfc2821').Address;
7
+ const { Address } = require('address-rfc2821');
8
8
  const config = require('haraka-config');
9
9
 
10
10
  const logger = require('../logger');
@@ -135,26 +135,24 @@ exports._add_file = (file, cb) => {
135
135
  const parts = _qfile.parts(file);
136
136
 
137
137
  if (parts.next_attempt <= self.cur_time) {
138
- logger.logdebug("[outbound] File needs processing now");
138
+ logger.logdebug(`[outbound] File ${file} needs processing now`);
139
139
  load_queue.push(file);
140
140
  }
141
141
  else {
142
- logger.logdebug(`[outbound] File needs processing later: ${parts.next_attempt - self.cur_time}ms`);
142
+ logger.logdebug(`[outbound] File ${file} needs processing later: ${parts.next_attempt - self.cur_time}ms`);
143
143
  temp_fail_queue.add(file, parts.next_attempt - self.cur_time, () => { load_queue.push(file);});
144
144
  }
145
145
 
146
146
  cb();
147
147
  }
148
148
 
149
- exports.load_queue_files = (pid, input_files, iteratee, callback) => {
149
+ exports.load_queue_files = (pid, input_files, iteratee, callback = function () {}) => {
150
150
  const self = exports;
151
151
  const searchPid = parseInt(pid);
152
152
 
153
153
  let stat_renamed = 0;
154
154
  let stat_loaded = 0;
155
155
 
156
- callback = callback || function () {};
157
-
158
156
  if (searchPid) {
159
157
  logger.loginfo(`[outbound] Grabbing queue files for pid: ${pid}`);
160
158
  }
@@ -195,13 +193,11 @@ exports.load_queue_files = (pid, input_files, iteratee, callback) => {
195
193
  }
196
194
 
197
195
  exports.stats = () => {
198
- // TODO: output more data here
199
- const results = {
196
+
197
+ return {
200
198
  queue_dir,
201
199
  queue_count,
202
200
  };
203
-
204
- return results;
205
201
  }
206
202
 
207
203
  exports._list_file = (file, cb) => {
@@ -226,7 +222,7 @@ exports._list_file = (file, cb) => {
226
222
  todo_struct.file = file;
227
223
  todo_struct.full_path = path.join(queue_dir, file);
228
224
  const parts = _qfile.parts(file);
229
- todo_struct.pid = (parts && parts.pid) || null;
225
+ todo_struct.pid = (parts?.pid) || null;
230
226
  cb(null, todo_struct);
231
227
  }
232
228
  });
@@ -262,7 +258,7 @@ exports.load_pid_queue = pid => {
262
258
  }
263
259
 
264
260
  exports.ensure_queue_dir = () => {
265
- // No reason not to do this stuff syncronously -
261
+ // No reason to do this asynchronously
266
262
  // this code is only run at start-up.
267
263
  if (fs.existsSync(queue_dir)) return;
268
264
 
@@ -18,11 +18,9 @@ class TQTimer {
18
18
 
19
19
  class TimerQueue {
20
20
 
21
- constructor (interval) {
22
- const self = this;
23
- interval = interval || 1000;
21
+ constructor (interval = 1000) {
24
22
  this.queue = [];
25
- this.interval_timer = setInterval(() => { self.fire(); }, interval);
23
+ this.interval_timer = setInterval(() => { this.fire(); }, interval);
26
24
  }
27
25
 
28
26
  add (id, ms, cb) {
package/outbound/tls.js CHANGED
@@ -74,33 +74,32 @@ class OutboundTLS {
74
74
 
75
75
  // Check for if host is prohibited from TLS negotiation
76
76
  check_tls_nogo (host, cb_ok, cb_nogo) {
77
- const obtls = this;
78
- if (!obtls.cfg.redis.disable_for_failed_hosts) return cb_ok();
77
+ if (!this.cfg.redis.disable_for_failed_hosts) return cb_ok();
79
78
 
80
79
  const dbkey = `no_tls|${host}`;
81
- obtls.db.get(dbkey, (err, dbr) => {
82
- if (err) {
83
- obtls.logdebug(obtls, `Redis returned error: ${err}`);
84
- return cb_ok();
85
- }
86
-
87
- return dbr ? cb_nogo(dbr) : cb_ok();
88
- });
80
+ this.db.get(dbkey)
81
+ .then(dbr => {
82
+ dbr ? cb_nogo(dbr) : cb_ok();
83
+ })
84
+ .catch(err => {
85
+ this.logdebug(this, `Redis returned error: ${err}`);
86
+ cb_ok();
87
+ })
89
88
  }
90
89
 
91
90
  mark_tls_nogo (host, cb) {
92
- const obtls = this;
93
91
  const dbkey = `no_tls|${host}`;
94
- const expiry = obtls.cfg.redis.disable_expiry || 604800;
92
+ const expiry = this.cfg.redis.disable_expiry || 604800;
95
93
 
96
- if (!obtls.cfg.redis.disable_for_failed_hosts) return cb();
94
+ if (!this.cfg.redis.disable_for_failed_hosts) return cb();
97
95
 
98
- logger.lognotice(obtls, `TLS connection failed. Marking ${host} as non-TLS for ${expiry} seconds`);
96
+ logger.lognotice(this, `TLS connection failed. Marking ${host} as non-TLS for ${expiry} seconds`);
99
97
 
100
- obtls.db.setex(dbkey, expiry, (new Date()).toISOString(), (err, dbr) => {
101
- if (err) logger.logerror(obtls, `Redis returned error: ${err}`);
102
- cb();
103
- });
98
+ this.db.setex(dbkey, expiry, (new Date()).toISOString())
99
+ .then(cb)
100
+ .catch(err => {
101
+ logger.logerror(this, `Redis returned error: ${err}`);
102
+ })
104
103
  }
105
104
  }
106
105
 
package/outbound/todo.js CHANGED
@@ -10,6 +10,7 @@ class TODOItem {
10
10
  this.message_stream = transaction.message_stream;
11
11
  this.notes = transaction.notes;
12
12
  this.uuid = transaction.uuid;
13
+ this.force_tls = false;
13
14
  }
14
15
  }
15
16
 
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "server",
10
10
  "email"
11
11
  ],
12
- "version": "2.8.28",
12
+ "version": "3.0.1",
13
13
  "homepage": "http://haraka.github.io",
14
14
  "repository": {
15
15
  "type": "git",
@@ -17,64 +17,68 @@
17
17
  },
18
18
  "main": "haraka.js",
19
19
  "engines": {
20
- "node": ">=12.22.6"
20
+ "node": ">=16"
21
21
  },
22
22
  "dependencies": {
23
- "address-rfc2821" : "^2.0.1",
24
- "address-rfc2822" : "^2.1.0",
25
- "async" : "~3.2.1",
26
- "daemon" : "~1.1.0",
27
- "generic-pool" : "~2.5.4",
28
- "iconv" : "~3.0.1",
29
- "ipaddr.js" : "~2.0.1",
30
- "libqp" : "^1.1.0",
31
- "libmime" : "^5.0.0",
32
- "nopt" : "~5.0.0",
33
- "npid" : "~0.4.0",
34
- "semver" : "~7.3.5",
35
- "sprintf-js" : "~1.1.2",
36
- "haraka-config" : "^1.0.20",
37
- "haraka-constants" : "^1.0.5",
38
- "haraka-dsn" : "^1.0.3",
39
- "haraka-net-utils" : "^1.3.1",
40
- "haraka-notes" : "^1.0.4",
41
- "haraka-plugin-redis" : "^1.0.13",
42
- "haraka-results" : "^2.1.0",
43
- "haraka-tld" : "^1.0.28",
44
- "haraka-utils" : "^1.0.2",
45
- "openssl-wrapper" : "^0.3.4",
46
- "sockaddr" : "^1.0.1"
23
+ "address-rfc2821": "^2.0.1",
24
+ "address-rfc2822": "^2.1.0",
25
+ "async": "^3.2.4",
26
+ "daemon": "~1.1.0",
27
+ "ipaddr.js": "~2.0.1",
28
+ "node-gyp": "^9.3.1",
29
+ "nopt": "~7.0.0",
30
+ "npid": "~0.4.0",
31
+ "semver": "~7.3.8",
32
+ "sprintf-js": "~1.1.2",
33
+ "haraka-config": "^1.1.0",
34
+ "haraka-constants": "^1.0.6",
35
+ "haraka-dsn": "^1.0.4",
36
+ "haraka-email-message": "^1.2.0",
37
+ "haraka-message-stream": "^1.2.0",
38
+ "haraka-net-utils": "^1.5.0",
39
+ "haraka-notes": "^1.0.6",
40
+ "haraka-plugin-attachment": "^1.0.7",
41
+ "haraka-plugin-spf": "1.2.0",
42
+ "haraka-plugin-redis": "^2.0.5",
43
+ "haraka-results": "^2.2.2",
44
+ "haraka-tld": "^1.1.0",
45
+ "haraka-utils": "^1.0.3",
46
+ "openssl-wrapper": "^0.3.4",
47
+ "sockaddr": "^1.0.1"
47
48
  },
48
49
  "optionalDependencies": {
49
- "haraka-plugin-access" : "^1.1.4",
50
- "haraka-plugin-asn" : "^1.0.8",
50
+ "haraka-plugin-access": "^1.1.5",
51
+ "haraka-plugin-aliases": "^1.0.1",
52
+ "haraka-plugin-asn": "^2.0.1",
51
53
  "haraka-plugin-auth-ldap": "^1.0.2",
52
- "haraka-plugin-dcc" : "^1.0.1",
53
- "haraka-plugin-elasticsearch" : "^1.0.6",
54
- "haraka-plugin-fcrdns" : "^1.0.3",
55
- "haraka-plugin-graph" : "^1.0.3",
56
- "haraka-plugin-geoip" : "^1.0.15",
57
- "haraka-plugin-headers" : "^1.0.2",
58
- "haraka-plugin-karma" : "^1.0.13",
59
- "haraka-plugin-limit" : "^1.0.4",
60
- "haraka-plugin-p0f" : "^1.0.5",
61
- "haraka-plugin-qmail-deliverable" : "^1.0.5",
54
+ "haraka-plugin-dcc": "^1.0.1",
55
+ "haraka-plugin-elasticsearch": "^1.0.6",
56
+ "haraka-plugin-fcrdns": "^1.1.0",
57
+ "haraka-plugin-graph": "^1.0.5",
58
+ "haraka-plugin-geoip": "^1.0.17",
59
+ "haraka-plugin-headers": "^1.0.3",
60
+ "haraka-plugin-karma": "^2.1.0",
61
+ "haraka-plugin-limit": "^1.1.0",
62
+ "haraka-plugin-p0f": "^1.0.9",
63
+ "haraka-plugin-qmail-deliverable": "^1.1.1",
64
+ "haraka-plugin-known-senders": "^1.0.8",
62
65
  "haraka-plugin-rcpt-ldap": "^1.0.0",
63
- "haraka-plugin-recipient-routes" : "^1.0.2",
64
- "haraka-plugin-rspamd" : "^1.1.6",
65
- "haraka-plugin-syslog" : "^1.0.3",
66
- "haraka-plugin-watch" : "^1.0.15",
67
- "ocsp" : "~1.2.0",
68
- "redis" : "~3.1.2",
69
- "tmp" : "~0.2.1"
66
+ "haraka-plugin-recipient-routes": "^1.0.4",
67
+ "haraka-plugin-rspamd": "^1.2.0",
68
+ "haraka-plugin-syslog": "^1.0.3",
69
+ "haraka-plugin-uribl": "^1.0.6",
70
+ "haraka-plugin-watch": "^2.0.2",
71
+ "ocsp": "~1.2.0",
72
+ "redis": "~4.5.1",
73
+ "tmp": "~0.2.1"
70
74
  },
71
75
  "devDependencies": {
72
- "nodeunit-x" : "^0.15.0",
73
- "haraka-test-fixtures" : "^1.0.33",
74
- "mock-require" : "^3.0.3",
75
- "eslint" : "^8.0",
76
- "eslint-plugin-haraka" : "^1.0.14",
77
- "nodemailer" : "6.7.0"
76
+ "nodeunit-x": "^0.15.0",
77
+ "haraka-test-fixtures": "^1.2.1",
78
+ "mock-require": "^3.0.3",
79
+ "eslint": "^8.27.0",
80
+ "eslint-plugin-haraka": "^1.0.15",
81
+ "nodemailer": "^6.7.7"
78
82
  },
79
83
  "bugs": {
80
84
  "mail": "haraka.mail@gmail.com",
@@ -82,15 +86,13 @@
82
86
  },
83
87
  "bin": {
84
88
  "haraka": "./bin/haraka",
85
- "spf": "./bin/spf",
86
89
  "dkimverify": "./bin/dkimverify",
87
90
  "haraka_grep": "./bin/haraka_grep"
88
91
  },
89
92
  "scripts": {
90
93
  "test": "node run_tests",
91
- "lint": "npx eslint *.js outbound/*.js plugins/*.js plugins/*/*.js tests/*.js tests/*/*.js tests/*/*/*.js bin/haraka bin/spf bin/dkimverify",
92
- "lintfix": "npx eslint --fix *.js outbound/*.js plugins/*.js plugins/*/*.js tests/*.js tests/*/*.js tests/*/*/*.js bin/haraka bin/spf bin/dkimverify",
93
- "cover": "NODE_ENV=cov npx nyc --reporter=lcovonly npm run test",
94
+ "lint": "npx eslint *.js outbound plugins plugins/*/*.js tests tests/*/*.js tests/*/*/*.js bin/haraka bin/dkimverify",
95
+ "lintfix": "npx eslint --fix *.js outbound plugins plugins/*/*.js tests tests/*/*.js tests/*/*/*.js bin/haraka bin/dkimverify",
94
96
  "versions": "npx dependency-version-checker check"
95
97
  }
96
98
  }
@@ -27,31 +27,29 @@ exports.hook_capabilities = (next, connection) => {
27
27
  exports.get_plain_passwd = (user, connection, cb) => cb()
28
28
 
29
29
  exports.hook_unrecognized_command = function (next, connection, params) {
30
- const plugin = this;
31
30
  if (params[0].toUpperCase() === AUTH_COMMAND && params[1]) {
32
- return plugin.select_auth_method(next, connection,
33
- params.slice(1).join(' '));
31
+ return this.select_auth_method(next, connection, params.slice(1).join(' '));
34
32
  }
35
- if (!connection.notes.authenticating) { return next(); }
33
+ if (!connection.notes.authenticating) return next();
36
34
 
37
35
  const am = connection.notes.auth_method;
38
36
  if (am === AUTH_METHOD_CRAM_MD5 && connection.notes.auth_ticket) {
39
- return plugin.auth_cram_md5(next, connection, params);
37
+ return this.auth_cram_md5(next, connection, params);
40
38
  }
41
39
  if (am === AUTH_METHOD_LOGIN) {
42
- return plugin.auth_login(next, connection, params);
40
+ return this.auth_login(next, connection, params);
43
41
  }
44
42
  if (am === AUTH_METHOD_PLAIN) {
45
- return plugin.auth_plain(next, connection, params);
43
+ return this.auth_plain(next, connection, params);
46
44
  }
47
- return next();
45
+ next();
48
46
  }
49
47
 
50
48
  exports.check_plain_passwd = function (connection, user, passwd, cb) {
51
49
  function callback (plain_pw) {
52
- if (plain_pw === null ) { return cb(false); }
53
- if (plain_pw !== passwd) { return cb(false); }
54
- return cb(true);
50
+ if (plain_pw === null ) return cb(false);
51
+ if (plain_pw !== passwd) return cb(false);
52
+ cb(true);
55
53
  }
56
54
  if (this.get_plain_passwd.length == 2) {
57
55
  this.get_plain_passwd(user, callback);
@@ -66,16 +64,13 @@ exports.check_plain_passwd = function (connection, user, passwd, cb) {
66
64
 
67
65
  exports.check_cram_md5_passwd = function (connection, user, passwd, cb) {
68
66
  function callback (plain_pw) {
69
- if (plain_pw == null) {
70
- return cb(false);
71
- }
67
+ if (plain_pw == null) return cb(false);
72
68
 
73
69
  const hmac = crypto.createHmac('md5', plain_pw.toString());
74
70
  hmac.update(connection.notes.auth_ticket);
75
71
 
76
- if (hmac.digest('hex') === passwd) {
77
- return cb(true);
78
- }
72
+ if (hmac.digest('hex') === passwd) return cb(true);
73
+
79
74
  return cb(false);
80
75
  }
81
76
  if (this.get_plain_passwd.length == 2) {
@@ -127,9 +122,8 @@ exports.check_user = function (next, connection, credentials, method) {
127
122
  return;
128
123
  }
129
124
 
130
- if (!connection.notes.auth_fails) {
131
- connection.notes.auth_fails = 0;
132
- }
125
+ if (!connection.notes.auth_fails) connection.notes.auth_fails = 0;
126
+
133
127
  connection.notes.auth_fails++;
134
128
  connection.results.add({name: 'auth'}, {
135
129
  fail:`${plugin.name}/${method}`,
@@ -150,12 +144,10 @@ exports.check_user = function (next, connection, credentials, method) {
150
144
  }
151
145
 
152
146
  if (method === AUTH_METHOD_PLAIN || method === AUTH_METHOD_LOGIN) {
153
- plugin.check_plain_passwd(connection, credentials[0], credentials[1],
154
- passwd_ok);
147
+ plugin.check_plain_passwd(connection, credentials[0], credentials[1], passwd_ok);
155
148
  }
156
149
  else if (method === AUTH_METHOD_CRAM_MD5) {
157
- plugin.check_cram_md5_passwd(connection, credentials[0], credentials[1],
158
- passwd_ok);
150
+ plugin.check_cram_md5_passwd(connection, credentials[0], credentials[1], passwd_ok);
159
151
  }
160
152
  }
161
153
 
@@ -163,28 +155,19 @@ exports.select_auth_method = function (next, connection, method) {
163
155
  const split = method.split(/\s+/);
164
156
  method = split.shift().toUpperCase();
165
157
  if (!connection.notes.allowed_auth_methods) return next();
166
- if (!connection.notes.allowed_auth_methods.includes(method)) {
167
- return next();
168
- }
158
+ if (!connection.notes.allowed_auth_methods.includes(method)) return next();
169
159
 
170
160
  if (connection.notes.authenticating) return next(DENYDISCONNECT, 'bad protocol');
171
161
 
172
162
  connection.notes.authenticating = true;
173
163
  connection.notes.auth_method = method;
174
164
 
175
- if (method === AUTH_METHOD_PLAIN) {
176
- return this.auth_plain(next, connection, split);
177
- }
178
- if (method === AUTH_METHOD_LOGIN) {
179
- return this.auth_login(next, connection, split);
180
- }
181
- if (method === AUTH_METHOD_CRAM_MD5) {
182
- return this.auth_cram_md5(next, connection);
183
- }
165
+ if (method === AUTH_METHOD_PLAIN) return this.auth_plain(next, connection, split);
166
+ if (method === AUTH_METHOD_LOGIN) return this.auth_login(next, connection, split);
167
+ if (method === AUTH_METHOD_CRAM_MD5) return this.auth_cram_md5(next, connection);
184
168
  }
185
169
 
186
170
  exports.auth_plain = function (next, connection, params) {
187
- const plugin = this;
188
171
  // one parameter given on line, either:
189
172
  // AUTH PLAIN <param> or
190
173
  // AUTH PLAIN\n
@@ -193,36 +176,32 @@ exports.auth_plain = function (next, connection, params) {
193
176
  if (params[0]) {
194
177
  const credentials = utils.unbase64(params[0]).split(/\0/);
195
178
  credentials.shift(); // Discard authid
196
- return plugin.check_user(next, connection, credentials, AUTH_METHOD_PLAIN);
179
+ this.check_user(next, connection, credentials, AUTH_METHOD_PLAIN);
180
+ return
197
181
  }
198
- else {
199
- if (connection.notes.auth_plain_asked_login) {
200
- return next(DENYDISCONNECT, 'bad protocol');
201
- }
202
- else {
203
- connection.respond(334, ' ', () => {
204
- connection.notes.auth_plain_asked_login = true;
205
- return next(OK);
206
- });
207
- return;
208
- }
182
+
183
+ if (connection.notes.auth_plain_asked_login) {
184
+ return next(DENYDISCONNECT, 'bad protocol');
209
185
  }
186
+
187
+ connection.respond(334, ' ', () => {
188
+ connection.notes.auth_plain_asked_login = true;
189
+ next(OK);
190
+ });
210
191
  }
211
192
 
212
193
  exports.auth_login = function (next, connection, params) {
213
- const plugin = this;
214
194
  if ((!connection.notes.auth_login_asked_login && params[0]) ||
215
195
  ( connection.notes.auth_login_asked_login &&
216
196
  !connection.notes.auth_login_userlogin)) {
217
- if (!params[0]){
218
- return next(DENYDISCONNECT, 'bad protocol');
219
- }
197
+
198
+ if (!params[0]) return next(DENYDISCONNECT, 'bad protocol');
220
199
 
221
200
  const login = utils.unbase64(params[0]);
222
201
  connection.respond(334, LOGIN_STRING2, () => {
223
202
  connection.notes.auth_login_userlogin = login;
224
203
  connection.notes.auth_login_asked_login = true;
225
- return next(OK);
204
+ next(OK);
226
205
  });
227
206
  return;
228
207
  }
@@ -236,30 +215,27 @@ exports.auth_login = function (next, connection, params) {
236
215
  connection.notes.auth_login_userlogin = null;
237
216
  connection.notes.auth_login_asked_login = false;
238
217
 
239
- return plugin.check_user(next, connection, credentials,
240
- AUTH_METHOD_LOGIN);
218
+ return this.check_user(next, connection, credentials, AUTH_METHOD_LOGIN);
241
219
  }
242
220
 
243
221
  connection.respond(334, LOGIN_STRING1, () => {
244
222
  connection.notes.auth_login_asked_login = true;
245
- return next(OK);
223
+ next(OK);
246
224
  });
247
225
  }
248
226
 
249
227
  exports.auth_cram_md5 = function (next, connection, params) {
250
- const plugin = this;
251
228
  if (params) {
252
229
  const credentials = utils.unbase64(params[0]).split(' ');
253
- return plugin.check_user(next, connection, credentials,
254
- AUTH_METHOD_CRAM_MD5);
230
+ return this.check_user(next, connection, credentials, AUTH_METHOD_CRAM_MD5);
255
231
  }
256
232
 
257
- const ticket = `<${plugin.hexi(Math.floor(Math.random() * 1000000))}. ${plugin.hexi(Date.now())}@${connection.local.host}>`;
233
+ const ticket = `<${this.hexi(Math.floor(Math.random() * 1000000))}. ${this.hexi(Date.now())}@${connection.local.host}>`;
258
234
 
259
- connection.loginfo(plugin, `ticket: ${ticket}`);
235
+ connection.loginfo(this, `ticket: ${ticket}`);
260
236
  connection.respond(334, utils.base64(ticket), () => {
261
237
  connection.notes.auth_ticket = ticket;
262
- return next(OK);
238
+ next(OK);
263
239
  });
264
240
  }
265
241
 
@@ -6,14 +6,13 @@ exports.register = function () {
6
6
  }
7
7
 
8
8
  exports.load_flat_ini = function () {
9
- const plugin = this;
10
- plugin.cfg = plugin.config.get('smtp_bridge.ini', () => {
11
- plugin.load_flat_ini();
9
+ this.cfg = this.config.get('smtp_bridge.ini', () => {
10
+ this.load_flat_ini();
12
11
  });
13
12
  }
14
13
 
15
14
  exports.check_plain_passwd = function (connection, user, passwd, cb) {
16
- let host = this.cfg.main.host;
15
+ let { host } = this.cfg.main;
17
16
  if (this.cfg.main.port) {
18
17
  host = `${host}:${this.cfg.main.port}`;
19
18
  }
@@ -1,18 +1,18 @@
1
1
  // Proxy AUTH requests selectively by domain
2
+
2
3
  const sock = require('./line_socket');
3
4
  const utils = require('haraka-utils');
4
- const smtp_regexp = /^([0-9]{3})([ -])(.*)/;
5
+
6
+ const smtp_regexp = /^(\d{3})([ -])(.*)/;
5
7
 
6
8
  exports.register = function () {
7
- const plugin = this;
8
- plugin.inherits('auth/auth_base');
9
- plugin.load_tls_ini();
9
+ this.inherits('auth/auth_base');
10
+ this.load_tls_ini();
10
11
  }
11
12
 
12
13
  exports.load_tls_ini = function () {
13
- const plugin = this;
14
- plugin.tls_cfg = plugin.config.get('tls.ini', () => {
15
- plugin.load_tls_ini();
14
+ this.tls_cfg = this.config.get('tls.ini', () => {
15
+ this.load_tls_ini();
16
16
  });
17
17
  }
18
18
 
@@ -27,8 +27,8 @@ exports.hook_capabilities = (next, connection) => {
27
27
  }
28
28
 
29
29
  exports.check_plain_passwd = function (connection, user, passwd, cb) {
30
- let domain;
31
- if ((domain = /@([^@]+)$/.exec(user))) {
30
+ let domain = /@([^@]+)$/.exec(user);
31
+ if (domain) {
32
32
  domain = domain[1].toLowerCase();
33
33
  }
34
34
  else {
@@ -84,7 +84,6 @@ exports.try_auth_proxy = function (connection, hosts, user, passwd, cb) {
84
84
  socket.on('error', err => {
85
85
  connection.logerror(self, `connection failed to host ${host}: ${err}`);
86
86
  socket.end();
87
- return;
88
87
  });
89
88
  socket.send_command = function (cmd, data) {
90
89
  let line = cmd + (data ? (` ${data}`) : '');
@@ -117,7 +116,7 @@ exports.try_auth_proxy = function (connection, hosts, user, passwd, cb) {
117
116
 
118
117
  connection.logdebug(self, `command state: ${command}`);
119
118
  if (command === 'ehlo') {
120
- if (code[0] === '5') {
119
+ if (code.startsWith('5')) {
121
120
  // EHLO command rejected; abort
122
121
  socket.send_command('QUIT');
123
122
  return;
@@ -131,6 +130,7 @@ exports.try_auth_proxy = function (connection, hosts, user, passwd, cb) {
131
130
  cert = self.config.get(self.tls_cfg.main.cert || 'tls_cert.pem', 'binary');
132
131
  if (key && cert) {
133
132
  this.on('secure', () => {
133
+ if (secure) return;
134
134
  secure = true;
135
135
  socket.send_command('EHLO', connection.local.host);
136
136
  });
@@ -163,21 +163,21 @@ exports.try_auth_proxy = function (connection, hosts, user, passwd, cb) {
163
163
  }
164
164
  if (command === 'auth') {
165
165
  // Handle LOGIN
166
- if (code[0] === '3' && response[0] === 'VXNlcm5hbWU6') {
166
+ if (code.startsWith('3') && response[0] === 'VXNlcm5hbWU6') {
167
167
  // Write to the socket directly to keep the state at 'auth'
168
168
  this.write(`${utils.base64(user)}\r\n`);
169
169
  response = [];
170
170
  return;
171
171
  }
172
- else if (code[0] === '3' && response[0] === 'UGFzc3dvcmQ6') {
172
+ else if (code.startsWith('3') && response[0] === 'UGFzc3dvcmQ6') {
173
173
  this.write(`${utils.base64(passwd)}\r\n`);
174
174
  response = [];
175
175
  return;
176
176
  }
177
- if (code[0] === '5') {
177
+ if (code.startsWith('5')) {
178
178
  // Initial attempt failed; strip domain and retry.
179
- let u;
180
- if ((u = /^([^@]+)@.+$/.exec(user))) {
179
+ const u = /^([^@]+)@.+$/.exec(user)
180
+ if (u) {
181
181
  user = u[1];
182
182
  if (methods.includes('PLAIN')) {
183
183
  socket.send_command('AUTH', `PLAIN ${utils.base64(`\0${user}\0${passwd}`)}`);