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
package/plugins/bounce.js CHANGED
@@ -1,44 +1,38 @@
1
1
  // bounce tests
2
2
  const tlds = require('haraka-tld');
3
+ const { SPF } = require('haraka-plugin-spf');
3
4
 
4
5
  const net_utils = require('haraka-net-utils');
5
- const SPF = require('./spf').SPF;
6
-
7
- // Override logging in SPF module
8
- SPF.prototype.log_debug = str => exports.logdebug(str)
9
6
 
10
7
  exports.register = function () {
11
- const plugin = this;
12
- plugin.load_bounce_ini();
13
- plugin.load_bounce_bad_rcpt();
14
-
15
- plugin.register_hook('mail', 'reject_all');
16
- plugin.register_hook('data', 'single_recipient');
17
- plugin.register_hook('data', 'bad_rcpt');
18
- plugin.register_hook('data_post', 'empty_return_path');
19
- plugin.register_hook('data', 'bounce_spf_enable');
20
- plugin.register_hook('data_post', 'bounce_spf');
21
- plugin.register_hook('data_post', 'non_local_msgid');
8
+ this.load_bounce_ini();
9
+ this.load_bounce_bad_rcpt();
10
+
11
+ this.register_hook('mail', 'reject_all');
12
+ this.register_hook('data', 'single_recipient');
13
+ this.register_hook('data', 'bad_rcpt');
14
+ this.register_hook('data_post', 'empty_return_path');
15
+ this.register_hook('data', 'bounce_spf_enable');
16
+ this.register_hook('data_post', 'bounce_spf');
17
+ this.register_hook('data_post', 'non_local_msgid');
22
18
  }
23
19
 
24
20
  exports.load_bounce_bad_rcpt = function () {
25
- const plugin = this;
26
21
 
27
- const new_list = plugin.config.get('bounce_bad_rcpt', 'list', () => {
28
- plugin.load_bounce_bad_rcpt();
22
+ const new_list = this.config.get('bounce_bad_rcpt', 'list', () => {
23
+ this.load_bounce_bad_rcpt();
29
24
  });
30
25
 
31
26
  const invalids = {};
32
- for (let i=0; i < new_list.length; i++) {
33
- invalids[new_list[i]] = true;
27
+ for (const element of new_list) {
28
+ invalids[element] = true;
34
29
  }
35
30
 
36
- plugin.cfg.invalid_addrs = invalids;
31
+ this.cfg.invalid_addrs = invalids;
37
32
  }
38
33
 
39
34
  exports.load_bounce_ini = function () {
40
- const plugin = this;
41
- plugin.cfg = plugin.config.get('bounce.ini', {
35
+ this.cfg = this.config.get('bounce.ini', {
42
36
  booleans: [
43
37
  '-check.reject_all',
44
38
  '+check.single_recipient',
@@ -53,48 +47,41 @@ exports.load_bounce_ini = function () {
53
47
  '-reject.non_local_msgid',
54
48
  ],
55
49
  }, () => {
56
- plugin.load_bounce_ini();
50
+ this.load_bounce_ini();
57
51
  });
58
52
 
59
53
  // Legacy config handling
60
- if (plugin.cfg.main.reject_invalid) {
61
- plugin.logerror('bounce.ini is out of date, please update!');
62
- plugin.cfg.check.single_recipient=true;
63
- plugin.cfg.reject.single_recipient=true;
54
+ if (this.cfg.main.reject_invalid) {
55
+ this.logerror('bounce.ini is out of date, please update!');
56
+ this.cfg.check.single_recipient=true;
57
+ this.cfg.reject.single_recipient=true;
64
58
  }
65
59
 
66
- if (plugin.cfg.main.reject_all) {
67
- plugin.logerror('bounce.ini is out of date, please update!');
68
- plugin.cfg.check.reject_all=true;
60
+ if (this.cfg.main.reject_all) {
61
+ this.logerror('bounce.ini is out of date, please update!');
62
+ this.cfg.check.reject_all=true;
69
63
  }
70
64
  }
71
65
 
72
66
  exports.reject_all = function (next, connection, params) {
73
- const plugin = this;
74
- if (!plugin.cfg.check.reject_all) { return next(); }
67
+ if (!this.cfg.check.reject_all) return next();
75
68
 
76
69
  const mail_from = params[0];
70
+ // bounce messages are from null senders
71
+ if (!this.has_null_sender(connection, mail_from)) return next();
77
72
 
78
- if (!plugin.has_null_sender(connection, mail_from)) {
79
- return next(); // bounce messages are from null senders
80
- }
81
-
82
- connection.transaction.results.add(plugin,
83
- {fail: 'bounces_accepted', emit: true });
73
+ connection.transaction.results.add(this, {fail: 'bounces_accepted', emit: true });
84
74
  return next(DENY, 'No bounces accepted here');
85
75
  }
86
76
 
87
77
  exports.single_recipient = function (next, connection) {
88
- const plugin = this;
89
- if (!plugin.cfg.check.single_recipient) return next();
90
- if (!plugin.has_null_sender(connection)) return next();
91
-
92
- const transaction = connection.transaction;
78
+ if (!this?.cfg?.check?.single_recipient) return next();
79
+ if (!this?.has_null_sender(connection)) return next();
80
+ const { transaction, relaying, remote } = connection;
93
81
 
94
82
  // Valid bounces have a single recipient
95
- if (connection.transaction.rcpt_to.length === 1) {
96
- transaction.results.add(plugin,
97
- {pass: 'single_recipient', emit: true });
83
+ if (transaction.rcpt_to.length === 1) {
84
+ transaction.results.add(this, {pass: 'single_recipient', emit: true });
98
85
  return next();
99
86
  }
100
87
 
@@ -103,33 +90,29 @@ exports.single_recipient = function (next, connection) {
103
90
  // to distribution groups using the null-sender if
104
91
  // the option 'Do not send delivery reports' is
105
92
  // checked (not sure if this is default or not)
106
- if (connection.relaying) {
107
- transaction.results.add(plugin,
108
- {skip: 'single_recipient(relay)', emit: true });
93
+ if (relaying) {
94
+ transaction.results.add(this, {skip: 'single_recipient(relay)', emit: true });
109
95
  return next();
110
96
  }
111
- if (connection.remote.is_private) {
112
- transaction.results.add(plugin,
113
- {skip: 'single_recipient(private_ip)', emit: true });
97
+ if (remote.is_private) {
98
+ transaction.results.add(this, {skip: 'single_recipient(private_ip)', emit: true });
114
99
  return next();
115
100
  }
116
101
 
117
- connection.loginfo(plugin, `bounce with too many recipients to: ${connection.transaction.rcpt_to.join(',')}`);
102
+ connection.loginfo(this, `bounce with too many recipients to: ${transaction.rcpt_to.join(',')}`);
118
103
 
119
- transaction.results.add(plugin, {fail: 'single_recipient', emit: true });
104
+ transaction.results.add(this, {fail: 'single_recipient', emit: true });
120
105
 
121
- if (!plugin.cfg.reject.single_recipient) return next();
106
+ if (!this.cfg.reject.single_recipient) return next();
122
107
 
123
108
  return next(DENY, 'this bounce message does not have 1 recipient');
124
109
  }
125
110
 
126
111
  exports.empty_return_path = function (next, connection) {
127
- const plugin = this;
128
- if (!plugin.cfg.check.empty_return_path) return next();
129
- if (!plugin.has_null_sender(connection)) return next();
130
-
131
- const transaction = connection.transaction;
112
+ if (!this.cfg.check.empty_return_path) return next();
113
+ if (!this.has_null_sender(connection)) return next();
132
114
 
115
+ const { transaction } = connection;
133
116
  // Bounce messages generally do not have a Return-Path set. This checks
134
117
  // for that. But whether it should is worth questioning...
135
118
 
@@ -144,56 +127,54 @@ exports.empty_return_path = function (next, connection) {
144
127
  // Return-Path, aka Reverse-PATH, Envelope FROM, RFC5321.MailFrom
145
128
  // validate that the Return-Path header is empty, RFC 3834
146
129
 
147
- const rp = connection.transaction.header.get('Return-Path');
130
+ const rp = transaction.header.get('Return-Path');
148
131
  if (!rp) {
149
- transaction.results.add(plugin, {pass: 'empty_return_path' });
132
+ transaction.results.add(this, {pass: 'empty_return_path' });
150
133
  return next();
151
134
  }
152
135
 
153
136
  if (rp === '<>') {
154
- transaction.results.add(plugin, {pass: 'empty_return_path' });
137
+ transaction.results.add(this, {pass: 'empty_return_path' });
155
138
  return next();
156
139
  }
157
140
 
158
- transaction.results.add(plugin, {fail: 'empty_return_path', emit: true });
141
+ transaction.results.add(this, {fail: 'empty_return_path', emit: true });
159
142
  return next(DENY, 'bounce with non-empty Return-Path (RFC 3834)');
160
143
  }
161
144
 
162
145
  exports.bad_rcpt = function (next, connection) {
163
- const plugin = this;
164
- const transaction = connection.transaction;
165
-
166
- if (!plugin.cfg.check.bad_rcpt) return next();
167
- if (!plugin.has_null_sender(connection)) return next();
168
- if (!plugin.cfg.invalid_addrs) return next();
169
-
170
- for (let i=0; i < connection.transaction.rcpt_to.length; i++) {
171
- const rcpt = connection.transaction.rcpt_to[i].address();
172
- if (!plugin.cfg.invalid_addrs[rcpt]) continue;
173
- transaction.results.add(plugin, {fail: 'bad_rcpt', emit: true });
146
+ if (!this.cfg.check.bad_rcpt) return next();
147
+ if (!this.has_null_sender(connection)) return next();
148
+ if (!this.cfg.invalid_addrs) return next();
149
+
150
+ const { transaction } = connection;
151
+ for (const element of transaction.rcpt_to) {
152
+ const rcpt = element.address();
153
+ if (!this.cfg.invalid_addrs[rcpt]) continue;
154
+ transaction.results.add(this, {fail: 'bad_rcpt', emit: true });
174
155
  return next(DENY, 'That recipient does not accept bounces');
175
156
  }
157
+ transaction.results.add(this, {pass: 'bad_rcpt'});
176
158
 
177
- transaction.results.add(plugin, {pass: 'bad_rcpt'});
178
159
  return next();
179
160
  }
180
161
 
181
162
  exports.has_null_sender = function (connection, mail_from) {
182
- const plugin = this;
183
- const transaction = connection.transaction;
163
+ // ok ?
164
+ const transaction = connection?.transaction;
165
+ if (!transaction) return false;
184
166
 
185
- if (!mail_from) mail_from = connection.transaction.mail_from;
167
+ if (!mail_from) mail_from = transaction.mail_from;
186
168
 
187
169
  // bounces have a null sender.
188
170
  // null sender could also be tested with mail_from.user
189
171
  // Why would isNull() exist if it wasn't the right way to test this?
190
-
191
172
  if (mail_from.isNull()) {
192
- transaction.results.add(plugin, {isa: 'yes'});
173
+ transaction.results.add(this, {isa: 'yes'});
193
174
  return true;
194
175
  }
195
176
 
196
- transaction.results.add(plugin, {isa: 'no'});
177
+ transaction.results.add(this, {isa: 'no'});
197
178
  return false;
198
179
  }
199
180
 
@@ -201,11 +182,13 @@ const message_id_re = /^Message-ID:\s*(<?[^>]+>?)/mig;
201
182
 
202
183
  function find_message_id_headers (headers, body, connection, self) {
203
184
  if (!body) return;
185
+
204
186
  let match;
205
187
  while ((match = message_id_re.exec(body.bodytext))) {
206
188
  const mid = match[1];
207
189
  headers[mid] = true;
208
190
  }
191
+
209
192
  for (let i=0,l=body.children.length; i < l; i++) {
210
193
  // Recure to any MIME children
211
194
  find_message_id_headers(headers, body.children[i], connection, self);
@@ -213,12 +196,11 @@ function find_message_id_headers (headers, body, connection, self) {
213
196
  }
214
197
 
215
198
  exports.non_local_msgid = function (next, connection) {
216
- const plugin = this;
217
- if (!plugin.cfg.check.non_local_msgid) return next();
218
- if (!plugin.has_null_sender(connection)) return next();
219
-
220
- const transaction = connection.transaction;
199
+ if (!this.cfg.check.non_local_msgid) return next();
200
+ if (!this.has_null_sender(connection)) return next();
221
201
 
202
+ const transaction = connection?.transaction;
203
+ if (!transaction) return next();
222
204
  // Bounce messages usually contain the headers of the original message
223
205
  // in the body. This parses the body, searching for the Message-ID header.
224
206
  // It then inspects the contents of that header, extracting the domain part,
@@ -234,44 +216,43 @@ exports.non_local_msgid = function (next, connection) {
234
216
  // http://lamsonproject.org/docs/bounce_detection.html
235
217
 
236
218
  let matches = {}
237
- find_message_id_headers(matches, transaction.body, connection, plugin);
219
+ find_message_id_headers(matches, transaction.body, connection, this);
238
220
  matches = Object.keys(matches);
239
- connection.logdebug(plugin, `found Message-IDs: ${matches.join(', ')}`);
221
+ connection.logdebug(this, `found Message-IDs: ${matches.join(', ')}`);
240
222
 
241
223
  if (!matches.length) {
242
- connection.loginfo(plugin, 'no Message-ID matches');
243
- transaction.results.add(plugin, { fail: 'Message-ID' });
244
- if (!plugin.cfg.reject.non_local_msgid) return next();
224
+ connection.loginfo(this, 'no Message-ID matches');
225
+ transaction.results.add(this, { fail: 'Message-ID' });
226
+ if (!this.cfg.reject.non_local_msgid) return next();
245
227
  return next(DENY, `bounce without Message-ID in headers, unable to verify that I sent it`);
246
228
  }
247
229
 
248
230
  const domains=[];
249
- for (let i=0; i < matches.length; i++) {
250
- const res = matches[i].match(/@([^>]*)>?/i);
231
+ for (const match of matches) {
232
+ const res = match.match(/@([^>]*)>?/i);
251
233
  if (!res) continue;
252
234
  domains.push(res[1]);
253
235
  }
254
236
 
255
237
  if (domains.length === 0) {
256
- connection.loginfo(plugin,
257
- 'no domain(s) parsed from Message-ID headers');
258
- transaction.results.add(plugin, { fail: 'Message-ID parseable' });
259
- if (!plugin.cfg.reject.non_local_msgid) return next();
238
+ connection.loginfo(this, 'no domain(s) parsed from Message-ID headers');
239
+ transaction.results.add(this, { fail: 'Message-ID parseable' });
240
+ if (!this.cfg.reject.non_local_msgid) return next();
260
241
  return next(DENY, `bounce with invalid Message-ID, I didn't send it.`);
261
242
  }
262
243
 
263
- connection.logdebug(plugin, domains);
244
+ connection.logdebug(this, domains);
264
245
 
265
246
  const valid_domains=[];
266
- for (let j=0; j < domains.length; j++) {
267
- const org_dom = tlds.get_organizational_domain(domains[j]);
247
+ for (const domain of domains) {
248
+ const org_dom = tlds.get_organizational_domain(domain);
268
249
  if (!org_dom) { continue; }
269
250
  valid_domains.push(org_dom);
270
251
  }
271
252
 
272
253
  if (valid_domains.length === 0) {
273
- transaction.results.add(plugin, { fail: 'Message-ID valid domain' });
274
- if (!plugin.cfg.reject.non_local_msgid) return next();
254
+ transaction.results.add(this, { fail: 'Message-ID valid domain' });
255
+ if (!this.cfg.reject.non_local_msgid) return next();
275
256
  return next(DENY, `bounce Message-ID without valid domain, I didn't send it.`);
276
257
  }
277
258
 
@@ -307,30 +288,31 @@ function find_received_headers (ips, body, connection, self) {
307
288
  }
308
289
 
309
290
  exports.bounce_spf_enable = function (next, connection) {
310
- const plugin = this;
311
- if (plugin.cfg.check.bounce_spf) {
291
+ if (!connection.transaction) return next();
292
+ if (this.cfg.check.bounce_spf) {
312
293
  connection.transaction.parse_body = true;
313
294
  }
314
295
  return next();
315
296
  }
316
297
 
317
298
  exports.bounce_spf = function (next, connection) {
318
- const plugin = this;
319
- if (!plugin.cfg.check.bounce_spf) return next();
320
- if (!plugin.has_null_sender(connection)) return next();
321
- const txn = connection.transaction;
299
+ if (!this.cfg.check.bounce_spf) return next();
300
+ if (!this.has_null_sender(connection)) return next();
301
+
302
+ const txn = connection?.transaction;
303
+ if (!txn) return next();
322
304
 
323
305
  // Recurse through all textual parts and store all parsed IPs
324
306
  // in an object to remove any duplicates which might appear.
325
307
  let ips = {};
326
- find_received_headers(ips, txn.body, connection, plugin);
308
+ find_received_headers(ips, txn.body, connection, this);
327
309
  ips = Object.keys(ips);
328
310
  if (!ips.length) {
329
- connection.loginfo(plugin, 'No received headers found in message');
311
+ connection.loginfo(this, 'No received headers found in message');
330
312
  return next();
331
313
  }
332
314
 
333
- connection.logdebug(plugin, `found IPs to check: ${ips.join(', ')}`);
315
+ connection.logdebug(this, `found IPs to check: ${ips.join(', ')}`);
334
316
 
335
317
  let pending = 0;
336
318
  let aborted = false;
@@ -348,10 +330,10 @@ exports.bounce_spf = function (next, connection) {
348
330
  }
349
331
 
350
332
  timer = setTimeout(() => {
351
- connection.logerror(plugin, 'Timed out');
352
- txn.results.add(plugin, { skip: 'bounce_spf(timeout)' });
333
+ connection.logerror(this, 'Timed out');
334
+ txn.results.add(this, { skip: 'bounce_spf(timeout)' });
353
335
  return run_cb(true);
354
- }, (plugin.timeout - 1) * 1000);
336
+ }, (this.timeout - 1) * 1000);
355
337
 
356
338
  ips.forEach(ip => {
357
339
  if (aborted) return;
@@ -362,30 +344,30 @@ exports.bounce_spf = function (next, connection) {
362
344
  if (aborted) return;
363
345
  pending--;
364
346
  if (err) {
365
- connection.logerror(plugin, err.message);
347
+ connection.logerror(this, err.message);
366
348
  return run_cb();
367
349
  }
368
- connection.logdebug(plugin, `ip=${ip} spf_result=${spf.result(result)}`);
350
+ connection.logdebug(this, `ip=${ip} spf_result=${spf.result(result)}`);
369
351
  switch (result) {
370
352
  case (spf.SPF_NONE):
371
353
  // falls through, domain doesn't publish an SPF record
372
354
  case (spf.SPF_TEMPERROR):
373
355
  case (spf.SPF_PERMERROR):
374
356
  // Abort as all subsequent lookups will return this
375
- connection.logdebug(plugin, `Aborted: SPF returned ${spf.result(result)}`);
376
- txn.results.add(plugin, { skip: 'bounce_spf' });
357
+ connection.logdebug(this, `Aborted: SPF returned ${spf.result(result)}`);
358
+ txn.results.add(this, { skip: 'bounce_spf' });
377
359
  return run_cb(true);
378
360
  case (spf.SPF_PASS):
379
361
  // Presume this is a valid bounce
380
362
  // TODO: this could be spoofed; could weight each IP to combat
381
- connection.loginfo(plugin, `Valid bounce originated from ${ip}`);
382
- txn.results.add(plugin, { pass: 'bounce_spf' });
363
+ connection.loginfo(this, `Valid bounce originated from ${ip}`);
364
+ txn.results.add(this, { pass: 'bounce_spf' });
383
365
  return run_cb(true);
384
366
  }
385
367
  if (pending === 0 && !aborted) {
386
368
  // We've checked all the IPs and none of them returned Pass
387
- txn.results.add(plugin, {fail: 'bounce_spf', emit: true });
388
- if (!plugin.cfg.reject.bounce_spf) return run_cb();
369
+ txn.results.add(this, {fail: 'bounce_spf', emit: true });
370
+ if (!this.cfg.reject.bounce_spf) return run_cb();
389
371
  return run_cb(false, DENY, 'Invalid bounce (spoofed sender)');
390
372
  }
391
373
  }