Haraka 2.8.28 → 3.0.0

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 (134) hide show
  1. package/.eslintrc.yaml +2 -10
  2. package/Changes.md +68 -2
  3. package/Dockerfile +1 -1
  4. package/Plugins.md +7 -4
  5. package/README.md +2 -6
  6. package/config/outbound.ini +0 -7
  7. package/config/plugins +1 -1
  8. package/config/smtp.ini +1 -1
  9. package/config/smtp_forward.ini +2 -8
  10. package/config/smtp_proxy.ini +0 -6
  11. package/connection.js +178 -204
  12. package/coverage/lcov.info +13863 -0
  13. package/coverage/tmp/coverage-42958-1658373250585-0.json +1 -0
  14. package/coverage/tmp/coverage-42961-1658373250529-0.json +1 -0
  15. package/dkim.js +65 -73
  16. package/docs/Body.md +1 -22
  17. package/docs/CoreConfig.md +2 -2
  18. package/docs/Header.md +1 -47
  19. package/docs/Outbound.md +8 -36
  20. package/endpoint.js +1 -1
  21. package/haraka.js +1 -1
  22. package/host_pool.js +8 -12
  23. package/logger.js +25 -32
  24. package/outbound/client_pool.js +11 -153
  25. package/outbound/config.js +5 -11
  26. package/outbound/hmail.js +109 -143
  27. package/outbound/index.js +13 -25
  28. package/outbound/mx_lookup.js +10 -7
  29. package/outbound/queue.js +8 -12
  30. package/outbound/timer_queue.js +2 -4
  31. package/outbound/tls.js +17 -18
  32. package/outbound/todo.js +1 -0
  33. package/package.json +42 -40
  34. package/plugins/auth/auth_base.js +39 -63
  35. package/plugins/auth/auth_bridge.js +3 -4
  36. package/plugins/auth/auth_proxy.js +16 -16
  37. package/plugins/auth/auth_vpopmaild.js +30 -37
  38. package/plugins/auth/flat_file.js +9 -13
  39. package/plugins/avg.js +9 -11
  40. package/plugins/backscatterer.js +1 -1
  41. package/plugins/block_me.js +2 -6
  42. package/plugins/bounce.js +106 -124
  43. package/plugins/clamd.js +59 -63
  44. package/plugins/data.signatures.js +6 -6
  45. package/plugins/data.uribl.js +1 -415
  46. package/plugins/delay_deny.js +19 -20
  47. package/plugins/dkim_sign.js +56 -62
  48. package/plugins/dkim_verify.js +9 -8
  49. package/plugins/dns_list_base.js +43 -42
  50. package/plugins/dnsbl.js +41 -46
  51. package/plugins/dnswl.js +23 -26
  52. package/plugins/early_talker.js +24 -28
  53. package/plugins/esets.js +8 -11
  54. package/plugins/greylist.js +161 -190
  55. package/plugins/helo.checks.js +175 -197
  56. package/plugins/mail_from.is_resolvable.js +38 -38
  57. package/plugins/messagesniffer.js +33 -40
  58. package/plugins/prevent_credential_leaks.js +7 -5
  59. package/plugins/process_title.js +16 -17
  60. package/plugins/queue/deliver.js +2 -2
  61. package/plugins/queue/lmtp.js +5 -6
  62. package/plugins/queue/qmail-queue.js +11 -13
  63. package/plugins/queue/quarantine.js +25 -34
  64. package/plugins/queue/rabbitmq.js +3 -2
  65. package/plugins/queue/rabbitmq_amqplib.js +9 -9
  66. package/plugins/queue/smtp_bridge.js +5 -4
  67. package/plugins/queue/smtp_forward.js +81 -89
  68. package/plugins/queue/smtp_proxy.js +21 -22
  69. package/plugins/queue/test.js +2 -1
  70. package/plugins/rcpt_to.host_list_base.js +20 -30
  71. package/plugins/rcpt_to.in_host_list.js +12 -14
  72. package/plugins/rcpt_to.max_count.js +7 -5
  73. package/plugins/record_envelope_addresses.js +4 -6
  74. package/plugins/relay.js +64 -74
  75. package/plugins/reseed_rng.js +1 -2
  76. package/plugins/spamassassin.js +56 -68
  77. package/plugins/status.js +2 -3
  78. package/plugins/tarpit.js +8 -11
  79. package/plugins/tls.js +14 -17
  80. package/plugins/toobusy.js +6 -8
  81. package/plugins/xclient.js +14 -25
  82. package/plugins.js +24 -29
  83. package/rfc1869.js +2 -2
  84. package/server.js +3 -13
  85. package/smtp_client.js +138 -215
  86. package/tests/config/smtp_forward.ini +0 -6
  87. package/tests/fixtures/line_socket.js +1 -1
  88. package/tests/fixtures/util_hmailitem.js +5 -7
  89. package/tests/fixtures/vm_harness.js +2 -2
  90. package/tests/host_pool.js +13 -14
  91. package/tests/installation/plugins/inherits.js +1 -2
  92. package/tests/logger.js +2 -2
  93. package/tests/plugins/bounce.js +6 -8
  94. package/tests/plugins/dkim_signer.js +7 -7
  95. package/tests/plugins/dns_list_base.js +7 -7
  96. package/tests/plugins/helo.checks.js +1 -1
  97. package/tests/plugins/mail_from.is_resolvable.js +10 -54
  98. package/tests/plugins/queue/smtp_forward.js +11 -11
  99. package/tests/plugins/rcpt_to.host_list_base.js +1 -1
  100. package/tests/plugins/rcpt_to.in_host_list.js +1 -1
  101. package/tests/plugins/spamassassin.js +1 -1
  102. package/tests/queue/multibyte +0 -0
  103. package/tests/queue/plain +0 -0
  104. package/tests/rfc1869.js +4 -1
  105. package/tests/server.js +15 -9
  106. package/tests/smtp_client/auth.js +4 -14
  107. package/tests/smtp_client/basic.js +5 -15
  108. package/tests/smtp_client.js +7 -3
  109. package/tests/transaction.js +72 -19
  110. package/tls_socket.js +75 -85
  111. package/transaction.js +7 -9
  112. package/attachment_stream.js +0 -118
  113. package/bin/spf +0 -48
  114. package/chunkemitter.js +0 -75
  115. package/config/data.uribl.excludes +0 -202
  116. package/config/data.uribl.ini +0 -37
  117. package/config/spf.ini +0 -1
  118. package/docs/plugins/attachment.md +0 -92
  119. package/docs/plugins/data.uribl.md +0 -120
  120. package/docs/plugins/spf.md +0 -142
  121. package/mailbody.js +0 -502
  122. package/mailheader.js +0 -304
  123. package/messagestream.js +0 -441
  124. package/plugins/aliases.js +0 -120
  125. package/plugins/attachment.js +0 -503
  126. package/plugins/connect.p0f.js +0 -5
  127. package/plugins/spf.js +0 -327
  128. package/spf.js +0 -689
  129. package/tests/mailbody.js +0 -348
  130. package/tests/mailheader.js +0 -138
  131. package/tests/messagestream.js +0 -34
  132. package/tests/plugins/aliases.js +0 -376
  133. package/tests/plugins/spf.js +0 -251
  134. package/tests/spf.js +0 -96
@@ -3,24 +3,21 @@
3
3
  const net = require('net');
4
4
 
5
5
  exports.register = function () {
6
- const plugin = this;
7
- plugin.inherits('auth/auth_base');
8
- plugin.load_vpop_ini();
6
+ this.inherits('auth/auth_base');
7
+ this.load_vpop_ini();
9
8
  }
10
9
 
11
10
  exports.load_vpop_ini = function () {
12
- const plugin = this;
13
- plugin.cfg = plugin.config.get('auth_vpopmaild.ini', () => {
14
- plugin.load_vpop_ini();
11
+ this.cfg = this.config.get('auth_vpopmaild.ini', () => {
12
+ this.load_vpop_ini();
15
13
  });
16
14
  }
17
15
 
18
16
  exports.hook_capabilities = function (next, connection) {
19
17
  if (!connection.tls.enabled) { return next(); }
20
- const plugin = this;
21
18
 
22
19
  const methods = [ 'PLAIN', 'LOGIN' ];
23
- if (plugin.cfg.main.sysadmin) { methods.push('CRAM-MD5'); }
20
+ if (this.cfg.main.sysadmin) { methods.push('CRAM-MD5'); }
24
21
 
25
22
  connection.capabilities.push(`AUTH ${methods.join(' ')}`);
26
23
  connection.notes.allowed_auth_methods = methods;
@@ -29,12 +26,11 @@ exports.hook_capabilities = function (next, connection) {
29
26
  }
30
27
 
31
28
  exports.check_plain_passwd = function (connection, user, passwd, cb) {
32
- const plugin = this;
33
29
 
34
30
  let chunk_count = 0;
35
31
  let auth_success = false;
36
32
 
37
- const socket = plugin.get_vpopmaild_socket(user);
33
+ const socket = this.get_vpopmaild_socket(user);
38
34
  socket.setEncoding('utf8');
39
35
 
40
36
  socket.on('data', chunk => {
@@ -55,94 +51,91 @@ exports.check_plain_passwd = function (connection, user, passwd, cb) {
55
51
  }
56
52
  });
57
53
  socket.on('end', () => {
58
- connection.loginfo(plugin, `AUTH user="${user}" success=${auth_success}`);
54
+ connection.loginfo(this, `AUTH user="${user}" success=${auth_success}`);
59
55
  return cb(auth_success);
60
56
  });
61
57
  }
62
58
 
63
59
  exports.get_sock_opts = function (user) {
64
- const plugin = this;
65
60
 
66
- plugin.sock_opts = {
61
+ this.sock_opts = {
67
62
  port: 89,
68
63
  host: '127.0.0.1',
69
64
  sysadmin: undefined,
70
65
  };
71
66
 
72
67
  const domain = (user.split('@'))[1];
73
- let sect = plugin.cfg.main;
74
- if (domain && plugin.cfg[domain]) {
75
- sect = plugin.cfg[domain];
68
+ let sect = this.cfg.main;
69
+ if (domain && this.cfg[domain]) {
70
+ sect = this.cfg[domain];
76
71
  }
77
72
 
78
- if (sect.port) { plugin.sock_opts.port = sect.port; }
79
- if (sect.host) { plugin.sock_opts.host = sect.host; }
80
- if (sect.sysadmin) { plugin.sock_opts.sysadmin = sect.sysadmin; }
73
+ if (sect.port) { this.sock_opts.port = sect.port; }
74
+ if (sect.host) { this.sock_opts.host = sect.host; }
75
+ if (sect.sysadmin) { this.sock_opts.sysadmin = sect.sysadmin; }
81
76
 
82
- plugin.logdebug(`sock: ${plugin.sock_opts.host}:${plugin.sock_opts.port}`);
83
- return plugin.sock_opts;
77
+ this.logdebug(`sock: ${this.sock_opts.host}:${this.sock_opts.port}`);
78
+ return this.sock_opts;
84
79
  }
85
80
 
86
81
  exports.get_vpopmaild_socket = function (user) {
87
- const plugin = this;
88
- plugin.get_sock_opts(user);
82
+ this.get_sock_opts(user);
89
83
 
90
84
  const socket = new net.Socket();
91
- socket.connect(plugin.sock_opts.port, plugin.sock_opts.host);
85
+ socket.connect(this.sock_opts.port, this.sock_opts.host);
92
86
  socket.setTimeout(300 * 1000);
93
87
  socket.setEncoding('utf8');
94
88
 
95
89
  socket.on('timeout', () => {
96
- plugin.logerror("vpopmaild connection timed out");
90
+ this.logerror("vpopmaild connection timed out");
97
91
  socket.end();
98
92
  });
99
93
  socket.on('error', err => {
100
- plugin.logerror(`vpopmaild connection failed: ${err}`);
94
+ this.logerror(`vpopmaild connection failed: ${err}`);
101
95
  socket.end();
102
96
  });
103
97
  socket.on('connect', () => {
104
- plugin.logdebug('vpopmail connected');
98
+ this.logdebug('vpopmail connected');
105
99
  });
106
100
  return socket;
107
101
  }
108
102
 
109
103
  exports.get_plain_passwd = function (user, connection, cb) {
110
- const plugin = this;
111
104
 
112
- const socket = plugin.get_vpopmaild_socket(user);
113
- if (!plugin.sock_opts.sysadmin) {
114
- plugin.logerror("missing sysadmin credentials");
105
+ const socket = this.get_vpopmaild_socket(user);
106
+ if (!this.sock_opts.sysadmin) {
107
+ this.logerror("missing sysadmin credentials");
115
108
  return cb(null);
116
109
  }
117
110
 
118
- const sys = plugin.sock_opts.sysadmin.split(':');
111
+ const sys = this.sock_opts.sysadmin.split(':');
119
112
  let plain_pass = null;
120
113
  let chunk_count = 0;
121
114
 
122
115
  socket.on('data', chunk => {
123
116
  chunk_count++;
124
- plugin.logdebug(`${chunk_count}\t${chunk}`);
117
+ this.logdebug(`${chunk_count}\t${chunk}`);
125
118
  if (chunk_count === 1) {
126
119
  if (/^\+OK/.test(chunk)) {
127
120
  socket.write(`slogin ${sys[0]} ${sys[1]}\n\r`);
128
121
  return;
129
122
  }
130
- plugin.logerror("no ok to start");
123
+ this.logerror("no ok to start");
131
124
  socket.end(); // disconnect
132
125
  }
133
126
  // slogin reply
134
127
  if (chunk_count === 2) {
135
128
  if (/^\+OK/.test(chunk)) {
136
- plugin.logdebug('login success, getting user info');
129
+ this.logdebug('login success, getting user info');
137
130
  socket.write(`user_info ${user}\n\r`);
138
131
  return;
139
132
  }
140
- plugin.logerror("syadmin login failed");
133
+ this.logerror("syadmin login failed");
141
134
  socket.end(); // disconnect
142
135
  }
143
136
  if (chunk_count > 2) {
144
137
  if (/^-ERR/.test(chunk)) {
145
- plugin.lognotice(`get_plain failed: ${chunk}`);
138
+ this.lognotice(`get_plain failed: ${chunk}`);
146
139
  socket.end(); // disconnect
147
140
  return;
148
141
  }
@@ -1,30 +1,27 @@
1
1
  // Auth against a flat file
2
2
 
3
3
  exports.register = function () {
4
- const plugin = this;
5
- plugin.inherits('auth/auth_base');
6
- plugin.load_flat_ini();
4
+ this.inherits('auth/auth_base');
5
+ this.load_flat_ini();
7
6
  }
8
7
 
9
8
  exports.load_flat_ini = function () {
10
- const plugin = this;
11
- plugin.cfg = plugin.config.get('auth_flat_file.ini', () => {
12
- plugin.load_flat_ini();
9
+ this.cfg = this.config.get('auth_flat_file.ini', () => {
10
+ this.load_flat_ini();
13
11
  });
14
12
  }
15
13
 
16
14
  exports.hook_capabilities = function (next, connection) {
17
- const plugin = this;
18
15
  // don't allow AUTH unless private IP or encrypted
19
16
  if (!connection.remote.is_private && !connection.tls.enabled) {
20
- connection.logdebug(plugin,
17
+ connection.logdebug(this,
21
18
  "Auth disabled for insecure public connection");
22
19
  return next();
23
20
  }
24
21
 
25
22
  let methods = null;
26
- if (plugin.cfg.core && plugin.cfg.core.methods ) {
27
- methods = plugin.cfg.core.methods.split(',');
23
+ if (this.cfg.core?.methods ) {
24
+ methods = this.cfg.core.methods.split(',');
28
25
  }
29
26
  if (methods && methods.length > 0) {
30
27
  connection.capabilities.push(`AUTH ${methods.join(' ')}`);
@@ -34,9 +31,8 @@ exports.hook_capabilities = function (next, connection) {
34
31
  }
35
32
 
36
33
  exports.get_plain_passwd = function (user, connection, cb) {
37
- const plugin = this;
38
- if (plugin.cfg.users[user]) {
39
- return cb(plugin.cfg.users[user].toString());
34
+ if (this.cfg.users[user]) {
35
+ return cb(this.cfg.users[user].toString());
40
36
  }
41
37
  return cb();
42
38
  }
package/plugins/avg.js CHANGED
@@ -7,37 +7,35 @@ const fs = require('fs');
7
7
  const path = require('path');
8
8
 
9
9
  const sock = require('./line_socket');
10
- const smtp_regexp = /^([0-9]{3})([ -])(.*)/;
10
+
11
+ const smtp_regexp = /^(\d{3})([ -])(.*)/;
11
12
 
12
13
  exports.register = function () {
13
- const plugin = this;
14
14
 
15
- plugin.load_avg_ini();
15
+ this.load_avg_ini();
16
16
  }
17
17
 
18
18
  exports.load_avg_ini = function () {
19
- const plugin = this;
20
19
 
21
- plugin.cfg = plugin.config.get('avg.ini', {
20
+ this.cfg = this.config.get('avg.ini', {
22
21
  booleans: [
23
22
  '+defer.timeout',
24
23
  '+defer.error',
25
24
  ],
26
25
  }, () => {
27
- plugin.load_avg_ini();
26
+ this.load_avg_ini();
28
27
  });
29
28
  }
30
29
 
31
30
  exports.get_tmp_file = function (transaction) {
32
- const plugin = this;
33
- const tmpdir = plugin.cfg.main.tmpdir || '/tmp';
31
+ const tmpdir = this.cfg.main.tmpdir || '/tmp';
34
32
  return path.join(tmpdir, `${transaction.uuid}.tmp`);
35
33
  }
36
34
 
37
35
  exports.hook_data_post = function (next, connection) {
38
- const plugin = this;
39
- if (!connection.transaction) return next();
36
+ if (!connection?.transaction) return next()
40
37
 
38
+ const plugin = this;
41
39
  const tmpfile = plugin.get_tmp_file(connection.transaction);
42
40
  const ws = fs.createWriteStream(tmpfile);
43
41
 
@@ -103,7 +101,7 @@ exports.hook_data_post = function (next, connection) {
103
101
  const cont = matches[2];
104
102
  const rest = matches[3];
105
103
  response.push(rest);
106
- if (cont !== ' ') { return; }
104
+ if (cont !== ' ') return;
107
105
 
108
106
  switch (command) {
109
107
  case 'connect':
@@ -5,7 +5,7 @@ exports.register = function () {
5
5
  }
6
6
 
7
7
  exports.hook_mail = function (next, connection, params) {
8
- const user = ((params[0] && params[0].user) ?
8
+ const user = ((params[0]?.user) ?
9
9
  params[0].user.toLowerCase() : null);
10
10
  if (!(!user || user === 'postmaster')) return next();
11
11
  // Check remote IP on ips.backscatterer.org
@@ -13,15 +13,11 @@ exports.hook_data = (next, connection) => {
13
13
  }
14
14
 
15
15
  exports.hook_data_post = function (next, connection) {
16
- if (!connection.relaying) {
17
- return next();
18
- }
16
+ if (!connection?.relaying || !connection?.transaction) return next();
19
17
 
20
18
  const recip = (this.config.get('block_me.recipient') || '').toLowerCase();
21
19
  const senders = this.config.get('block_me.senders', 'list');
22
20
 
23
- const self = this;
24
-
25
21
  // Make sure only 1 recipient
26
22
  if (connection.transaction.rcpt_to.length != 1) {
27
23
  return next();
@@ -52,7 +48,7 @@ exports.hook_data_post = function (next, connection) {
52
48
  // add to mail_from.blocklist
53
49
  fs.open('./config/mail_from.blocklist', 'a', (err, fd) => {
54
50
  if (err) {
55
- connection.logerror(self, `Unable to append to mail_from.blocklist: ${err}`);
51
+ connection.logerror(this, `Unable to append to mail_from.blocklist: ${err}`);
56
52
  return;
57
53
  }
58
54
  fs.write(fd, `${to_block}\n`, null, 'UTF-8', (err2, written) => {