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
@@ -7,40 +7,37 @@
7
7
  const smtp_client_mod = require('./smtp_client');
8
8
 
9
9
  exports.register = function () {
10
- const plugin = this;
11
10
 
12
- plugin.load_smtp_proxy_ini();
11
+ this.load_smtp_proxy_ini();
13
12
 
14
- if (plugin.cfg.main.enable_outbound) {
15
- plugin.register_hook('queue_outbound', 'hook_queue');
13
+ if (this.cfg.main.enable_outbound) {
14
+ this.register_hook('queue_outbound', 'hook_queue');
16
15
  }
17
16
  }
18
17
 
19
18
  exports.load_smtp_proxy_ini = function () {
20
- const plugin = this;
21
19
 
22
- plugin.cfg = plugin.config.get('smtp_proxy.ini', {
20
+ this.cfg = this.config.get('smtp_proxy.ini', {
23
21
  booleans: [
24
22
  '-main.enable_tls',
25
23
  '+main.enable_outbound',
26
24
  ],
27
25
  },
28
26
  () => {
29
- plugin.load_smtp_proxy_ini();
27
+ this.load_smtp_proxy_ini();
30
28
  });
31
29
 
32
- if (plugin.cfg.main.enable_outbound) {
33
- plugin.lognotice('outbound enabled, will default to disabled in Haraka v3 (see #1472)');
30
+ if (this.cfg.main.enable_outbound) {
31
+ this.lognotice('outbound enabled, will default to disabled in Haraka v3 (see #1472)');
34
32
  }
35
33
  }
36
34
 
37
35
  exports.hook_mail = function (next, connection, params) {
38
- const plugin = this;
39
- const c = plugin.cfg.main;
40
- connection.loginfo(plugin, `forwarding to ${
36
+ const c = this.cfg.main;
37
+ connection.loginfo(this, `forwarding to ${
41
38
  c.forwarding_host_pool ? "configured forwarding_host_pool" : `${c.host}:${c.port}`}`
42
39
  );
43
- smtp_client_mod.get_client_plugin(plugin, connection, c, (err, smtp_client) => {
40
+ smtp_client_mod.get_client_plugin(this, connection, c, (err, smtp_client) => {
44
41
  connection.notes.smtp_client = smtp_client;
45
42
  smtp_client.next = next;
46
43
 
@@ -49,7 +46,7 @@ exports.hook_mail = function (next, connection, params) {
49
46
  smtp_client.on('data', smtp_client.call_next);
50
47
 
51
48
  smtp_client.on('dot', () => {
52
- if (smtp_client.is_dead_sender(plugin, connection)) {
49
+ if (smtp_client.is_dead_sender(this, connection)) {
53
50
  delete connection.notes.smtp_client;
54
51
  return;
55
52
  }
@@ -71,7 +68,7 @@ exports.hook_mail = function (next, connection, params) {
71
68
  // errors are OK for rcpt, but nothing else
72
69
  // this can also happen if the destination server
73
70
  // times out, but that is okay.
74
- connection.loginfo(plugin, "message denied, proxying failed");
71
+ connection.loginfo(this, "message denied, proxying failed");
75
72
  smtp_client.release();
76
73
  delete connection.notes.smtp_client;
77
74
  }
@@ -80,25 +77,27 @@ exports.hook_mail = function (next, connection, params) {
80
77
  }
81
78
 
82
79
  exports.hook_rcpt_ok = (next, connection, recipient) => {
83
- const smtp_client = connection.notes.smtp_client;
80
+ const { smtp_client } = connection.notes;
84
81
  if (!smtp_client) return next();
85
82
  smtp_client.next = next;
86
83
  smtp_client.send_command('RCPT', `TO:${recipient.format(!smtp_client.smtp_utf8)}`);
87
84
  }
88
85
 
89
86
  exports.hook_data = (next, connection) => {
90
- const smtp_client = connection.notes.smtp_client;
87
+ const { smtp_client } = connection.notes;
91
88
  if (!smtp_client) return next();
92
89
  smtp_client.next = next;
93
90
  smtp_client.send_command("DATA");
94
91
  }
95
92
 
96
93
  exports.hook_queue = function (next, connection) {
97
- const plugin = this;
98
- const smtp_client = connection.notes.smtp_client;
94
+ if (!connection?.transaction || !connection?.notes) return next();
95
+
96
+ const { smtp_client } = connection.notes;
99
97
  if (!smtp_client) return next();
98
+
100
99
  smtp_client.next = next;
101
- if (smtp_client.is_dead_sender(plugin, connection)) {
100
+ if (smtp_client.is_dead_sender(this, connection)) {
102
101
  delete connection.notes.smtp_client;
103
102
  return;
104
103
  }
@@ -106,7 +105,7 @@ exports.hook_queue = function (next, connection) {
106
105
  }
107
106
 
108
107
  exports.hook_rset = (next, connection) => {
109
- const smtp_client = connection.notes.smtp_client;
108
+ const { smtp_client } = connection.notes;
110
109
  if (!smtp_client) return next();
111
110
  smtp_client.release();
112
111
  delete connection.notes.smtp_client;
@@ -116,7 +115,7 @@ exports.hook_rset = (next, connection) => {
116
115
  exports.hook_quit = exports.hook_rset;
117
116
 
118
117
  exports.hook_disconnect = (next, connection) => {
119
- const smtp_client = connection.notes.smtp_client;
118
+ const { smtp_client } = connection.notes;
120
119
  if (!smtp_client) return next();
121
120
  smtp_client.release();
122
121
  delete connection.notes.smtp_client;
@@ -1,10 +1,11 @@
1
-
2
1
  const fs = require('fs');
3
2
  const os = require('os');
4
3
 
5
4
  const tempDir = os.tmpdir();
6
5
 
7
6
  exports.hook_queue = function (next, connection) {
7
+ if (!connection?.transaction) return next();
8
+
8
9
  const ws = fs.createWriteStream(`${tempDir}/mail.eml`);
9
10
  connection.logdebug(this, `Saving to ${tempDir}/mail.eml`);
10
11
  ws.once('close', () => next(OK));
@@ -2,78 +2,68 @@
2
2
  // Base class for plugins that use config/host_list
3
3
 
4
4
  exports.load_host_list = function () {
5
- const plugin = this;
6
5
 
7
6
  const lowered_list = {}; // assemble
8
- const raw_list = plugin.config.get('host_list', 'list', () => {
9
- plugin.load_host_list();
7
+ const raw_list = this.config.get('host_list', 'list', () => {
8
+ this.load_host_list();
10
9
  });
11
10
 
12
11
  for (const i in raw_list) {
13
12
  lowered_list[raw_list[i].toLowerCase()] = true;
14
13
  }
15
14
 
16
- plugin.host_list = lowered_list;
15
+ this.host_list = lowered_list;
17
16
  }
18
17
 
19
18
  exports.load_host_list_regex = function () {
20
- const plugin = this;
21
19
 
22
- plugin.host_list_regex = plugin.config.get(
20
+ this.host_list_regex = this.config.get(
23
21
  'host_list_regex',
24
22
  'list',
25
- () => { plugin.load_host_list_regex(); }
23
+ () => { this.load_host_list_regex(); }
26
24
  );
27
25
 
28
- plugin.hl_re = new RegExp (`^(?:${
29
- plugin.host_list_regex.join('|')})$`, 'i');
26
+ this.hl_re = new RegExp (`^(?:${this.host_list_regex.join('|')})$`, 'i');
30
27
  }
31
28
 
32
29
  exports.hook_mail = function (next, connection, params) {
33
- const plugin = this;
34
- const txn = connection.transaction;
35
- if (!txn) { return; }
30
+ const txn = connection?.transaction;
31
+ if (!txn) return;
36
32
 
37
33
  const email = params[0].address();
38
34
  if (!email) {
39
- txn.results.add(plugin, {skip: 'mail_from.null', emit: true});
35
+ txn.results.add(this, {skip: 'mail_from.null', emit: true});
40
36
  return next();
41
37
  }
42
38
 
43
39
  const domain = params[0].host.toLowerCase();
44
40
 
45
- const anti_spoof = plugin.config.get('host_list.anti_spoof') || false;
41
+ const anti_spoof = this.config.get('host_list.anti_spoof') || false;
46
42
 
47
- if (plugin.in_host_list(domain) || plugin.in_host_regex(domain)) {
43
+ if (this.in_host_list(domain) || this.in_host_regex(domain)) {
48
44
  if (anti_spoof && !connection.relaying) {
49
- txn.results.add(plugin, {fail: 'mail_from.anti_spoof'});
45
+ txn.results.add(this, {fail: 'mail_from.anti_spoof'});
50
46
  return next(DENY, `Mail from domain '${domain}' is not allowed from your host`);
51
47
  }
52
- txn.results.add(plugin, {pass: 'mail_from'});
48
+ txn.results.add(this, {pass: 'mail_from'});
53
49
  txn.notes.local_sender = true;
54
50
  return next();
55
51
  }
56
52
 
57
- txn.results.add(plugin, {msg: 'mail_from!local'});
53
+ txn.results.add(this, {msg: 'mail_from!local'});
58
54
  return next();
59
55
  }
60
56
 
61
57
  exports.in_host_list = function (domain) {
62
- const plugin = this;
63
- plugin.logdebug(`checking ${domain} in config/host_list`);
64
- if (plugin.host_list[domain]) {
65
- return true;
66
- }
67
- return false;
58
+ this.logdebug(`checking ${domain} in config/host_list`);
59
+ return !!(this.host_list[domain]);
68
60
  }
69
61
 
70
62
  exports.in_host_regex = function (domain) {
71
- const plugin = this;
72
- if (!plugin.host_list_regex) return false;
73
- if (!plugin.host_list_regex.length) return false;
63
+ if (!this.host_list_regex) return false;
64
+ if (!this.host_list_regex.length) return false;
74
65
 
75
- plugin.logdebug(`checking ${domain} against config/host_list_regex `);
66
+ this.logdebug(`checking ${domain} against config/host_list_regex `);
76
67
 
77
- if (plugin.hl_re.test(domain)) { return true; }
78
- return false;
68
+ return !!(this.hl_re.test(domain));
79
69
  }
@@ -10,49 +10,47 @@
10
10
  // is enabled and the sending domain is local, the receipt is OK.
11
11
 
12
12
  exports.register = function () {
13
- const plugin = this;
14
- plugin.inherits('rcpt_to.host_list_base');
13
+ this.inherits('rcpt_to.host_list_base');
15
14
 
16
- plugin.load_host_list();
17
- plugin.load_host_list_regex();
15
+ this.load_host_list();
16
+ this.load_host_list_regex();
18
17
  }
19
18
 
20
19
  exports.hook_rcpt = function (next, connection, params) {
21
- const plugin = this;
22
- const txn = connection.transaction;
20
+ const txn = connection?.transaction;
23
21
  if (!txn) return;
24
22
 
25
23
  const rcpt = params[0];
26
24
 
27
25
  // Check for RCPT TO without an @ first - ignore those here
28
26
  if (!rcpt.host) {
29
- txn.results.add(plugin, {fail: 'rcpt!domain'});
27
+ txn.results.add(this, {fail: 'rcpt!domain'});
30
28
  return next();
31
29
  }
32
30
 
33
- connection.logdebug(plugin, `Checking if ${rcpt} host is in host_list`);
31
+ connection.logdebug(this, `Checking if ${rcpt} host is in host_list`);
34
32
 
35
33
  const domain = rcpt.host.toLowerCase();
36
34
 
37
- if (plugin.in_host_list(domain)) {
38
- txn.results.add(plugin, {pass: 'rcpt_to'});
35
+ if (this.in_host_list(domain)) {
36
+ txn.results.add(this, {pass: 'rcpt_to'});
39
37
  return next(OK);
40
38
  }
41
39
 
42
- if (plugin.in_host_regex(domain)) {
43
- txn.results.add(plugin, {pass: 'rcpt_to'});
40
+ if (this.in_host_regex(domain)) {
41
+ txn.results.add(this, {pass: 'rcpt_to'});
44
42
  return next(OK);
45
43
  }
46
44
 
47
45
  // in this case, a client with relaying privileges is sending FROM a local
48
46
  // domain. For them, any RCPT address is accepted.
49
47
  if (connection.relaying && txn.notes.local_sender) {
50
- txn.results.add(plugin, {pass: 'relaying local_sender'});
48
+ txn.results.add(this, {pass: 'relaying local_sender'});
51
49
  return next(OK);
52
50
  }
53
51
 
54
52
  // the MAIL FROM domain is not local and neither is the RCPT TO
55
53
  // Another RCPT plugin may yet vouch for this recipient.
56
- txn.results.add(plugin, {msg: 'rcpt!local'});
54
+ txn.results.add(this, {msg: 'rcpt!local'});
57
55
  return next();
58
56
  }
@@ -5,17 +5,19 @@
5
5
  // Consider using the karma plugin. It supports limiting the number
6
6
  // of recipients based on past behavior (good, bad, unknown)
7
7
 
8
- exports.hook_rcpt = function (next, connection) {
9
- if (connection.transaction.notes.rcpt_to_count) {
10
- connection.transaction.notes.rcpt_to_count++;
8
+ exports.hook_rcpt = function (next, connection = {}) {
9
+ const { notes } = connection.transaction
10
+
11
+ if (notes?.rcpt_to_count) {
12
+ notes.rcpt_to_count++;
11
13
  }
12
14
  else {
13
- connection.transaction.notes.rcpt_to_count = 1;
15
+ notes.rcpt_to_count = 1;
14
16
  }
15
17
 
16
18
  const max_count = this.config.get('rcpt_to.max_count') || 40;
17
19
 
18
- if (connection.transaction.notes.rcpt_to_count > max_count) {
20
+ if (notes.rcpt_to_count > max_count) {
19
21
  return next(DENYDISCONNECT, "Too many recipient attempts");
20
22
  }
21
23
  return next();
@@ -3,17 +3,15 @@
3
3
  // documentation via: haraka -h plugins/record_envelope_addresses
4
4
 
5
5
  exports.hook_rcpt = (next, connection, params) => {
6
- const txn = connection.transaction;
7
- if (txn) {
8
- txn.add_header('X-Envelope-To', params[0].address());
6
+ if (connection?.transaction) {
7
+ connection.transaction.add_header('X-Envelope-To', params[0].address());
9
8
  }
10
9
  next();
11
10
  }
12
11
 
13
12
  exports.hook_mail = (next, connection, params) => {
14
- const txn = connection.transaction;
15
- if (txn) {
16
- txn.add_header('X-Envelope-From', params[0].address());
13
+ if (connection?.transaction) {
14
+ connection.transaction.add_header('X-Envelope-From', params[0].address());
17
15
  }
18
16
  next();
19
17
  }
package/plugins/relay.js CHANGED
@@ -6,36 +6,34 @@ const ipaddr = require('ipaddr.js');
6
6
  const net = require('net');
7
7
 
8
8
  exports.register = function () {
9
- const plugin = this;
10
9
 
11
- plugin.load_relay_ini(); // plugin.cfg = { }
10
+ this.load_relay_ini(); // plugin.cfg = { }
12
11
 
13
- if (plugin.cfg.relay.acl) {
14
- plugin.load_acls(); // plugin.acl_allow = [..]
15
- plugin.register_hook('connect_init', 'acl');
16
- plugin.register_hook('connect', 'pass_relaying');
12
+ if (this.cfg.relay.acl) {
13
+ this.load_acls(); // plugin.acl_allow = [..]
14
+ this.register_hook('connect_init', 'acl');
15
+ this.register_hook('connect', 'pass_relaying');
17
16
  }
18
17
 
19
- if (plugin.cfg.relay.force_routing || plugin.cfg.relay.dest_domains) {
20
- plugin.load_dest_domains(); // plugin.dest.domains = { }
18
+ if (this.cfg.relay.force_routing || this.cfg.relay.dest_domains) {
19
+ this.load_dest_domains(); // plugin.dest.domains = { }
21
20
  }
22
21
 
23
- if (plugin.cfg.relay.force_routing) {
24
- plugin.register_hook('get_mx', 'force_routing');
22
+ if (this.cfg.relay.force_routing) {
23
+ this.register_hook('get_mx', 'force_routing');
25
24
  }
26
25
 
27
- if (plugin.cfg.relay.dest_domains) {
28
- plugin.register_hook('rcpt', 'dest_domains');
26
+ if (this.cfg.relay.dest_domains) {
27
+ this.register_hook('rcpt', 'dest_domains');
29
28
  }
30
29
 
31
- if (plugin.cfg.relay.all) {
32
- plugin.register_hook('rcpt', 'all');
30
+ if (this.cfg.relay.all) {
31
+ this.register_hook('rcpt', 'all');
33
32
  }
34
33
  }
35
34
 
36
35
  exports.load_relay_ini = function () {
37
- const plugin = this;
38
- plugin.cfg = plugin.config.get('relay.ini', {
36
+ this.cfg = this.config.get('relay.ini', {
39
37
  booleans: [
40
38
  '+relay.acl',
41
39
  '+relay.force_routing',
@@ -43,52 +41,49 @@ exports.load_relay_ini = function () {
43
41
  '-relay.dest_domains',
44
42
  ],
45
43
  }, () => {
46
- plugin.load_relay_ini();
44
+ this.load_relay_ini();
47
45
  });
48
46
  }
49
47
 
50
48
  exports.load_dest_domains = function () {
51
- const plugin = this;
52
- plugin.dest = plugin.config.get(
49
+ this.dest = this.config.get(
53
50
  'relay_dest_domains.ini',
54
51
  'ini',
55
- () => { plugin.load_dest_domains(); }
52
+ () => { this.load_dest_domains(); }
56
53
  );
57
54
  }
58
55
 
59
56
  exports.load_acls = function () {
60
- const plugin = this;
61
57
  const file_name = 'relay_acl_allow';
62
58
 
63
59
  // load with a self-referential callback
64
- plugin.acl_allow = plugin.config.get(file_name, 'list', () => {
65
- plugin.load_acls();
60
+ this.acl_allow = this.config.get(file_name, 'list', () => {
61
+ this.load_acls();
66
62
  });
67
63
 
68
- for (let i=0; i<plugin.acl_allow.length; i++) {
69
- const cidr = plugin.acl_allow[i].split('/');
64
+ for (let i=0; i<this.acl_allow.length; i++) {
65
+ const cidr = this.acl_allow[i].split('/');
70
66
  if (!net.isIP(cidr[0])) {
71
- plugin.logerror(plugin, `invalid entry in ${file_name}: ${cidr[0]}`);
67
+ this.logerror(this, `invalid entry in ${file_name}: ${cidr[0]}`);
72
68
  }
73
69
  if (!cidr[1]) {
74
- plugin.logerror(plugin, `appending missing CIDR suffix in: ${file_name}`);
75
- plugin.acl_allow[i] = `${cidr[0] }/32`;
70
+ this.logerror(this, `appending missing CIDR suffix in: ${file_name}`);
71
+ this.acl_allow[i] = `${cidr[0] }/32`;
76
72
  }
77
73
  }
78
74
  }
79
75
 
80
76
  exports.acl = function (next, connection) {
81
- const plugin = this;
82
- if (!plugin.cfg.relay.acl) { return next(); }
77
+ if (!this.cfg.relay.acl) { return next(); }
83
78
 
84
79
  connection.logdebug(this, `checking ${connection.remote.ip} in relay_acl_allow`);
85
80
 
86
- if (!plugin.is_acl_allowed(connection)) {
87
- connection.results.add(plugin, {skip: 'acl(unlisted)'});
81
+ if (!this.is_acl_allowed(connection)) {
82
+ connection.results.add(this, {skip: 'acl(unlisted)'});
88
83
  return next();
89
84
  }
90
85
 
91
- connection.results.add(plugin, {pass: 'acl'});
86
+ connection.results.add(this, {pass: 'acl'});
92
87
  connection.relaying = true;
93
88
  return next(OK);
94
89
  }
@@ -102,16 +97,14 @@ exports.pass_relaying = (next, connection) => {
102
97
  }
103
98
 
104
99
  exports.is_acl_allowed = function (connection) {
105
- const plugin = this;
106
- if (!plugin.acl_allow) { return false; }
107
- if (!plugin.acl_allow.length) { return false; }
100
+ if (!this.acl_allow) { return false; }
101
+ if (!this.acl_allow.length) { return false; }
108
102
 
109
- const ip = connection.remote.ip;
103
+ const { ip } = connection.remote;
110
104
 
111
- for (let i=0; i < plugin.acl_allow.length; i++) {
112
- const item = plugin.acl_allow[i];
113
- connection.logdebug(plugin, `checking if ${ip} is in ${item}`);
114
- const cidr = plugin.acl_allow[i].split('/');
105
+ for (const item of this.acl_allow) {
106
+ connection.logdebug(this, `checking if ${ip} is in ${item}`);
107
+ const cidr = item.split('/');
115
108
  const c_net = cidr[0];
116
109
  const c_mask = cidr[1] || 32;
117
110
 
@@ -120,7 +113,7 @@ exports.is_acl_allowed = function (connection) {
120
113
  if (net.isIPv6(ip) && net.isIPv4(c_net)) continue;
121
114
 
122
115
  if (ipaddr.parse(ip).match(ipaddr.parse(c_net), c_mask)) {
123
- connection.logdebug(plugin, `checking if ${ip} is in ${item}: yes`);
116
+ connection.logdebug(this, `checking if ${ip} is in ${item}: yes`);
124
117
  return true;
125
118
  }
126
119
  }
@@ -128,37 +121,37 @@ exports.is_acl_allowed = function (connection) {
128
121
  }
129
122
 
130
123
  exports.dest_domains = function (next, connection, params) {
131
- const plugin = this;
132
- if (!plugin.cfg.relay.dest_domains) { return next(); }
133
- const transaction = connection.transaction;
124
+ if (!this.cfg.relay.dest_domains) { return next(); }
125
+ const { relaying, transaction } = connection ?? {}
126
+ if (!transaction) return next();
134
127
 
135
128
  // Skip this if the host is already allowed to relay
136
- if (connection.relaying) {
137
- transaction.results.add(plugin, {skip: 'relay_dest_domain(relay)'});
129
+ if (relaying) {
130
+ transaction.results.add(this, {skip: 'relay_dest_domain(relay)'});
138
131
  return next();
139
132
  }
140
133
 
141
- if (!plugin.dest) {
142
- transaction.results.add(plugin, {err: 'relay_dest_domain(no config!)'});
134
+ if (!this.dest) {
135
+ transaction.results.add(this, {err: 'relay_dest_domain(no config!)'});
143
136
  return next();
144
137
  }
145
138
 
146
- if (!plugin.dest.domains) {
147
- transaction.results.add(plugin, {skip: 'relay_dest_domain(config)'});
139
+ if (!this.dest.domains) {
140
+ transaction.results.add(this, {skip: 'relay_dest_domain(config)'});
148
141
  return next();
149
142
  }
150
143
 
151
144
  const dest_domain = params[0].host;
152
- connection.logdebug(plugin, `dest_domain = ${dest_domain}`);
145
+ connection.logdebug(this, `dest_domain = ${dest_domain}`);
153
146
 
154
- const dst_cfg = plugin.dest.domains[dest_domain];
147
+ const dst_cfg = this.dest.domains[dest_domain];
155
148
  if (!dst_cfg) {
156
- transaction.results.add(plugin, {fail: 'relay_dest_domain'});
149
+ transaction.results.add(this, {fail: 'relay_dest_domain'});
157
150
  return next(DENY, "You are not allowed to relay");
158
151
  }
159
152
 
160
- const action = JSON.parse(dst_cfg).action;
161
- connection.logdebug(plugin, `found config for ${dest_domain}: ${action}`);
153
+ const { action } = JSON.parse(dst_cfg);
154
+ connection.logdebug(this, `found config for ${dest_domain}: ${action}`);
162
155
 
163
156
  switch (action) {
164
157
  case "accept":
@@ -166,53 +159,50 @@ exports.dest_domains = function (next, connection, params) {
166
159
  // address to be considered 'local'. What advantage does relaying
167
160
  // bring?
168
161
  connection.relaying = true;
169
- transaction.results.add(plugin, {pass: 'relay_dest_domain'});
162
+ transaction.results.add(this, {pass: 'relay_dest_domain'});
170
163
  return next(OK);
171
164
  case "continue":
172
165
  // why oh why? Only reason I can think of is to enable outbound.
173
166
  connection.relaying = true;
174
- transaction.results.add(plugin, {pass: 'relay_dest_domain'});
167
+ transaction.results.add(this, {pass: 'relay_dest_domain'});
175
168
  return next(CONT); // same as next()
176
169
  case "deny":
177
- transaction.results.add(plugin, {fail: 'relay_dest_domain'});
170
+ transaction.results.add(this, {fail: 'relay_dest_domain'});
178
171
  return next(DENY, "You are not allowed to relay");
179
172
  }
180
173
 
181
- transaction.results.add(plugin, {fail: 'relay_dest_domain'});
174
+ transaction.results.add(this, {fail: 'relay_dest_domain'});
182
175
  return next(DENY, "Mail for that recipient is not accepted here.");
183
176
  }
184
177
 
185
178
  exports.force_routing = function (next, hmail, domain) {
186
- const plugin = this;
187
- if (!plugin.cfg.relay.force_routing) { return next(); }
188
- if (!plugin.dest) { return next(); }
189
- if (!plugin.dest.domains) { return next(); }
190
- let route = plugin.dest.domains[domain];
179
+ if (!this.cfg.relay.force_routing) { return next(); }
180
+ if (!this.dest) { return next(); }
181
+ if (!this.dest.domains) { return next(); }
182
+ let route = this.dest.domains[domain];
191
183
 
192
184
  if (!route) {
193
- route = plugin.dest.domains.any;
185
+ route = this.dest.domains.any;
194
186
  if (!route) {
195
- plugin.logdebug(plugin, `using normal MX lookup for: ${domain}`);
187
+ this.logdebug(this, `using normal MX lookup for: ${domain}`);
196
188
  return next();
197
189
  }
198
190
  }
199
191
 
200
- const nexthop = JSON.parse(route).nexthop;
192
+ const { nexthop } = JSON.parse(route);
201
193
  if (!nexthop) {
202
- plugin.logdebug(plugin, `using normal MX lookup for: ${domain}`);
194
+ this.logdebug(this, `using normal MX lookup for: ${domain}`);
203
195
  return next();
204
196
  }
205
197
 
206
- plugin.logdebug(plugin, `using ${nexthop} for: ${domain}`);
198
+ this.logdebug(this, `using ${nexthop} for: ${domain}`);
207
199
  return next(OK, nexthop);
208
200
  }
209
201
 
210
202
  exports.all = function (next, connection, params) {
211
- // relay everything - could be useful for a spamtrap
212
- const plugin = this;
213
- if (!plugin.cfg.relay.all) { return next(); }
203
+ if (!this.cfg.relay.all) { return next(); }
214
204
 
215
- connection.loginfo(plugin, `confirming recipient ${params[0]}`);
205
+ connection.loginfo(this, `confirming recipient ${params[0]}`);
216
206
  connection.relaying = true;
217
207
  next(OK);
218
208
  }
@@ -1,8 +1,7 @@
1
1
  const crypto = require('crypto');
2
2
 
3
3
  exports.hook_init_child = function (next) {
4
- const plugin = this;
5
4
  Math.seedrandom(crypto.randomBytes(256).toString('hex'));
6
- plugin.logdebug("reseeded rng");
5
+ this.logdebug("reseeded rng");
7
6
  next();
8
7
  }