Haraka 3.1.0 → 3.1.2

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 (160) hide show
  1. package/.prettierignore +4 -0
  2. package/CONTRIBUTORS.md +5 -5
  3. package/Changes.md +69 -50
  4. package/Plugins.md +3 -1
  5. package/README.md +1 -1
  6. package/bin/haraka +475 -478
  7. package/config/outbound.ini +3 -0
  8. package/connection.js +1072 -1108
  9. package/docs/Connection.md +29 -30
  10. package/docs/CoreConfig.md +38 -39
  11. package/docs/CustomReturnCodes.md +0 -1
  12. package/docs/HAProxy.md +2 -2
  13. package/docs/Header.md +1 -1
  14. package/docs/Logging.md +29 -5
  15. package/docs/Outbound.md +93 -78
  16. package/docs/Plugins.md +103 -108
  17. package/docs/Transaction.md +49 -51
  18. package/docs/Tutorial.md +127 -143
  19. package/docs/deprecated/access.md +0 -1
  20. package/docs/deprecated/backscatterer.md +2 -3
  21. package/docs/deprecated/connect.rdns_access.md +18 -27
  22. package/docs/deprecated/data.headers.md +0 -1
  23. package/docs/deprecated/data.nomsgid.md +1 -2
  24. package/docs/deprecated/data.noreceived.md +1 -2
  25. package/docs/deprecated/data.rfc5322_header_checks.md +1 -2
  26. package/docs/deprecated/dkim_sign.md +13 -17
  27. package/docs/deprecated/dkim_verify.md +9 -17
  28. package/docs/deprecated/dnsbl.md +36 -38
  29. package/docs/deprecated/dnswl.md +41 -43
  30. package/docs/deprecated/lookup_rdns.strict.md +21 -34
  31. package/docs/deprecated/mail_from.access.md +17 -25
  32. package/docs/deprecated/mail_from.blocklist.md +9 -12
  33. package/docs/deprecated/mail_from.nobounces.md +1 -2
  34. package/docs/deprecated/rcpt_to.access.md +20 -27
  35. package/docs/deprecated/rcpt_to.blocklist.md +10 -13
  36. package/docs/deprecated/rcpt_to.routes.md +0 -1
  37. package/docs/deprecated/rdns.regexp.md +13 -15
  38. package/docs/plugins/aliases.md +89 -89
  39. package/docs/plugins/auth/auth_bridge.md +5 -7
  40. package/docs/plugins/auth/auth_ldap.md +11 -14
  41. package/docs/plugins/auth/auth_proxy.md +10 -12
  42. package/docs/plugins/auth/auth_vpopmaild.md +5 -6
  43. package/docs/plugins/auth/flat_file.md +4 -4
  44. package/docs/plugins/block_me.md +3 -3
  45. package/docs/plugins/data.signatures.md +1 -2
  46. package/docs/plugins/delay_deny.md +3 -4
  47. package/docs/plugins/max_unrecognized_commands.md +4 -4
  48. package/docs/plugins/prevent_credential_leaks.md +6 -6
  49. package/docs/plugins/process_title.md +18 -18
  50. package/docs/plugins/queue/deliver.md +2 -3
  51. package/docs/plugins/queue/discard.md +4 -4
  52. package/docs/plugins/queue/lmtp.md +1 -3
  53. package/docs/plugins/queue/qmail-queue.md +7 -9
  54. package/docs/plugins/queue/quarantine.md +16 -21
  55. package/docs/plugins/queue/rabbitmq.md +8 -11
  56. package/docs/plugins/queue/rabbitmq_amqplib.md +43 -39
  57. package/docs/plugins/queue/smtp_bridge.md +7 -10
  58. package/docs/plugins/queue/smtp_forward.md +42 -34
  59. package/docs/plugins/queue/smtp_proxy.md +30 -29
  60. package/docs/plugins/queue/test.md +1 -3
  61. package/docs/plugins/rcpt_to.in_host_list.md +6 -6
  62. package/docs/plugins/rcpt_to.max_count.md +1 -1
  63. package/docs/plugins/record_envelope_addresses.md +3 -3
  64. package/docs/plugins/reseed_rng.md +6 -6
  65. package/docs/plugins/status.md +9 -8
  66. package/docs/plugins/tarpit.md +7 -11
  67. package/docs/plugins/tls.md +12 -17
  68. package/docs/plugins/toobusy.md +4 -4
  69. package/docs/plugins/xclient.md +3 -3
  70. package/docs/tutorials/Migrating_from_v1_to_v2.md +19 -41
  71. package/docs/tutorials/SettingUpOutbound.md +6 -9
  72. package/endpoint.js +35 -38
  73. package/eslint.config.mjs +22 -19
  74. package/haraka.js +42 -47
  75. package/host_pool.js +75 -79
  76. package/http/html/404.html +45 -49
  77. package/http/html/index.html +39 -28
  78. package/http/package.json +2 -4
  79. package/line_socket.js +27 -28
  80. package/logger.js +182 -201
  81. package/outbound/client_pool.js +34 -27
  82. package/outbound/config.js +64 -59
  83. package/outbound/fsync_writestream.js +24 -25
  84. package/outbound/hmail.js +888 -835
  85. package/outbound/index.js +194 -187
  86. package/outbound/qfile.js +49 -52
  87. package/outbound/queue.js +197 -190
  88. package/outbound/timer_queue.js +41 -43
  89. package/outbound/tls.js +68 -61
  90. package/outbound/todo.js +11 -11
  91. package/package.json +38 -33
  92. package/plugins/.eslintrc.yaml +0 -1
  93. package/plugins/auth/auth_base.js +123 -127
  94. package/plugins/auth/auth_bridge.js +7 -7
  95. package/plugins/auth/auth_proxy.js +121 -126
  96. package/plugins/auth/auth_vpopmaild.js +84 -85
  97. package/plugins/auth/flat_file.js +18 -17
  98. package/plugins/block_me.js +31 -31
  99. package/plugins/data.signatures.js +13 -13
  100. package/plugins/delay_deny.js +65 -61
  101. package/plugins/prevent_credential_leaks.js +23 -23
  102. package/plugins/process_title.js +125 -128
  103. package/plugins/profile.js +5 -5
  104. package/plugins/queue/deliver.js +3 -3
  105. package/plugins/queue/discard.js +13 -14
  106. package/plugins/queue/lmtp.js +16 -17
  107. package/plugins/queue/qmail-queue.js +54 -55
  108. package/plugins/queue/quarantine.js +68 -70
  109. package/plugins/queue/rabbitmq.js +80 -87
  110. package/plugins/queue/rabbitmq_amqplib.js +75 -54
  111. package/plugins/queue/smtp_bridge.js +16 -16
  112. package/plugins/queue/smtp_forward.js +175 -179
  113. package/plugins/queue/smtp_proxy.js +69 -71
  114. package/plugins/queue/test.js +9 -9
  115. package/plugins/rcpt_to.host_list_base.js +30 -34
  116. package/plugins/rcpt_to.in_host_list.js +19 -19
  117. package/plugins/record_envelope_addresses.js +4 -4
  118. package/plugins/reseed_rng.js +4 -4
  119. package/plugins/status.js +90 -97
  120. package/plugins/tarpit.js +25 -14
  121. package/plugins/tls.js +68 -68
  122. package/plugins/toobusy.js +21 -23
  123. package/plugins/xclient.js +51 -53
  124. package/plugins.js +276 -293
  125. package/rfc1869.js +30 -35
  126. package/server.js +308 -299
  127. package/smtp_client.js +244 -228
  128. package/test/.eslintrc.yaml +0 -1
  129. package/test/connection.js +127 -134
  130. package/test/endpoint.js +53 -47
  131. package/test/fixtures/line_socket.js +12 -12
  132. package/test/fixtures/util_hmailitem.js +89 -85
  133. package/test/host_pool.js +90 -92
  134. package/test/installation/plugins/base_plugin.js +2 -2
  135. package/test/installation/plugins/folder_plugin/index.js +2 -3
  136. package/test/installation/plugins/inherits.js +3 -3
  137. package/test/installation/plugins/load_first.js +2 -3
  138. package/test/installation/plugins/plugin.js +1 -3
  139. package/test/installation/plugins/tls.js +2 -4
  140. package/test/logger.js +135 -116
  141. package/test/outbound/hmail.js +49 -35
  142. package/test/outbound/index.js +118 -101
  143. package/test/outbound/qfile.js +51 -53
  144. package/test/outbound_bounce_net_errors.js +84 -69
  145. package/test/outbound_bounce_rfc3464.js +235 -165
  146. package/test/plugins/auth/auth_base.js +420 -279
  147. package/test/plugins/auth/auth_vpopmaild.js +38 -39
  148. package/test/plugins/queue/smtp_forward.js +126 -104
  149. package/test/plugins/rcpt_to.host_list_base.js +85 -67
  150. package/test/plugins/rcpt_to.in_host_list.js +159 -112
  151. package/test/plugins/status.js +71 -64
  152. package/test/plugins/tls.js +37 -34
  153. package/test/plugins.js +97 -92
  154. package/test/rfc1869.js +19 -26
  155. package/test/server.js +293 -272
  156. package/test/smtp_client.js +180 -176
  157. package/test/tls_socket.js +62 -66
  158. package/test/transaction.js +159 -160
  159. package/tls_socket.js +331 -333
  160. package/transaction.js +129 -137
package/plugins.js CHANGED
@@ -1,44 +1,43 @@
1
- 'use strict';
1
+ 'use strict'
2
2
  // load all defined plugins
3
3
 
4
4
  // node built-ins
5
- const fs = require('node:fs');
6
- const path = require('node:path');
7
- const vm = require('node:vm');
5
+ const fs = require('node:fs')
6
+ const path = require('node:path')
7
+ const vm = require('node:vm')
8
8
 
9
9
  // npm modules
10
- exports.config = require('haraka-config');
11
- const constants = require('haraka-constants');
10
+ exports.config = require('haraka-config')
11
+ const constants = require('haraka-constants')
12
12
 
13
13
  // local modules
14
- const logger = require('./logger');
14
+ const logger = require('./logger')
15
15
 
16
- exports.registered_hooks = {};
17
- exports.registered_plugins = {};
18
- exports.plugin_list = [];
16
+ exports.registered_hooks = {}
17
+ exports.registered_plugins = {}
18
+ exports.plugin_list = []
19
19
 
20
- let order = 0;
20
+ let order = 0
21
21
 
22
22
  class Plugin {
23
-
24
- constructor (name) {
25
- this.name = name;
26
- this.base = {};
27
- this.timeout = get_timeout(name);
28
- this._get_plugin_path();
29
- this.config = this._get_config();
30
- this.hooks = {};
23
+ constructor(name) {
24
+ this.name = name
25
+ this.base = {}
26
+ this.timeout = get_timeout(name)
27
+ this._get_plugin_path()
28
+ this.config = this._get_config()
29
+ this.hooks = {}
31
30
  }
32
31
 
33
- haraka_require (name) {
34
- return require(`./${name}`);
32
+ haraka_require(name) {
33
+ return require(`./${name}`)
35
34
  }
36
35
 
37
- core_require (name) {
38
- return this.haraka_require(name);
36
+ core_require(name) {
37
+ return this.haraka_require(name)
39
38
  }
40
39
 
41
- _get_plugin_path () {
40
+ _get_plugin_path() {
42
41
  /* From https://github.com/haraka/Haraka/pull/1278#issuecomment-168856528
43
42
  In Development mode, or install via a plain "git clone":
44
43
 
@@ -56,155 +55,147 @@ class Plugin {
56
55
  Plugin in <core_haraka_dir>/node_modules.
57
56
  */
58
57
 
59
- this.hasPackageJson = false;
60
- const name = this.name.startsWith('haraka-plugin-') ? this.name.substr(14) : this.name;
61
- if (this.name !== name) this.name = name;
58
+ this.hasPackageJson = false
59
+ const name = this.name.startsWith('haraka-plugin-') ? this.name.substr(14) : this.name
60
+ if (this.name !== name) this.name = name
62
61
 
63
- let paths = [];
62
+ let paths = []
64
63
  if (process.env.HARAKA) {
65
64
  // Installed mode - started via bin/haraka
66
- paths = paths.concat(plugin_search_paths(process.env.HARAKA, name));
65
+ paths = paths.concat(plugin_search_paths(process.env.HARAKA, name))
67
66
 
68
67
  // permit local "folder" plugins (/$name/package.json) (see #1649)
69
68
  paths.push(
70
69
  path.resolve(process.env.HARAKA, 'plugins', name, 'package.json'),
71
- path.resolve(process.env.HARAKA, 'node_modules', name, 'package.json')
72
- );
70
+ path.resolve(process.env.HARAKA, 'node_modules', name, 'package.json'),
71
+ )
73
72
  }
74
73
 
75
74
  // development mode
76
- paths = paths.concat(plugin_search_paths(__dirname, name));
75
+ paths = paths.concat(plugin_search_paths(__dirname, name))
77
76
  for (const pp of paths) {
78
- if (this.plugin_path) continue;
77
+ if (this.plugin_path) continue
79
78
  try {
80
- fs.statSync(pp);
81
- this.plugin_path = pp;
79
+ fs.statSync(pp)
80
+ this.plugin_path = pp
82
81
  if (path.basename(pp) === 'package.json') {
83
- this.hasPackageJson = true;
82
+ this.hasPackageJson = true
84
83
  }
85
- }
86
- catch (ignore) {}
84
+ } catch (ignore) {}
87
85
  }
88
86
  }
89
87
 
90
- _get_config () {
88
+ _get_config() {
91
89
  if (this.hasPackageJson) {
92
90
  // It's a package/folder plugin - look in plugin folder for defaults,
93
91
  // haraka/config folder for overrides
94
- return exports.config.module_config(
95
- path.dirname(this.plugin_path),
96
- process.env.HARAKA || __dirname
97
- );
92
+ return exports.config.module_config(path.dirname(this.plugin_path), process.env.HARAKA || __dirname)
98
93
  }
99
94
  if (process.env.HARAKA) {
100
95
  // Plain .js file, installed mode - look in core folder for defaults,
101
96
  // install dir for overrides
102
- return exports.config.module_config(__dirname, process.env.HARAKA);
97
+ return exports.config.module_config(__dirname, process.env.HARAKA)
103
98
  }
104
99
  if (process.env.HARAKA_TEST_DIR) {
105
- return exports.config.module_config(process.env.HARAKA_TEST_DIR);
100
+ return exports.config.module_config(process.env.HARAKA_TEST_DIR)
106
101
  }
107
102
 
108
103
  // Plain .js file, git mode - just look in this folder
109
- return exports.config.module_config(__dirname);
104
+ return exports.config.module_config(__dirname)
110
105
  }
111
106
 
112
- register_hook (hook_name, method_name, priority) {
113
- priority = parseInt(priority);
114
- if (!priority) priority = 0;
115
- if (priority > 100) priority = 100;
116
- if (priority < -100) priority = -100;
107
+ register_hook(hook_name, method_name, priority) {
108
+ priority = parseInt(priority)
109
+ if (!priority) priority = 0
110
+ if (priority > 100) priority = 100
111
+ if (priority < -100) priority = -100
117
112
 
118
113
  if (!Array.isArray(exports.registered_hooks[hook_name])) {
119
- exports.registered_hooks[hook_name] = [];
114
+ exports.registered_hooks[hook_name] = []
120
115
  }
121
116
  exports.registered_hooks[hook_name].push({
122
117
  plugin: this.name,
123
118
  method: method_name,
124
119
  priority,
125
120
  timeout: this.timeout,
126
- order: order++
127
- });
128
- this.hooks[hook_name] = this.hooks[hook_name] || [];
129
- this.hooks[hook_name].push(method_name);
121
+ order: order++,
122
+ })
123
+ this.hooks[hook_name] = this.hooks[hook_name] || []
124
+ this.hooks[hook_name].push(method_name)
130
125
 
131
- plugins.logdebug(`registered hook ${hook_name} to ${this.name}.${method_name} priority ${priority}`);
126
+ plugins.logdebug(`registered hook ${hook_name} to ${this.name}.${method_name} priority ${priority}`)
132
127
  }
133
128
 
134
- register () {} // noop
129
+ register() {} // noop
135
130
 
136
- inherits (parent_name) {
137
- const parent_plugin = plugins._load_and_compile_plugin(parent_name);
131
+ inherits(parent_name) {
132
+ const parent_plugin = plugins._load_and_compile_plugin(parent_name)
138
133
  for (const method in parent_plugin) {
139
134
  if (!this[method]) {
140
- this[method] = parent_plugin[method];
135
+ this[method] = parent_plugin[method]
141
136
  }
142
137
  }
143
138
  if (parent_plugin.register) {
144
- parent_plugin.register.call(this);
139
+ parent_plugin.register.call(this)
145
140
  }
146
- this.base[parent_name] = parent_plugin;
141
+ this.base[parent_name] = parent_plugin
147
142
  }
148
143
 
149
- _make_custom_require () {
150
- return module => {
144
+ _make_custom_require() {
145
+ return (module) => {
151
146
  if (this.hasPackageJson) {
152
- const mod = require(module);
153
- constants.import(global);
154
- global.server = plugins.server;
155
- return mod;
147
+ const mod = require(module)
148
+ constants.import(global)
149
+ global.server = plugins.server
150
+ return mod
156
151
  }
157
152
 
158
153
  if (module === './config') {
159
- return this.config;
154
+ return this.config
160
155
  }
161
156
 
162
157
  if (!/^\./.test(module)) {
163
- return require(module);
158
+ return require(module)
164
159
  }
165
160
 
166
- if (fs.existsSync(path.join(__dirname, `${module}.js`)) ||
167
- fs.existsSync(path.join(__dirname, module))) {
168
- return require(module);
161
+ if (fs.existsSync(path.join(__dirname, `${module}.js`)) || fs.existsSync(path.join(__dirname, module))) {
162
+ return require(module)
169
163
  }
170
164
 
171
- return require(path.join(path.dirname(this.plugin_path), module));
172
- };
165
+ return require(path.join(path.dirname(this.plugin_path), module))
166
+ }
173
167
  }
174
168
 
175
- _get_code (pp) {
176
-
169
+ _get_code(pp) {
177
170
  if (this.hasPackageJson) {
178
- let packageDir = path.dirname(pp);
171
+ let packageDir = path.dirname(pp)
179
172
  if (/^win(32|64)/.test(process.platform)) {
180
173
  // escape the c:\path\back\slashes else they disappear
181
- packageDir = packageDir.replace(/\\/g, '\\\\');
174
+ packageDir = packageDir.replace(/\\/g, '\\\\')
182
175
  }
183
- return `var _p = require("${packageDir}"); for (var k in _p) { exports[k] = _p[k] }`;
176
+ return `var _p = require("${packageDir}"); for (var k in _p) { exports[k] = _p[k] }`
184
177
  }
185
178
 
186
179
  try {
187
- return `"use strict";${fs.readFileSync(pp)}`;
188
- }
189
- catch (err) {
180
+ return `"use strict";${fs.readFileSync(pp)}`
181
+ } catch (err) {
190
182
  if (exports.config.get('smtp.ini').main.ignore_bad_plugins) {
191
- plugins.logcrit(`Loading ${this.name} failed: ${err}`);
192
- return;
183
+ plugins.logcrit(`Loading ${this.name} failed: ${err}`)
184
+ return
193
185
  }
194
- throw `Loading plugin ${this.name} failed: ${err}`;
186
+ throw `Loading plugin ${this.name} failed: ${err}`
195
187
  }
196
188
  }
197
189
 
198
- _compile () {
199
-
200
- const pp = this.plugin_path;
201
- const code = this._get_code(pp);
202
- if (!code) return;
190
+ _compile() {
191
+ const pp = this.plugin_path
192
+ const code = this._get_code(pp)
193
+ if (!code) return
203
194
 
204
195
  const sandbox = {
205
196
  require: this._make_custom_require(),
206
197
  __filename: pp,
207
- __dirname: path.dirname(pp),
198
+ __dirname: path.dirname(pp),
208
199
  exports: this,
209
200
  setTimeout,
210
201
  clearTimeout,
@@ -214,22 +205,21 @@ class Plugin {
214
205
  Buffer,
215
206
  Math,
216
207
  server: plugins.server,
217
- setImmediate
218
- };
208
+ setImmediate,
209
+ }
219
210
  if (this.hasPackageJson) {
220
- delete sandbox.__filename;
211
+ delete sandbox.__filename
221
212
  }
222
- constants.import(sandbox);
213
+ constants.import(sandbox)
223
214
  try {
224
- vm.runInNewContext(code, sandbox, pp);
225
- }
226
- catch (err) {
227
- plugins.logcrit(`compiling '${this.name}' failed`);
215
+ vm.runInNewContext(code, sandbox, pp)
216
+ } catch (err) {
217
+ plugins.logcrit(`compiling '${this.name}' failed`)
228
218
  if (exports.config.get('smtp.ini').main.ignore_bad_plugins) {
229
- plugins.logcrit(`Loading '${this.name}' failed: ${err.message} - skipping`);
230
- return;
219
+ plugins.logcrit(`Loading '${this.name}' failed: ${err.message} - skipping`)
220
+ return
231
221
  }
232
- throw err; // default is to re-throw and stop Haraka
222
+ throw err // default is to re-throw and stop Haraka
233
223
  }
234
224
  }
235
225
  }
@@ -237,342 +227,336 @@ class Plugin {
237
227
  exports.shutdown_plugins = () => {
238
228
  for (const i in exports.registered_plugins) {
239
229
  if (exports.registered_plugins[i].shutdown) {
240
- exports.registered_plugins[i].shutdown();
230
+ exports.registered_plugins[i].shutdown()
241
231
  }
242
232
  }
243
233
  }
244
234
 
245
- process.on('message', msg => {
235
+ process.on('message', (msg) => {
246
236
  if (msg.event && msg.event == 'plugins.shutdown') {
247
- plugins.loginfo("Shutting down");
248
- exports.shutdown_plugins();
237
+ plugins.loginfo('Shutting down')
238
+ exports.shutdown_plugins()
249
239
  }
250
- });
240
+ })
251
241
 
252
- function plugin_search_paths (prefix, name) {
242
+ function plugin_search_paths(prefix, name) {
253
243
  return [
254
244
  path.resolve(prefix, 'plugins', `${name}.js`),
255
245
  path.resolve(prefix, 'node_modules', `haraka-plugin-${name}`, 'package.json'),
256
- path.resolve(prefix, '..', `haraka-plugin-${name}`, 'package.json')
257
- ];
246
+ path.resolve(prefix, '..', `haraka-plugin-${name}`, 'package.json'),
247
+ ]
258
248
  }
259
249
 
260
- function get_timeout (name) {
261
- let timeout = parseFloat((exports.config.get(`${name}.timeout`)));
250
+ function get_timeout(name) {
251
+ let timeout = parseFloat(exports.config.get(`${name}.timeout`))
262
252
  if (isNaN(timeout)) {
263
- plugins.logdebug(`no timeout in ${name}.timeout`);
264
- timeout = parseFloat(exports.config.get('plugin_timeout'));
253
+ plugins.logdebug(`no timeout in ${name}.timeout`)
254
+ timeout = parseFloat(exports.config.get('plugin_timeout'))
265
255
  }
266
256
  if (isNaN(timeout)) {
267
- plugins.logdebug('no timeout in plugin_timeout');
268
- timeout = 30;
257
+ plugins.logdebug('no timeout in plugin_timeout')
258
+ timeout = 30
269
259
  }
270
260
 
271
- plugins.logdebug(`plugin ${name} timeout is: ${timeout}s`);
272
- return timeout;
261
+ plugins.logdebug(`plugin ${name} timeout is: ${timeout}s`)
262
+ return timeout
273
263
  }
274
264
 
275
265
  logger.add_log_methods(Plugin)
276
266
 
277
- const plugins = exports;
267
+ const plugins = exports
278
268
 
279
269
  logger.add_log_methods(plugins, 'plugins')
280
270
 
281
- plugins.Plugin = Plugin;
271
+ plugins.Plugin = Plugin
282
272
 
283
- plugins.load_plugins = override => {
284
- plugins.logdebug('Loading');
285
- let plugin_list;
273
+ plugins.load_plugins = (override) => {
274
+ plugins.logdebug('Loading')
275
+ let plugin_list
286
276
  if (override) {
287
- if (!Array.isArray(override)) override = [ override ];
288
- plugin_list = override;
289
- }
290
- else {
291
- plugin_list = exports.config.get('plugins', 'list');
277
+ if (!Array.isArray(override)) override = [override]
278
+ plugin_list = override
279
+ } else {
280
+ plugin_list = exports.config.get('plugins', 'list')
292
281
  }
293
282
 
294
283
  for (let plugin of plugin_list) {
295
284
  if (plugin.startsWith('haraka-plugin-')) plugin = plugin.substr(14)
296
285
  if (plugins.deprecated[plugin]) {
297
- plugins.lognotice(`${plugin} has been replaced by '${plugins.deprecated[plugin]}'. Please update config/plugins`)
298
- plugins.load_plugin(plugins.deprecated[plugin]);
299
- }
300
- else {
301
- plugins.load_plugin(plugin);
286
+ plugins.lognotice(
287
+ `${plugin} has been replaced by '${plugins.deprecated[plugin]}'. Please update config/plugins`,
288
+ )
289
+ plugins.load_plugin(plugins.deprecated[plugin])
290
+ } else {
291
+ plugins.load_plugin(plugin)
302
292
  }
303
293
  }
304
294
 
305
- plugins.plugin_list = Object.keys(plugins.registered_plugins);
295
+ plugins.plugin_list = Object.keys(plugins.registered_plugins)
306
296
 
307
297
  // Sort registered_hooks by priority
308
298
  for (const hook of Object.keys(plugins.registered_hooks)) {
309
299
  plugins.registered_hooks[hook].sort((a, b) => {
310
- if (a.priority < b.priority) return -1;
311
- if (a.priority > b.priority) return 1;
300
+ if (a.priority < b.priority) return -1
301
+ if (a.priority > b.priority) return 1
312
302
  if (a.priority == b.priority) {
313
- if (a.order > b.order) return 1;
314
- return -1;
303
+ if (a.order > b.order) return 1
304
+ return -1
315
305
  }
316
- return 0;
317
- });
306
+ return 0
307
+ })
318
308
  }
319
309
 
320
- logger.dump_logs(); // now logging plugins are loaded.
310
+ logger.dump_logs() // now logging plugins are loaded.
321
311
  }
322
312
 
323
313
  plugins.deprecated = {
324
- 'auth/auth_ldap' : 'auth-ldap',
325
- 'backscatterer' : 'dns-list',
326
- 'connect.asn' : 'asn',
327
- 'connect.fcrdns' : 'fcrdns',
328
- 'connect.geoip' : 'geoip',
329
- 'connect.p0f' : 'p0f',
330
- 'connect.rdns_access' : 'access',
331
- 'data.nomsgid' : 'headers',
332
- 'data.noreceived' : 'headers',
314
+ 'auth/auth_ldap': 'auth-ldap',
315
+ backscatterer: 'dns-list',
316
+ 'connect.asn': 'asn',
317
+ 'connect.fcrdns': 'fcrdns',
318
+ 'connect.geoip': 'geoip',
319
+ 'connect.p0f': 'p0f',
320
+ 'connect.rdns_access': 'access',
321
+ 'data.nomsgid': 'headers',
322
+ 'data.noreceived': 'headers',
333
323
  'data.rfc5322_header_checks': 'headers',
334
- 'data.headers' : 'headers',
335
- 'dkim_sign' : 'dkim',
336
- 'dkim_verify' : 'dkim',
337
- 'data.uribl' : 'uribl',
338
- 'dnsbl' : 'dns-list',
339
- 'dnswl' : 'dns-list',
340
- 'log.syslog' : 'syslog',
341
- 'mail_from.access' : 'access',
342
- 'mail_from.blocklist' : 'access',
343
- 'mail_from.nobounces' : 'bounce',
344
- 'max_unrecognized_commands' : 'limit',
345
- 'rate_limit' : 'limit',
346
- 'rcpt_to.access' : 'access',
347
- 'rcpt_to.blocklist' : 'access',
348
- 'rcpt_to.ldap' : 'rcpt-ldap',
349
- 'rcpt_to.max_count' : 'limit',
350
- 'rcpt_to.qmail_deliverable' : 'qmail-deliverable',
351
- 'rdns.regexp' : 'access',
352
- 'relay_acl' : 'relay',
353
- 'relay_all' : 'relay',
354
- 'relay_force_routing' : 'relay',
324
+ 'data.headers': 'headers',
325
+ dkim_sign: 'dkim',
326
+ dkim_verify: 'dkim',
327
+ 'data.uribl': 'uribl',
328
+ dnsbl: 'dns-list',
329
+ dnswl: 'dns-list',
330
+ 'log.syslog': 'syslog',
331
+ 'mail_from.access': 'access',
332
+ 'mail_from.blocklist': 'access',
333
+ 'mail_from.nobounces': 'bounce',
334
+ max_unrecognized_commands: 'limit',
335
+ rate_limit: 'limit',
336
+ 'rcpt_to.access': 'access',
337
+ 'rcpt_to.blocklist': 'access',
338
+ 'rcpt_to.ldap': 'rcpt-ldap',
339
+ 'rcpt_to.max_count': 'limit',
340
+ 'rcpt_to.qmail_deliverable': 'qmail-deliverable',
341
+ 'rdns.regexp': 'access',
342
+ relay_acl: 'relay',
343
+ relay_all: 'relay',
344
+ relay_force_routing: 'relay',
355
345
  }
356
346
 
357
- plugins.load_plugin = name => {
358
- plugins.loginfo(`loading ${name}`);
347
+ plugins.load_plugin = (name) => {
348
+ plugins.loginfo(`loading ${name}`)
359
349
 
360
- const plugin = plugins._load_and_compile_plugin(name);
350
+ const plugin = plugins._load_and_compile_plugin(name)
361
351
  if (plugin) {
362
- plugins._register_plugin(plugin);
352
+ plugins._register_plugin(plugin)
363
353
  }
364
354
 
365
- plugins.registered_plugins[name] = plugin;
355
+ plugins.registered_plugins[name] = plugin
366
356
  }
367
357
 
368
358
  // Set in server.js; initialized to empty object
369
359
  // to prevent it from blowing up any unit tests.
370
- plugins.server = { notes: {} };
360
+ plugins.server = { notes: {} }
371
361
 
372
- plugins._load_and_compile_plugin = name => {
373
- const plugin = new Plugin(name);
362
+ plugins._load_and_compile_plugin = (name) => {
363
+ const plugin = new Plugin(name)
374
364
  if (!plugin.plugin_path) {
375
- const err = `Loading plugin ${plugin.name} failed: No plugin with this name found`;
365
+ const err = `Loading plugin ${plugin.name} failed: No plugin with this name found`
376
366
  if (exports.config.get('smtp.ini').main.ignore_bad_plugins) {
377
- plugins.logcrit(err);
378
- return;
367
+ plugins.logcrit(err)
368
+ return
379
369
  }
380
- throw err;
370
+ throw err
381
371
  }
382
- plugin._compile();
383
- return plugin;
372
+ plugin._compile()
373
+ return plugin
384
374
  }
385
375
 
386
- plugins._register_plugin = plugin => {
387
- plugin.register();
376
+ plugins._register_plugin = (plugin) => {
377
+ plugin.register()
388
378
 
389
379
  // register any hook_blah methods.
390
380
  for (const method in plugin) {
391
- const result = method.match(/^hook_(\w+)\b/);
381
+ const result = method.match(/^hook_(\w+)\b/)
392
382
  if (result) {
393
- plugin.register_hook(result[1], method);
383
+ plugin.register_hook(result[1], method)
394
384
  }
395
385
  }
396
386
  }
397
387
 
398
388
  plugins.run_hooks = (hook, object, params) => {
399
389
  if (client_disconnected(object) && !is_required_hook(hook)) {
400
- object.logdebug(`aborting ${hook} hook`);
401
- return;
390
+ object.logdebug(`aborting ${hook} hook`)
391
+ return
402
392
  }
403
393
 
404
- if (hook !== 'log') object.logdebug(`running ${hook} hooks`);
394
+ if (hook !== 'log') object.logdebug(`running ${hook} hooks`)
405
395
 
406
396
  if (is_required_hook(hook) && object.current_hook) {
407
- object.current_hook[2](); // call cancel function
397
+ object.current_hook[2]() // call cancel function
408
398
  }
409
399
 
410
- if (!is_required_hook(hook) && hook !== 'deny' &&
411
- object.hooks_to_run && object.hooks_to_run.length) {
412
- throw new Error('We are already running hooks! Fatal error!');
400
+ if (!is_required_hook(hook) && hook !== 'deny' && object.hooks_to_run && object.hooks_to_run.length) {
401
+ throw new Error('We are already running hooks! Fatal error!')
413
402
  }
414
403
 
415
404
  if (hook === 'deny') {
416
405
  // Save the hooks_to_run list so that we can run any remaining
417
406
  // plugins on the previous hook once this hook is complete.
418
- object.saved_hooks_to_run = object.hooks_to_run;
407
+ object.saved_hooks_to_run = object.hooks_to_run
419
408
  }
420
- object.hooks_to_run = [];
409
+ object.hooks_to_run = []
421
410
 
422
411
  if (plugins.registered_hooks[hook]) {
423
412
  for (const item of plugins.registered_hooks[hook]) {
424
- const plugin = plugins.registered_plugins[item.plugin];
425
- object.hooks_to_run.push([plugin, item.method]);
413
+ const plugin = plugins.registered_plugins[item.plugin]
414
+ object.hooks_to_run.push([plugin, item.method])
426
415
  }
427
416
  }
428
417
 
429
- plugins.run_next_hook(hook, object, params);
418
+ plugins.run_next_hook(hook, object, params)
430
419
  }
431
420
 
432
421
  plugins.run_next_hook = (hook, object, params) => {
433
422
  if (client_disconnected(object) && !is_required_hook(hook)) {
434
- object.logdebug(`aborting ${hook} hook`);
435
- return;
423
+ object.logdebug(`aborting ${hook} hook`)
424
+ return
436
425
  }
437
- let called_once = false;
438
- let timeout_id;
439
- let timed_out = false;
440
- let cancelled = false;
441
- let item;
426
+ let called_once = false
427
+ let timeout_id
428
+ let timed_out = false
429
+ let cancelled = false
430
+ let item
442
431
 
443
- function cancel () {
444
- if (timeout_id) clearTimeout(timeout_id);
445
- cancelled = true;
432
+ function cancel() {
433
+ if (timeout_id) clearTimeout(timeout_id)
434
+ cancelled = true
446
435
  }
447
- function callback (retval, msg) {
448
- if (timeout_id) clearTimeout(timeout_id);
449
- object.current_hook = null;
450
- if (cancelled) return; // This hook has been cancelled
436
+ function callback(retval, msg) {
437
+ if (timeout_id) clearTimeout(timeout_id)
438
+ object.current_hook = null
439
+ if (cancelled) return // This hook has been cancelled
451
440
 
452
441
  // Bail if client has disconnected
453
442
  if (client_disconnected(object) && !is_required_hook(hook)) {
454
- object.logdebug(`ignoring ${item[0].name} plugin callback`);
455
- return;
443
+ object.logdebug(`ignoring ${item[0].name} plugin callback`)
444
+ return
456
445
  }
457
446
  if (called_once && hook !== 'log') {
458
447
  if (!timed_out) {
459
- object.logerror(`${item[0].name} plugin ran callback ` +
460
- `multiple times - ignoring subsequent calls`);
448
+ object.logerror(`${item[0].name} plugin ran callback ` + `multiple times - ignoring subsequent calls`)
461
449
  // Write a stack trace to the log to aid debugging
462
- object.logerror((new Error()).stack);
450
+ object.logerror(new Error().stack)
463
451
  }
464
- return;
452
+ return
465
453
  }
466
- called_once = true;
467
- if (!retval) retval = constants.cont;
454
+ called_once = true
455
+ if (!retval) retval = constants.cont
468
456
 
469
- log_run_item(item, hook, retval, object, params, msg);
457
+ log_run_item(item, hook, retval, object, params, msg)
470
458
 
471
459
  if (object.hooks_to_run.length !== 0) {
472
460
  if (retval === constants.cont) {
473
- return plugins.run_next_hook(hook, object, params);
461
+ return plugins.run_next_hook(hook, object, params)
474
462
  }
475
463
  if (hook === 'connect_init' || hook === 'disconnect') {
476
464
  // these hooks ignore retval and always run for every plugin
477
- return plugins.run_next_hook(hook, object, params);
465
+ return plugins.run_next_hook(hook, object, params)
478
466
  }
479
467
  }
480
468
 
481
- const respond_method = `${hook}_respond`;
482
- if (item && is_deny_retval(retval) && hook.substr(0,5) !== 'init_') {
483
- object.deny_respond = get_denyfn(object, hook, params, retval, msg, respond_method);
484
- plugins.run_hooks('deny', object, [retval, msg, item[0].name, item[1], params, hook]);
485
- }
486
- else {
487
- object.hooks_to_run = [];
488
- object[respond_method](retval, msg, params);
469
+ const respond_method = `${hook}_respond`
470
+ if (item && is_deny_retval(retval) && hook.substr(0, 5) !== 'init_') {
471
+ object.deny_respond = get_denyfn(object, hook, params, retval, msg, respond_method)
472
+ plugins.run_hooks('deny', object, [retval, msg, item[0].name, item[1], params, hook])
473
+ } else {
474
+ object.hooks_to_run = []
475
+ object[respond_method](retval, msg, params)
489
476
  }
490
477
  }
491
478
 
492
- if (!object.hooks_to_run.length) return callback();
479
+ if (!object.hooks_to_run.length) return callback()
493
480
 
494
481
  // shift the next one off the stack and run it.
495
- item = object.hooks_to_run.shift();
496
- item.push(cancel);
482
+ item = object.hooks_to_run.shift()
483
+ item.push(cancel)
497
484
 
498
485
  if (hook !== 'log' && item[0].timeout) {
499
486
  timeout_id = setTimeout(() => {
500
- timed_out = true;
501
- object.logcrit(`Plugin ${item[0].name} timed out on hook ${hook} - make sure it calls the callback`);
502
- callback(constants.denysoft, 'plugin timeout');
503
- }, item[0].timeout * 1000);
487
+ timed_out = true
488
+ object.logcrit(`Plugin ${item[0].name} timed out on hook ${hook} - make sure it calls the callback`)
489
+ callback(constants.denysoft, 'plugin timeout')
490
+ }, item[0].timeout * 1000)
504
491
  }
505
492
 
506
493
  if (hook !== 'log') {
507
- object.logdebug(`running ${hook} hook in ${item[0].name} plugin`);
494
+ object.logdebug(`running ${hook} hook in ${item[0].name} plugin`)
508
495
  }
509
496
 
510
497
  if (object.transaction?.notes.skip_plugins.includes(item[0].name)) {
511
- object.logdebug(`skipping ${item[0].name}_${hook} by request in notes`);
512
- return callback();
498
+ object.logdebug(`skipping ${item[0].name}_${hook} by request in notes`)
499
+ return callback()
513
500
  }
514
501
 
515
502
  try {
516
- object.current_hook = item;
517
- object.hook = hook;
518
- item[0][ item[1] ].call(item[0], callback, object, params);
519
- }
520
- catch (err) {
503
+ object.current_hook = item
504
+ object.hook = hook
505
+ item[0][item[1]].call(item[0], callback, object, params)
506
+ } catch (err) {
521
507
  if (hook !== 'log') {
522
- object.logcrit(`Plugin ${item[0].name} failed: ${(err.stack || err)}`);
508
+ object.logcrit(`Plugin ${item[0].name} failed: ${err.stack || err}`)
523
509
  }
524
- callback();
510
+ callback()
525
511
  }
526
512
  }
527
513
 
528
- function client_disconnected (object) {
529
- if (object.constructor.name === 'Connection' &&
530
- object.state >= constants.connection.state.DISCONNECTING) {
531
- object.logdebug('client has disconnected');
532
- return true;
514
+ function client_disconnected(object) {
515
+ if (object.constructor.name === 'Connection' && object.state >= constants.connection.state.DISCONNECTING) {
516
+ object.logdebug('client has disconnected')
517
+ return true
533
518
  }
534
- return false;
519
+ return false
535
520
  }
536
521
 
537
- function is_required_hook (hook) {
522
+ function is_required_hook(hook) {
538
523
  // Hooks that must always run
539
524
  switch (hook) {
540
525
  case 'reset_transaction':
541
526
  case 'disconnect':
542
527
  case 'log':
543
- return true;
528
+ return true
544
529
  default:
545
- return false;
530
+ return false
546
531
  }
547
532
  }
548
533
 
549
- function log_run_item (item, hook, retval, object, params, msg) {
550
- if (!item) return;
551
- if (hook === 'log') return;
534
+ function log_run_item(item, hook, retval, object, params, msg) {
535
+ if (!item) return
536
+ if (hook === 'log') return
552
537
 
553
- let log = 'logdebug';
554
- const is_not_cont = (retval !== constants.cont &&
555
- logger.would_log(logger.LOGINFO));
556
- if (is_not_cont) log = 'loginfo';
538
+ let log = 'logdebug'
539
+ const is_not_cont = retval !== constants.cont && logger.would_log(logger.LOGINFO)
540
+ if (is_not_cont) log = 'loginfo'
557
541
  if (is_not_cont || logger.would_log(logger.LOGDEBUG)) {
558
542
  object[log]({
559
543
  hook,
560
- 'plugin' : item[0].name,
561
- 'function' : item[1],
562
- 'params' : ((params) ? ((typeof params === 'string') ? params : params[0]) : ''),
563
- 'retval' : constants.translate(retval),
564
- 'msg' : sanitize(msg),
565
- });
544
+ plugin: item[0].name,
545
+ function: item[1],
546
+ params: params ? (typeof params === 'string' ? params : params[0]) : '',
547
+ retval: constants.translate(retval),
548
+ msg: sanitize(msg),
549
+ })
566
550
  }
567
551
  }
568
552
 
569
- function sanitize (msg) {
553
+ function sanitize(msg) {
570
554
  if (!msg) return ''
571
555
  if (typeof msg === 'string') return msg
572
556
  if (typeof msg === 'object') {
573
557
  if (msg.constructor.name === 'DSN') return msg.reply
574
- const sanitized = { ...msg }; // copy the message
575
- for (const priv of ['password','auth_pass']) {
558
+ const sanitized = { ...msg } // copy the message
559
+ for (const priv of ['password', 'auth_pass']) {
576
560
  delete sanitized[priv]
577
561
  }
578
562
  return JSON.stringify(sanitized)
@@ -580,37 +564,36 @@ function sanitize (msg) {
580
564
  logger.logerror(`what is ${msg} (typeof ${typeof msg})?`)
581
565
  }
582
566
 
583
- function is_deny_retval (val) {
567
+ function is_deny_retval(val) {
584
568
  switch (val) {
585
569
  case constants.deny:
586
570
  case constants.denysoft:
587
571
  case constants.denydisconnect:
588
572
  case constants.denysoftdisconnect:
589
- return true;
573
+ return true
590
574
  }
591
- return false;
575
+ return false
592
576
  }
593
577
 
594
- function get_denyfn (object, hook, params, retval, msg, respond_method) {
578
+ function get_denyfn(object, hook, params, retval, msg, respond_method) {
595
579
  return (deny_retval, deny_msg) => {
596
580
  switch (deny_retval) {
597
581
  case constants.ok:
598
582
  // Override rejection
599
- object.loginfo(`deny(soft?) overriden by deny hook${(deny_msg ? ': deny_msg' : '')}`);
583
+ object.loginfo(`deny(soft?) overriden by deny hook${deny_msg ? ': deny_msg' : ''}`)
600
584
  // Restore hooks_to_run with saved copy so that
601
585
  // any other plugins on this hook can also run.
602
586
  if (object.saved_hooks_to_run.length > 0) {
603
- object.hooks_to_run = object.saved_hooks_to_run;
604
- plugins.run_next_hook(hook, object, params);
605
- }
606
- else {
607
- object[respond_method](constants.cont, deny_msg, params);
587
+ object.hooks_to_run = object.saved_hooks_to_run
588
+ plugins.run_next_hook(hook, object, params)
589
+ } else {
590
+ object[respond_method](constants.cont, deny_msg, params)
608
591
  }
609
- break;
592
+ break
610
593
  default:
611
- object.saved_hooks_to_run = [];
612
- object.hooks_to_run = [];
613
- object[respond_method](retval, msg, params);
594
+ object.saved_hooks_to_run = []
595
+ object.hooks_to_run = []
596
+ object[respond_method](retval, msg, params)
614
597
  }
615
- };
598
+ }
616
599
  }