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
@@ -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) => {