Haraka 3.0.2 → 3.0.4

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 (267) hide show
  1. package/.eslintrc.yaml +5 -9
  2. package/.prettierrc.yml +1 -0
  3. package/CONTRIBUTORS.md +11 -0
  4. package/Changes.md +1393 -1211
  5. package/Dockerfile +3 -3
  6. package/Plugins.md +119 -106
  7. package/README.md +7 -16
  8. package/TODO +1 -24
  9. package/bin/haraka +197 -298
  10. package/config/auth_flat_file.ini +2 -0
  11. package/config/auth_vpopmaild.ini +4 -2
  12. package/config/dhparams.pem +8 -0
  13. package/config/mail_from.is_resolvable.ini +4 -2
  14. package/config/me +1 -0
  15. package/config/outbound.ini +0 -2
  16. package/config/plugins +36 -35
  17. package/config/rabbitmq_amqplib.ini +8 -1
  18. package/config/smtp.ini +0 -1
  19. package/config/smtp.json +17 -0
  20. package/config/tls_cert.pem +23 -0
  21. package/config/tls_key.pem +28 -0
  22. package/connection.js +46 -73
  23. package/contrib/bsd-rc.d/haraka +3 -1
  24. package/contrib/plugin2npm.sh +6 -36
  25. package/docs/Connection.md +1 -1
  26. package/docs/CoreConfig.md +2 -2
  27. package/docs/Logging.md +7 -21
  28. package/docs/Outbound.md +104 -210
  29. package/docs/Plugins.md +47 -40
  30. package/docs/Transaction.md +59 -82
  31. package/docs/{plugins → deprecated}/connect.rdns_access.md +1 -1
  32. package/docs/{plugins → deprecated}/mail_from.access.md +1 -1
  33. package/docs/{plugins → deprecated}/rcpt_to.access.md +1 -1
  34. package/docs/plugins/auth/auth_vpopmaild.md +15 -19
  35. package/docs/plugins/auth/flat_file.md +23 -30
  36. package/docs/plugins/queue/rabbitmq_amqplib.md +7 -0
  37. package/docs/plugins/queue/smtp_forward.md +1 -1
  38. package/docs/plugins/queue/smtp_proxy.md +5 -10
  39. package/docs/plugins/relay.md +2 -2
  40. package/docs/plugins/tls.md +29 -9
  41. package/endpoint.js +16 -13
  42. package/haraka.js +10 -14
  43. package/host_pool.js +5 -5
  44. package/line_socket.js +3 -4
  45. package/logger.js +44 -28
  46. package/outbound/client_pool.js +27 -23
  47. package/outbound/config.js +4 -6
  48. package/outbound/fsync_writestream.js +1 -1
  49. package/outbound/hmail.js +180 -220
  50. package/outbound/index.js +86 -99
  51. package/outbound/qfile.js +1 -1
  52. package/outbound/queue.js +55 -43
  53. package/outbound/timer_queue.js +3 -2
  54. package/outbound/tls.js +19 -7
  55. package/package.json +66 -55
  56. package/plugins/.eslintrc.yaml +0 -6
  57. package/plugins/auth/auth_base.js +30 -12
  58. package/plugins/auth/auth_proxy.js +14 -12
  59. package/plugins/auth/auth_vpopmaild.js +30 -20
  60. package/plugins/auth/flat_file.js +17 -12
  61. package/plugins/block_me.js +1 -1
  62. package/plugins/data.signatures.js +2 -4
  63. package/plugins/early_talker.js +2 -1
  64. package/plugins/mail_from.is_resolvable.js +65 -135
  65. package/plugins/queue/deliver.js +4 -5
  66. package/plugins/queue/lmtp.js +11 -14
  67. package/plugins/queue/qmail-queue.js +2 -2
  68. package/plugins/queue/quarantine.js +2 -2
  69. package/plugins/queue/rabbitmq.js +16 -17
  70. package/plugins/queue/rabbitmq_amqplib.js +1 -1
  71. package/plugins/queue/smtp_forward.js +6 -6
  72. package/plugins/queue/smtp_proxy.js +10 -1
  73. package/plugins/queue/test.js +2 -2
  74. package/plugins/rcpt_to.host_list_base.js +5 -5
  75. package/plugins/rcpt_to.in_host_list.js +2 -2
  76. package/plugins/relay.js +6 -7
  77. package/plugins/reseed_rng.js +1 -1
  78. package/plugins/status.js +37 -33
  79. package/plugins/tls.js +2 -2
  80. package/plugins/xclient.js +3 -2
  81. package/plugins.js +51 -54
  82. package/run_tests +3 -30
  83. package/server.js +190 -190
  84. package/smtp_client.js +30 -23
  85. package/{tests → test}/config/plugins +0 -2
  86. package/{tests → test}/config/smtp.ini +1 -1
  87. package/test/config/tls/example.com/_.example.com.key +28 -0
  88. package/test/config/tls/example.com/example.com.crt +25 -0
  89. package/test/connection.js +302 -0
  90. package/test/endpoint.js +94 -0
  91. package/{tests → test}/fixtures/line_socket.js +1 -1
  92. package/{tests → test}/fixtures/util_hmailitem.js +19 -25
  93. package/{tests → test}/host_pool.js +42 -57
  94. package/test/logger.js +258 -0
  95. package/test/outbound/hmail.js +141 -0
  96. package/test/outbound/index.js +220 -0
  97. package/test/outbound/qfile.js +126 -0
  98. package/test/outbound_bounce_net_errors.js +142 -0
  99. package/{tests → test}/outbound_bounce_rfc3464.js +110 -122
  100. package/test/plugins/auth/auth_base.js +484 -0
  101. package/test/plugins/auth/auth_vpopmaild.js +83 -0
  102. package/test/plugins/early_talker.js +104 -0
  103. package/test/plugins/mail_from.is_resolvable.js +35 -0
  104. package/test/plugins/queue/smtp_forward.js +206 -0
  105. package/test/plugins/rcpt_to.host_list_base.js +122 -0
  106. package/test/plugins/rcpt_to.in_host_list.js +193 -0
  107. package/test/plugins/relay.js +303 -0
  108. package/test/plugins/status.js +130 -0
  109. package/test/plugins/tls.js +70 -0
  110. package/test/plugins.js +228 -0
  111. package/{tests → test}/queue/multibyte +0 -0
  112. package/{tests → test}/queue/plain +0 -0
  113. package/test/rfc1869.js +73 -0
  114. package/test/server.js +491 -0
  115. package/test/smtp_client.js +299 -0
  116. package/test/tls_socket.js +273 -0
  117. package/test/transaction.js +270 -0
  118. package/tls_socket.js +202 -252
  119. package/transaction.js +9 -24
  120. package/CONTRIBUTING.md +0 -1
  121. package/bin/dkimverify +0 -40
  122. package/config/access.domains +0 -13
  123. package/config/attachment.ctype.regex +0 -2
  124. package/config/attachment.filename.regex +0 -1
  125. package/config/avg.ini +0 -5
  126. package/config/bounce.ini +0 -15
  127. package/config/data.headers.ini +0 -61
  128. package/config/dkim/dkim_key_gen.sh +0 -78
  129. package/config/dkim_sign.ini +0 -4
  130. package/config/dkim_verify.ini +0 -7
  131. package/config/dnsbl.ini +0 -23
  132. package/config/greylist.ini +0 -43
  133. package/config/helo.checks.ini +0 -52
  134. package/config/lookup_rdns.strict.ini +0 -12
  135. package/config/lookup_rdns.strict.timeout +0 -1
  136. package/config/lookup_rdns.strict.whitelist +0 -1
  137. package/config/lookup_rdns.strict.whitelist_regex +0 -5
  138. package/config/messagesniffer.ini +0 -18
  139. package/config/rcpt_to.blocklist +0 -1
  140. package/config/rdns.allow_regexps +0 -0
  141. package/config/rdns.deny_regexps +0 -0
  142. package/config/spamassassin.ini +0 -56
  143. package/config.js +0 -6
  144. package/dkim.js +0 -614
  145. package/docs/plugins/avg.md +0 -35
  146. package/docs/plugins/bounce.md +0 -69
  147. package/docs/plugins/clamd.md +0 -147
  148. package/docs/plugins/esets.md +0 -8
  149. package/docs/plugins/greylist.md +0 -90
  150. package/docs/plugins/helo.checks.md +0 -135
  151. package/docs/plugins/messagesniffer.md +0 -163
  152. package/docs/plugins/relay_acl.md +0 -29
  153. package/docs/plugins/relay_all.md +0 -15
  154. package/docs/plugins/relay_force_routing.md +0 -33
  155. package/docs/plugins/spamassassin.md +0 -180
  156. package/outbound/mx_lookup.js +0 -70
  157. package/plugins/auth/auth_ldap.js +0 -3
  158. package/plugins/avg.js +0 -162
  159. package/plugins/backscatterer.js +0 -25
  160. package/plugins/bounce.js +0 -381
  161. package/plugins/clamd.js +0 -381
  162. package/plugins/data.headers.js +0 -4
  163. package/plugins/data.uribl.js +0 -4
  164. package/plugins/dkim_sign.js +0 -395
  165. package/plugins/dkim_verify.js +0 -62
  166. package/plugins/dns_list_base.js +0 -221
  167. package/plugins/dnsbl.js +0 -146
  168. package/plugins/dnswl.js +0 -58
  169. package/plugins/esets.js +0 -71
  170. package/plugins/graph.js +0 -5
  171. package/plugins/greylist.js +0 -645
  172. package/plugins/helo.checks.js +0 -533
  173. package/plugins/messagesniffer.js +0 -381
  174. package/plugins/rcpt_to.ldap.js +0 -3
  175. package/plugins/rcpt_to.max_count.js +0 -24
  176. package/plugins/relay_all.js +0 -13
  177. package/plugins/spamassassin.js +0 -384
  178. package/tests/config/dkim/example.com/dns +0 -29
  179. package/tests/config/dkim/example.com/private +0 -6
  180. package/tests/config/dkim/example.com/public +0 -4
  181. package/tests/config/dkim/example.com/selector +0 -1
  182. package/tests/config/dkim.private.key +0 -6
  183. package/tests/config/dkim_sign.ini +0 -4
  184. package/tests/config/helo.checks.ini +0 -52
  185. package/tests/connection.js +0 -327
  186. package/tests/endpoint.js +0 -128
  187. package/tests/fixtures/vm_harness.js +0 -59
  188. package/tests/logger.js +0 -327
  189. package/tests/outbound/hmail.js +0 -112
  190. package/tests/outbound/index.js +0 -324
  191. package/tests/outbound/qfile.js +0 -67
  192. package/tests/outbound_bounce_net_errors.js +0 -173
  193. package/tests/plugins/auth/auth_base.js +0 -463
  194. package/tests/plugins/auth/auth_vpopmaild.js +0 -91
  195. package/tests/plugins/bounce.js +0 -307
  196. package/tests/plugins/clamd.js +0 -224
  197. package/tests/plugins/deprecated/relay_acl.js +0 -140
  198. package/tests/plugins/deprecated/relay_all.js +0 -59
  199. package/tests/plugins/dkim_sign.js +0 -315
  200. package/tests/plugins/dkim_signer.js +0 -108
  201. package/tests/plugins/dns_list_base.js +0 -259
  202. package/tests/plugins/dnsbl.js +0 -101
  203. package/tests/plugins/early_talker.js +0 -115
  204. package/tests/plugins/greylist.js +0 -58
  205. package/tests/plugins/helo.checks.js +0 -525
  206. package/tests/plugins/mail_from.is_resolvable.js +0 -116
  207. package/tests/plugins/queue/smtp_forward.js +0 -221
  208. package/tests/plugins/rcpt_to.host_list_base.js +0 -132
  209. package/tests/plugins/rcpt_to.in_host_list.js +0 -218
  210. package/tests/plugins/relay.js +0 -339
  211. package/tests/plugins/spamassassin.js +0 -171
  212. package/tests/plugins/status.js +0 -138
  213. package/tests/plugins/tls.js +0 -84
  214. package/tests/plugins.js +0 -247
  215. package/tests/rfc1869.js +0 -61
  216. package/tests/server.js +0 -510
  217. package/tests/smtp_client/auth.js +0 -105
  218. package/tests/smtp_client/basic.js +0 -101
  219. package/tests/smtp_client.js +0 -80
  220. package/tests/tls_socket.js +0 -333
  221. package/tests/transaction.js +0 -284
  222. /package/docs/{plugins → deprecated}/dkim_sign.md +0 -0
  223. /package/docs/{plugins → deprecated}/dkim_verify.md +0 -0
  224. /package/docs/{plugins → deprecated}/dnsbl.md +0 -0
  225. /package/docs/{plugins → deprecated}/dnswl.md +0 -0
  226. /package/docs/{plugins → deprecated}/rcpt_to.routes.md +0 -0
  227. /package/{tests → test}/.eslintrc.yaml +0 -0
  228. /package/{tests → test}/config/auth_flat_file.ini +0 -0
  229. /package/{tests → test}/config/dhparams.pem +0 -0
  230. /package/{tests → test}/config/host_list +0 -0
  231. /package/{tests → test}/config/outbound_tls_cert.pem +0 -0
  232. /package/{tests → test}/config/outbound_tls_key.pem +0 -0
  233. /package/{tests → test}/config/smtp_forward.ini +0 -0
  234. /package/{tests → test}/config/tls/ec.pem +0 -0
  235. /package/{tests → test}/config/tls/haraka.local.pem +0 -0
  236. /package/{tests → test}/config/tls/mismatched.pem +0 -0
  237. /package/{tests → test}/config/tls.ini +0 -0
  238. /package/{tests → test}/config/tls_cert.pem +0 -0
  239. /package/{tests → test}/config/tls_key.pem +0 -0
  240. /package/{tests → test}/fixtures/todo_qfile.txt +0 -0
  241. /package/{tests → test}/installation/config/test-plugin-flat +0 -0
  242. /package/{tests → test}/installation/config/test-plugin.ini +0 -0
  243. /package/{tests → test}/installation/config/tls.ini +0 -0
  244. /package/{tests → test}/installation/node_modules/load_first/index.js +0 -0
  245. /package/{tests → test}/installation/node_modules/load_first/package.json +0 -0
  246. /package/{tests → test}/installation/node_modules/test-plugin/config/test-plugin-flat +0 -0
  247. /package/{tests → test}/installation/node_modules/test-plugin/config/test-plugin.ini +0 -0
  248. /package/{tests → test}/installation/node_modules/test-plugin/package.json +0 -0
  249. /package/{tests → test}/installation/node_modules/test-plugin/test-plugin.js +0 -0
  250. /package/{tests → test}/installation/plugins/base_plugin.js +0 -0
  251. /package/{tests → test}/installation/plugins/folder_plugin/index.js +0 -0
  252. /package/{tests → test}/installation/plugins/folder_plugin/package.json +0 -0
  253. /package/{tests → test}/installation/plugins/inherits.js +0 -0
  254. /package/{tests → test}/installation/plugins/load_first.js +0 -0
  255. /package/{tests → test}/installation/plugins/plugin.js +0 -0
  256. /package/{tests → test}/installation/plugins/tls.js +0 -0
  257. /package/{tests → test}/loud/config/dhparams.pem +0 -0
  258. /package/{tests → test}/loud/config/tls/goobered.pem +0 -0
  259. /package/{tests → test}/loud/config/tls.ini +0 -0
  260. /package/{tests → test}/mail_specimen/base64-root-part.txt +0 -0
  261. /package/{tests → test}/mail_specimen/varied-fold-lengths-preserve-data.txt +0 -0
  262. /package/{tests → test}/queue/1507509981169_1507509981169_0_61403_e0Y0Ym_1_fixed +0 -0
  263. /package/{tests → test}/queue/1507509981169_1507509981169_0_61403_e0Y0Ym_1_haraka +0 -0
  264. /package/{tests → test}/queue/1508269674999_1508269674999_0_34002_socVUF_1_haraka +0 -0
  265. /package/{tests → test}/queue/1508455115683_1508455115683_0_90253_9Q4o4V_1_haraka +0 -0
  266. /package/{tests → test}/queue/zero-length +0 -0
  267. /package/{tests → test}/test-queue/delete-me +0 -0
package/smtp_client.js CHANGED
@@ -7,18 +7,15 @@
7
7
  // than a bunch of connections to a single host from the configuration values
8
8
  // in "host" and "port" (see host_pool.js).
9
9
 
10
- // node.js builtins
11
- const events = require('events');
10
+ const events = require('node:events');
12
11
 
13
- // npm deps
14
- const ipaddr = require('ipaddr.js');
15
- const net_utils = require('haraka-net-utils');
16
- const utils = require('haraka-utils');
12
+ const ipaddr = require('ipaddr.js');
13
+ const net_utils = require('haraka-net-utils');
14
+ const utils = require('haraka-utils');
17
15
 
18
- // haraka libs
19
- const line_socket = require('./line_socket');
20
- const logger = require('./logger');
21
- const HostPool = require('./host_pool');
16
+ const tls_socket = require('./tls_socket')
17
+ const logger = require('./logger');
18
+ const HostPool = require('./host_pool');
22
19
 
23
20
  const smtp_regexp = /^(\d{3})([ -])(.*)/;
24
21
  const STATE = {
@@ -33,7 +30,7 @@ class SMTPClient extends events.EventEmitter {
33
30
  super();
34
31
  this.uuid = utils.uuid();
35
32
  this.connect_timeout = parseInt(opts.connect_timeout) || 30;
36
- this.socket = opts.socket || line_socket.connect(opts.port, opts.host);
33
+ this.socket = opts.socket || this.get_socket(opts)
37
34
  this.socket.setTimeout(this.connect_timeout * 1000);
38
35
  this.socket.setKeepAlive(true);
39
36
  this.state = STATE.IDLE;
@@ -66,7 +63,7 @@ class SMTPClient extends events.EventEmitter {
66
63
  if (cont !== ' ') return;
67
64
 
68
65
  if (client.command === 'auth' || client.authenticating) {
69
- logger.loginfo(`SERVER RESPONSE, CLIENT ${client.command}, authenticating=${client.authenticating},code=${code},cont=${cont},msg=${msg}`);
66
+ logger.info(`SERVER RESPONSE, CLIENT ${client.command}, authenticating=${client.authenticating},code=${code},cont=${cont},msg=${msg}`);
70
67
  if (/^3/.test(code) && (
71
68
  msg === 'VXNlcm5hbWU6' ||
72
69
  msg === 'dXNlcm5hbWU6' // Workaround ill-mannered SMTP servers (namely smtp.163.com)
@@ -79,7 +76,7 @@ class SMTPClient extends events.EventEmitter {
79
76
  return;
80
77
  }
81
78
  if (/^2/.test(code) && client.authenticating) {
82
- logger.loginfo('AUTHENTICATED');
79
+ logger.info('AUTHENTICATED');
83
80
  client.authenticating = false;
84
81
  client.authenticated = true;
85
82
  client.emit('auth');
@@ -155,7 +152,7 @@ class SMTPClient extends events.EventEmitter {
155
152
  client.socket.setTimeout((opts.idle_timeout || 300) * 1000);
156
153
  if (!client.socket.remoteAddress) {
157
154
  // "Value may be undefined if the socket is destroyed"
158
- logger.logdebug('socket.remoteAddress undefined');
155
+ logger.debug('socket.remoteAddress undefined');
159
156
  return;
160
157
  }
161
158
  client.remote_ip = ipaddr.process(client.socket.remoteAddress).toString();
@@ -184,7 +181,7 @@ class SMTPClient extends events.EventEmitter {
184
181
  default:
185
182
  }
186
183
 
187
- logger.logdebug(`[smtp_client] ${errMsg} (state=${client.state})`);
184
+ logger.debug(`[smtp_client] ${errMsg} (state=${client.state})`);
188
185
  }
189
186
  }
190
187
 
@@ -220,7 +217,7 @@ class SMTPClient extends events.EventEmitter {
220
217
 
221
218
  release () {
222
219
  if (this.state === STATE.DESTROYED) return;
223
- logger.logdebug(`[smtp_client] ${this.uuid} releasing, state=${this.state}`);
220
+ logger.debug(`[smtp_client] ${this.uuid} releasing, state=${this.state}`);
224
221
 
225
222
  [
226
223
  'auth', 'bad_code', 'capabilities', 'client_protocol', 'connection-error',
@@ -243,7 +240,7 @@ class SMTPClient extends events.EventEmitter {
243
240
  upgrade (tls_options) {
244
241
 
245
242
  this.socket.upgrade(tls_options, (verified, verifyError, cert, cipher) => {
246
- logger.loginfo(`secured:${
243
+ logger.info(`secured:${
247
244
 
248
245
  (cipher) ? ` cipher=${cipher.name} version=${cipher.version}` : ''
249
246
  } verified=${verified}${
@@ -263,6 +260,16 @@ class SMTPClient extends events.EventEmitter {
263
260
  this.release();
264
261
  return true;
265
262
  }
263
+
264
+ get_socket(opts) {
265
+ const socket = tls_socket.connect({
266
+ host: opts.host,
267
+ port: opts.port,
268
+ timeout: this.connect_timeout,
269
+ })
270
+ net_utils.add_line_processor(socket)
271
+ return socket
272
+ }
266
273
  }
267
274
 
268
275
  exports.smtp_client = SMTPClient;
@@ -271,7 +278,7 @@ exports.smtp_client = SMTPClient;
271
278
  // used only in testing
272
279
  exports.get_client = (server, callback, opts = {}) => {
273
280
  const smtp_client = new SMTPClient(opts)
274
- logger.logdebug(`[smtp_client] uuid=${smtp_client.uuid} host=${opts.host} port=${opts.port} created`)
281
+ logger.debug(`[smtp_client] uuid=${smtp_client.uuid} host=${opts.host} port=${opts.port} created`)
275
282
  callback(smtp_client)
276
283
  }
277
284
 
@@ -336,7 +343,7 @@ exports.get_client_plugin = (plugin, connection, c, callback) => {
336
343
 
337
344
  const hostport = get_hostport(connection, connection.server, c);
338
345
  const smtp_client = new SMTPClient(hostport)
339
- logger.loginfo(`[smtp_client] uuid=${smtp_client.uuid} host=${hostport.host} port=${hostport.port} created`);
346
+ logger.info(`[smtp_client] uuid=${smtp_client.uuid} host=${hostport.host} port=${hostport.port} created`);
340
347
 
341
348
  connection.logdebug(plugin, `Got smtp_client: ${smtp_client.uuid}`);
342
349
 
@@ -400,7 +407,7 @@ exports.get_client_plugin = (plugin, connection, c, callback) => {
400
407
  if (!c.auth.user || !c.auth.pass) {
401
408
  throw new Error("Must include auth.user and auth.pass for PLAIN auth.");
402
409
  }
403
- logger.logdebug(`[smtp_client] uuid=${smtp_client.uuid} authenticating as "${c.auth.user}"`);
410
+ logger.debug(`[smtp_client] uuid=${smtp_client.uuid} authenticating as "${c.auth.user}"`);
404
411
  smtp_client.send_command('AUTH', `PLAIN ${utils.base64(`${c.auth.user}\0${c.auth.user}\0${c.auth.pass}`)}`);
405
412
  break;
406
413
  case 'cram-md5':
@@ -429,7 +436,7 @@ exports.get_client_plugin = (plugin, connection, c, callback) => {
429
436
  // these are the errors thrown when the connection is dead
430
437
  smtp_client.on('connection-error', (error) => {
431
438
  // error contains e.g. "Error: connect ECONNREFUSE"
432
- logger.logerror(`backend failure: ${smtp_client.host}:${smtp_client.port} - ${error}`);
439
+ logger.error(`backend failure: ${smtp_client.host}:${smtp_client.port} - ${error}`);
433
440
  const { host_pool } = connection.server.notes;
434
441
  // only exists for if forwarding_host_pool is set in the config
435
442
  if (host_pool) {
@@ -465,12 +472,12 @@ function get_hostport (connection, server, cfg) {
465
472
  const host = server.notes.host_pool.get_host();
466
473
  if (host) return host; // { host: 1.2.3.4, port: 567 }
467
474
 
468
- logger.logerror('[smtp_client] no backend hosts in pool!');
475
+ logger.error('[smtp_client] no backend hosts in pool!');
469
476
  throw new Error("no backend hosts found in pool!");
470
477
  }
471
478
 
472
479
  if (cfg.host && cfg.port) return { host: cfg.host, port: cfg.port };
473
480
 
474
- logger.logwarn("[smtp_client] forwarding_host_pool or host and port were not found in config file");
481
+ logger.warn("[smtp_client] forwarding_host_pool or host and port were not found in config file");
475
482
  throw new Error("You must specify either forwarding_host_pool or host and port");
476
483
  }
@@ -4,6 +4,4 @@ auth/flat_file
4
4
 
5
5
  rcpt_to.in_host_list
6
6
 
7
- dkim_verify
8
-
9
7
  queue/discard
@@ -6,4 +6,4 @@ nodes=0
6
6
 
7
7
  daemonize=false
8
8
 
9
- spool_dir=tests/tmp/queue
9
+ spool_dir=test/tmp/queue
@@ -0,0 +1,28 @@
1
+ -----BEGIN PRIVATE KEY-----
2
+ MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCYpxuOx4M2s6sI
3
+ iOEInjet7AcJddg/3uVoqoKRW6iTwAUKnP4CsU1Xe/rMU3wr/UcCs8zzFm7L6/cq
4
+ nbj2Pg1dnEvd5arYFWN59XhWjI6vua2ubZkTwBEEGSgSvwnBGU/9qdrXKTeuq+8C
5
+ BgV+SJzeEAmHEyhCDDT0M9Z1p5TFx0ynkaChy2yjffC2dbiRtK7RAja0I97MmSZL
6
+ ym+bVpY0ucTBNNwSNNh8UhWvWZSvVP92WGd2L72txCyfT333i0u1+SoexnJI7Wvn
7
+ 7YUaMNA3HSJ5/JjTW0/rOIZGyrfnjFEs5UmULCs6RZSE0eeEuJVRL+Kd+ncYCMlC
8
+ pmsqeIlHAgMBAAECggEAO0n8LBJVZjOWJDR1opFA8u4PNZ9tpDEATQyctbQx32Df
9
+ FGYxSf5vGaFvoVhzi+pNYEFRQsDdu5okX4ruwcUMD+Wamc6P8mksP7wVRxhEev/U
10
+ 80BiCge5FCxpIg7MzRD1voHwG01I8TCaHeEU1R2Cv8TeznWkVzLChm5zxzKVV9Mc
11
+ 08eqSxOg6M7wF3RpFpn1sBKch2ZNypu0IU4sP+NlRwxsRs/GBZqnyE/dmqvjHeCg
12
+ izcaji/ev8UdiYqASNZ2zzti9SME8VQebAWb71T6MMic03S9cfA+p3FZbzoYrnbG
13
+ pWf1AEsXiyclf6jaxd7ZV1ho6JbcaGdIPXzHZ5VIsQKBgQDLqg9M2oUBrBjJ31LN
14
+ 6OtjvMj9SO5BA5eMS/xC2j5cbb9bn8PV3Lge4IDlRMafZW/FwpAt3S68f81lHi9Y
15
+ KwK7zid8J16XFIEh+E95d0O5WOtdm1EU3T19ky8MbfCEIwcmurUusRZoyCYV/9cX
16
+ 1n9pDA3hXZtN1OcoHgOaubc+WwKBgQC/4Uh/KIz11YDcWgSO3Z37vwjh8JTtkjLg
17
+ DHRY0zOR6lzrUh5dT9nNT7TjeNxRk8ypPW5BET7T7NBTsoblN53d/nI2lI/sikg0
18
+ nOzqauXAlAX7s6tI/5LSsGF9OHZaiw7R2+egquIv4zN2Keq3Eq4WbGtcV0jiWFsC
19
+ oaOCXyCshQKBgDh2YCGFX2R0SrcEs9ckIMYY23vk0TCzBzu9ASWjjbBgOLH1G/zZ
20
+ YS4mPXXSWGJuY8tmwkQE0uUtZUsIUEXYPrzETYwM+htWcupxBc998gebkDz2R0dK
21
+ grairGN8wzZO47eoAXz9WWIZQv3MXNxd+hqsXdjB88FjKeakU4l8vUGLAoGAG7/z
22
+ AiDVMgBsoHGMUzUN0giwuixW/Xy1St3CPc5dmO6x/X5k0c3oi97JJFSoWEvtv1QZ
23
+ C+P4mCGZh2E8TQ4cEKzpy6b0oZrmEmXXhZdsHsvJibtUPDxp+Xp0vu1ZgIK34/XP
24
+ q9bK224aVS5+uXdEIg4QAMzGx6VLlDfYM9SaHxkCgYBOXl6pRe6UNhRKCfcbKH5e
25
+ JxwHbIyv2d9cL7yqy2lsYlXPhp7S8ClXChoaP5c6v1wAmY2RwPxP/7a541dzGxG5
26
+ RtUY78HHzKQGyobH55YNTyJq+qEUrP/DH5nhLJNvyV1SO7cpMnIO1p3dvnYawVzW
27
+ q+4Yrrdi6tWFPXnjWTGSjw==
28
+ -----END PRIVATE KEY-----
@@ -0,0 +1,25 @@
1
+ -----BEGIN CERTIFICATE-----
2
+ MIIEMTCCAxmgAwIBAgIUel2F7YVWKevz0bTFV4mbjr6ZWbIwDQYJKoZIhvcNAQEL
3
+ BQAwgaYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQH
4
+ DAdTZWF0dGxlMR0wGwYDVQQKDBRFeGFtcGxlIFdpZGdldHMgSW5jLjETMBEGA1UE
5
+ CwwKRW1haWwgVGVhbTEWMBQGA1UEAwwNKi5leGFtcGxlLmNvbTEkMCIGCSqGSIb3
6
+ DQEJARYVaGFyYWthLm1haWxAZ21haWwuY29tMCAXDTI0MDUwMjE4MzMwMVoYDzIw
7
+ NTEwOTE3MTgzMzAxWjCBpjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0
8
+ b24xEDAOBgNVBAcMB1NlYXR0bGUxHTAbBgNVBAoMFEV4YW1wbGUgV2lkZ2V0cyBJ
9
+ bmMuMRMwEQYDVQQLDApFbWFpbCBUZWFtMRYwFAYDVQQDDA0qLmV4YW1wbGUuY29t
10
+ MSQwIgYJKoZIhvcNAQkBFhVoYXJha2EubWFpbEBnbWFpbC5jb20wggEiMA0GCSqG
11
+ SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYpxuOx4M2s6sIiOEInjet7AcJddg/3uVo
12
+ qoKRW6iTwAUKnP4CsU1Xe/rMU3wr/UcCs8zzFm7L6/cqnbj2Pg1dnEvd5arYFWN5
13
+ 9XhWjI6vua2ubZkTwBEEGSgSvwnBGU/9qdrXKTeuq+8CBgV+SJzeEAmHEyhCDDT0
14
+ M9Z1p5TFx0ynkaChy2yjffC2dbiRtK7RAja0I97MmSZLym+bVpY0ucTBNNwSNNh8
15
+ UhWvWZSvVP92WGd2L72txCyfT333i0u1+SoexnJI7Wvn7YUaMNA3HSJ5/JjTW0/r
16
+ OIZGyrfnjFEs5UmULCs6RZSE0eeEuJVRL+Kd+ncYCMlCpmsqeIlHAgMBAAGjUzBR
17
+ MB0GA1UdDgQWBBSuPzKGYEvrv9ZuBlSbpgUYG2/gSjAfBgNVHSMEGDAWgBSuPzKG
18
+ YEvrv9ZuBlSbpgUYG2/gSjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBCwUA
19
+ A4IBAQCCqek5MhytpmmEjVHxfSrbSBJQ63oDa1AllqpDduWCcZZE60zOZOfrGGRO
20
+ A/JUXlJL5otPuxxJX65dJU57Y+ONbGVp9sFOT2bGrL+uwsqS7L+XyUz281sfgO0o
21
+ wsVZq6NyBVaMvtD5ViXPTZslcIZWygcvDVaUEyQ4ri8wqXNQeCNZiZikfM4U03oH
22
+ 9kgW/4IuW28Utmnt9f8vPR5XTHURX20p3Q0xhM74mZRtmldwyO3grfe25S7ZOZ5W
23
+ TFuLfxuftJNl5t1w5CdTZre7BYzbWA+Jg34eNWMiHkHE3lVMCLMqZFb8FY0TOLxw
24
+ 7YZFDrLYrA2G/alivbHs7ipj6D7i
25
+ -----END CERTIFICATE-----
@@ -0,0 +1,302 @@
1
+
2
+ const assert = require('node:assert')
3
+
4
+ const constants = require('haraka-constants');
5
+ const DSN = require('haraka-dsn')
6
+
7
+ const connection = require('../connection');
8
+ const Server = require('../server');
9
+
10
+ // huge hack here, but plugin tests need constants
11
+ constants.import(global);
12
+
13
+ const _set_up = (done) => {
14
+ this.backup = {};
15
+ const client = {
16
+ remotePort: null,
17
+ remoteAddress: null,
18
+ destroy: () => { true; },
19
+ };
20
+ const server = {
21
+ ip_address: null,
22
+ address () {
23
+ return this.ip_address;
24
+ }
25
+ }
26
+ this.connection = connection.createConnection(client, server, Server.cfg);
27
+ done()
28
+ }
29
+
30
+ describe('connection', () => {
31
+
32
+ describe('connectionRaw', () => {
33
+ beforeEach(_set_up)
34
+
35
+ it('has remote object', () => {
36
+ assert.deepEqual(this.connection.remote, {
37
+ ip: null,
38
+ port: null,
39
+ host: null,
40
+ info: null,
41
+ closed: false,
42
+ is_private: false,
43
+ is_local: false
44
+ });
45
+ })
46
+
47
+ it('has local object', () => {
48
+ assert.equal(this.connection.local.ip, null);
49
+ assert.equal(this.connection.local.port, null);
50
+ assert.ok(this.connection.local.host, this.connection.local.host);
51
+ })
52
+
53
+ it('has tls object', () => {
54
+ assert.deepEqual(this.connection.tls, {
55
+ enabled: false,
56
+ advertised: false,
57
+ verified: false,
58
+ cipher: {},
59
+ });
60
+ })
61
+
62
+ it('get_capabilities', () => {
63
+ assert.deepEqual([], this.connection.get_capabilities());
64
+ })
65
+
66
+ it('queue_msg, defined', () => {
67
+ assert.equal(
68
+ 'test message',
69
+ this.connection.queue_msg(1, 'test message')
70
+ );
71
+ })
72
+
73
+ it('queue_msg, default deny', () => {
74
+ assert.equal(
75
+ 'Message denied',
76
+ this.connection.queue_msg(DENY)
77
+ );
78
+ assert.equal(
79
+ 'Message denied',
80
+ this.connection.queue_msg(DENYDISCONNECT)
81
+ );
82
+ })
83
+
84
+ it('queue_msg, default denysoft', () => {
85
+ assert.equal(
86
+ 'Message denied temporarily',
87
+ this.connection.queue_msg(DENYSOFT)
88
+ );
89
+ assert.equal(
90
+ 'Message denied temporarily',
91
+ this.connection.queue_msg(DENYSOFTDISCONNECT)
92
+ );
93
+ })
94
+
95
+ it('queue_msg, default else', () => {
96
+ assert.equal('', this.connection.queue_msg('hello'));
97
+ })
98
+
99
+ it('has normalized connection properties', () => {
100
+ this.connection.set('remote', 'ip', '172.16.15.1');
101
+ this.connection.set('hello', 'verb', 'EHLO');
102
+ this.connection.set('tls', 'enabled', true);
103
+
104
+ assert.equal('172.16.15.1', this.connection.remote.ip);
105
+ assert.equal(null, this.connection.remote.port);
106
+ assert.equal('EHLO', this.connection.hello.verb);
107
+ assert.equal(null, this.connection.hello.host);
108
+ assert.equal(true, this.connection.tls.enabled);
109
+ })
110
+
111
+ it('sets remote.is_private and remote.is_local', () => {
112
+ assert.equal(false, this.connection.remote.is_private);
113
+ assert.equal(false, this.connection.remote.is_local);
114
+ })
115
+
116
+ it('has normalized proxy properties, default', () => {
117
+ assert.equal(false, this.connection.proxy.allowed);
118
+ assert.equal(null, this.connection.proxy.ip);
119
+ assert.equal(null, this.connection.proxy.type);
120
+ assert.equal(null, this.connection.proxy.timer);
121
+ })
122
+
123
+ it('has normalized proxy properties, set', () => {
124
+ this.connection.set('proxy', 'ip', '172.16.15.1');
125
+ this.connection.set('proxy', 'type', 'haproxy');
126
+ this.connection.set('proxy', 'timer', setTimeout(() => {}, 1000));
127
+ this.connection.set('proxy', 'allowed', true);
128
+
129
+ assert.equal(true, this.connection.proxy.allowed);
130
+ assert.equal('172.16.15.1', this.connection.proxy.ip);
131
+ assert.ok(this.connection.proxy.timer);
132
+ assert.equal(this.connection.proxy.type, 'haproxy');
133
+ })
134
+ })
135
+
136
+ describe('connectionPrivate', () => {
137
+ beforeEach((done) => {
138
+ this.backup = {};
139
+ const client = {
140
+ remotePort: 2525,
141
+ remoteAddress: '172.16.15.1',
142
+ localPort: 25,
143
+ localAddress: '172.16.15.254',
144
+ destroy: () => { true; },
145
+ };
146
+ const server = {
147
+ ip_address: '172.16.15.254',
148
+ address () {
149
+ return this.ip_address;
150
+ }
151
+ }
152
+ this.connection = connection.createConnection(client, server, Server.cfg);
153
+ done()
154
+ })
155
+
156
+ it('sets remote.is_private and remote.is_local', () => {
157
+ assert.equal(true, this.connection.remote.is_private);
158
+ assert.equal(false, this.connection.remote.is_local);
159
+ assert.equal(2525, this.connection.remote.port);
160
+ })
161
+ })
162
+
163
+
164
+ describe('connectionLocal', () => {
165
+ beforeEach((done) => {
166
+ const client = {
167
+ remotePort: 2525,
168
+ remoteAddress: '127.0.0.2',
169
+ localPort: 25,
170
+ localAddress: '172.0.0.1',
171
+ destroy: () => { true; },
172
+ };
173
+ const server = {
174
+ ip_address: '127.0.0.1',
175
+ address () {
176
+ return this.ip_address;
177
+ }
178
+ };
179
+ this.connection = connection.createConnection(client, server, Server.cfg);
180
+ done();
181
+ })
182
+
183
+ it('sets remote.is_private and remote.is_local', () => {
184
+ assert.equal(true, this.connection.remote.is_private);
185
+ assert.equal(true, this.connection.remote.is_local);
186
+ assert.equal(2525, this.connection.remote.port);
187
+ })
188
+ })
189
+
190
+
191
+ describe('get_remote', () => {
192
+ beforeEach(_set_up)
193
+
194
+ it('valid hostname', () => {
195
+ this.connection.remote.host='a.host.tld'
196
+ this.connection.remote.ip='172.16.199.198'
197
+ assert.equal(this.connection.get_remote('host'), 'a.host.tld [172.16.199.198]');
198
+ })
199
+
200
+ it('no hostname', () => {
201
+ this.connection.remote.ip='172.16.199.198'
202
+ assert.equal(this.connection.get_remote('host'), '[172.16.199.198]');
203
+ })
204
+
205
+ it('DNSERROR', () => {
206
+ this.connection.remote.host='DNSERROR'
207
+ this.connection.remote.ip='172.16.199.198'
208
+ assert.equal(this.connection.get_remote('host'), '[172.16.199.198]');
209
+ })
210
+
211
+ it('NXDOMAIN', () => {
212
+ this.connection.remote.host='NXDOMAIN'
213
+ this.connection.remote.ip='172.16.199.198'
214
+ assert.equal(this.connection.get_remote('host'), '[172.16.199.198]');
215
+ })
216
+
217
+ })
218
+
219
+ describe('local_info', () => {
220
+ beforeEach(_set_up)
221
+
222
+ it('is Haraka/version', () => {
223
+ assert.ok(/Haraka\/\d.\d/.test(this.connection.local.info), this.connection.local.info);
224
+ })
225
+ })
226
+
227
+ describe('relaying', () => {
228
+ beforeEach(_set_up)
229
+
230
+ it('sets and gets', () => {
231
+ assert.equal(this.connection.relaying, false);
232
+ assert.ok(this.connection.relaying = 'alligators');
233
+ assert.equal(this.connection.relaying, 'alligators');
234
+ })
235
+
236
+ it('sets and gets in a transaction', () => {
237
+ assert.equal(this.connection.relaying, false);
238
+ this.connection.transaction = {};
239
+ assert.ok(this.connection.relaying = 'crocodiles');
240
+ assert.equal(this.connection.transaction._relaying, 'crocodiles');
241
+ assert.equal(this.connection.relaying, 'crocodiles');
242
+ })
243
+ })
244
+
245
+ describe('get_set', () => {
246
+ beforeEach(_set_up)
247
+
248
+ it('sets single level properties', () => {
249
+ this.connection.set('encoding', true);
250
+ assert.ok(this.connection.encoding);
251
+ assert.ok(this.connection.get('encoding'));
252
+ })
253
+
254
+ it('sets two level deep properties', () => {
255
+ this.connection.set('local.host', 'test');
256
+ assert.equal(this.connection.local.host, 'test');
257
+ assert.equal(this.connection.get('local.host'), 'test');
258
+ })
259
+
260
+ it('sets three level deep properties', () => {
261
+ this.connection.set('some.fine.example', true);
262
+ assert.ok(this.connection.some.fine.example);
263
+ assert.ok(this.connection.get('some.fine.example'));
264
+ })
265
+ })
266
+
267
+ describe('respond', () => {
268
+ beforeEach(_set_up)
269
+
270
+ it('disconnected returns undefined', () => {
271
+ this.connection.state = constants.connection.state.DISCONNECTED
272
+ assert.equal(this.connection.respond(200, 'your lucky day'), undefined);
273
+ assert.equal(this.connection.respond(550, 'you are jacked'), undefined);
274
+ })
275
+
276
+ it('state=command, 200', () => {
277
+ assert.equal(this.connection.respond(200, 'you may pass Go'), '200 you may pass Go\r\n');
278
+ })
279
+
280
+ it('DSN 200', () => {
281
+ assert.equal(
282
+ this.connection.respond(200, DSN.create(200, 'you may pass Go')),
283
+ '200 2.0.0 you may pass Go\r\n'
284
+ );
285
+ })
286
+
287
+ it('DSN 550 create', () => {
288
+ // note, the DSN code overrides the response code
289
+ assert.equal(
290
+ this.connection.respond(450, DSN.create(550, 'This domain is not in use and does not accept mail')),
291
+ '550 5.0.0 This domain is not in use and does not accept mail\r\n'
292
+ );
293
+ })
294
+
295
+ it('DSN 550 addr_bad_dest_system', () => {
296
+ assert.equal(
297
+ this.connection.respond(550, DSN.addr_bad_dest_system('This domain is not in use and does not accept mail', 550)),
298
+ '550 5.1.2 This domain is not in use and does not accept mail\r\n'
299
+ );
300
+ })
301
+ })
302
+ })
@@ -0,0 +1,94 @@
1
+ const assert = require('node:assert')
2
+
3
+ const mock = require('mock-require');
4
+ const endpoint = require('../endpoint');
5
+
6
+ describe('endpoint', () => {
7
+
8
+ it('toString()', () => {
9
+ assert.equal( endpoint(25), '[::0]:25' );
10
+ assert.equal( endpoint('10.0.0.3', 42), '10.0.0.3:42' );
11
+ assert.equal( endpoint('/foo/bar.sock'), '/foo/bar.sock' );
12
+ assert.equal( endpoint('/foo/bar.sock:770'), '/foo/bar.sock:770' );
13
+ assert.equal( endpoint({address: '::0', port: 80}), '[::0]:80' );
14
+ })
15
+
16
+ describe('parse', () => {
17
+ it('Number as port', () => {
18
+ assert.deepEqual( endpoint(25), {host:'::0', port:25} );
19
+ })
20
+
21
+ it('Default port if only host', () => {
22
+ assert.deepEqual( endpoint('10.0.0.3', 42), {host:'10.0.0.3', port:42} );
23
+ })
24
+
25
+ it('Unix socket', () => {
26
+ assert.deepEqual( endpoint('/foo/bar.sock'), {path:'/foo/bar.sock'} );
27
+ })
28
+
29
+ it('Unix socket w/mode', () => {
30
+ assert.deepEqual( endpoint('/foo/bar.sock:770'), {path:'/foo/bar.sock', mode:'770'} );
31
+ })
32
+ })
33
+
34
+ describe('bind()', () => {
35
+ beforeEach((done) => {
36
+ // Mock filesystem and log server + fs method calls
37
+ const modes = this.modes = {}
38
+ const log = this.log = []
39
+
40
+ this.server = {
41
+ listen (opts, cb) {
42
+ log.push(['listen', opts]);
43
+ if (cb) cb();
44
+ }
45
+ }
46
+
47
+ this.mockfs = {
48
+ chmod (path, mode, ...args) {
49
+ log.push(['chmod', path, mode, ...args]);
50
+ modes[path] = mode;
51
+ },
52
+ rm (path, ...args) {
53
+ log.push(['rm', path, ...args]);
54
+ },
55
+ };
56
+
57
+ mock('node:fs/promises', this.mockfs);
58
+ this.endpoint = mock.reRequire('../endpoint');
59
+ done();
60
+ })
61
+
62
+ afterEach((done) => {
63
+ mock.stop('node:fs/promises');
64
+ done();
65
+ })
66
+
67
+ it('IP socket', async () => {
68
+ await this.endpoint('10.0.0.3:42').bind(this.server, {backlog:19});
69
+ assert.deepEqual(
70
+ this.log, [
71
+ ['listen', {host: '10.0.0.3', port: 42, backlog: 19}],
72
+ ]);
73
+ })
74
+
75
+ it('Unix socket', async () => {
76
+ await this.endpoint('/foo/bar.sock').bind(this.server, {readableAll:true});
77
+ assert.deepEqual(
78
+ this.log, [
79
+ ['rm', '/foo/bar.sock', {force:true}],
80
+ ['listen', {path: '/foo/bar.sock', readableAll: true}],
81
+ ]);
82
+ })
83
+
84
+ it('Unix socket w/mode', async () => {
85
+ await this.endpoint('/foo/bar.sock:764').bind(this.server);
86
+ assert.deepEqual(
87
+ this.log, [
88
+ ['rm', '/foo/bar.sock', {force:true}],
89
+ ['listen', {path: '/foo/bar.sock'}],
90
+ ['chmod', '/foo/bar.sock', 0o764],
91
+ ]);
92
+ })
93
+ })
94
+ })
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- const events = require('events');
3
+ const events = require('node:events');
4
4
  const fixtures = require('haraka-test-fixtures');
5
5
  const { stub } = fixtures.stub;
6
6