Haraka 3.0.2 → 3.0.4

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 (267) hide show
  1. package/.eslintrc.yaml +5 -9
  2. package/.prettierrc.yml +1 -0
  3. package/CONTRIBUTORS.md +11 -0
  4. package/Changes.md +1393 -1211
  5. package/Dockerfile +3 -3
  6. package/Plugins.md +119 -106
  7. package/README.md +7 -16
  8. package/TODO +1 -24
  9. package/bin/haraka +197 -298
  10. package/config/auth_flat_file.ini +2 -0
  11. package/config/auth_vpopmaild.ini +4 -2
  12. package/config/dhparams.pem +8 -0
  13. package/config/mail_from.is_resolvable.ini +4 -2
  14. package/config/me +1 -0
  15. package/config/outbound.ini +0 -2
  16. package/config/plugins +36 -35
  17. package/config/rabbitmq_amqplib.ini +8 -1
  18. package/config/smtp.ini +0 -1
  19. package/config/smtp.json +17 -0
  20. package/config/tls_cert.pem +23 -0
  21. package/config/tls_key.pem +28 -0
  22. package/connection.js +46 -73
  23. package/contrib/bsd-rc.d/haraka +3 -1
  24. package/contrib/plugin2npm.sh +6 -36
  25. package/docs/Connection.md +1 -1
  26. package/docs/CoreConfig.md +2 -2
  27. package/docs/Logging.md +7 -21
  28. package/docs/Outbound.md +104 -210
  29. package/docs/Plugins.md +47 -40
  30. package/docs/Transaction.md +59 -82
  31. package/docs/{plugins → deprecated}/connect.rdns_access.md +1 -1
  32. package/docs/{plugins → deprecated}/mail_from.access.md +1 -1
  33. package/docs/{plugins → deprecated}/rcpt_to.access.md +1 -1
  34. package/docs/plugins/auth/auth_vpopmaild.md +15 -19
  35. package/docs/plugins/auth/flat_file.md +23 -30
  36. package/docs/plugins/queue/rabbitmq_amqplib.md +7 -0
  37. package/docs/plugins/queue/smtp_forward.md +1 -1
  38. package/docs/plugins/queue/smtp_proxy.md +5 -10
  39. package/docs/plugins/relay.md +2 -2
  40. package/docs/plugins/tls.md +29 -9
  41. package/endpoint.js +16 -13
  42. package/haraka.js +10 -14
  43. package/host_pool.js +5 -5
  44. package/line_socket.js +3 -4
  45. package/logger.js +44 -28
  46. package/outbound/client_pool.js +27 -23
  47. package/outbound/config.js +4 -6
  48. package/outbound/fsync_writestream.js +1 -1
  49. package/outbound/hmail.js +180 -220
  50. package/outbound/index.js +86 -99
  51. package/outbound/qfile.js +1 -1
  52. package/outbound/queue.js +55 -43
  53. package/outbound/timer_queue.js +3 -2
  54. package/outbound/tls.js +19 -7
  55. package/package.json +66 -55
  56. package/plugins/.eslintrc.yaml +0 -6
  57. package/plugins/auth/auth_base.js +30 -12
  58. package/plugins/auth/auth_proxy.js +14 -12
  59. package/plugins/auth/auth_vpopmaild.js +30 -20
  60. package/plugins/auth/flat_file.js +17 -12
  61. package/plugins/block_me.js +1 -1
  62. package/plugins/data.signatures.js +2 -4
  63. package/plugins/early_talker.js +2 -1
  64. package/plugins/mail_from.is_resolvable.js +65 -135
  65. package/plugins/queue/deliver.js +4 -5
  66. package/plugins/queue/lmtp.js +11 -14
  67. package/plugins/queue/qmail-queue.js +2 -2
  68. package/plugins/queue/quarantine.js +2 -2
  69. package/plugins/queue/rabbitmq.js +16 -17
  70. package/plugins/queue/rabbitmq_amqplib.js +1 -1
  71. package/plugins/queue/smtp_forward.js +6 -6
  72. package/plugins/queue/smtp_proxy.js +10 -1
  73. package/plugins/queue/test.js +2 -2
  74. package/plugins/rcpt_to.host_list_base.js +5 -5
  75. package/plugins/rcpt_to.in_host_list.js +2 -2
  76. package/plugins/relay.js +6 -7
  77. package/plugins/reseed_rng.js +1 -1
  78. package/plugins/status.js +37 -33
  79. package/plugins/tls.js +2 -2
  80. package/plugins/xclient.js +3 -2
  81. package/plugins.js +51 -54
  82. package/run_tests +3 -30
  83. package/server.js +190 -190
  84. package/smtp_client.js +30 -23
  85. package/{tests → test}/config/plugins +0 -2
  86. package/{tests → test}/config/smtp.ini +1 -1
  87. package/test/config/tls/example.com/_.example.com.key +28 -0
  88. package/test/config/tls/example.com/example.com.crt +25 -0
  89. package/test/connection.js +302 -0
  90. package/test/endpoint.js +94 -0
  91. package/{tests → test}/fixtures/line_socket.js +1 -1
  92. package/{tests → test}/fixtures/util_hmailitem.js +19 -25
  93. package/{tests → test}/host_pool.js +42 -57
  94. package/test/logger.js +258 -0
  95. package/test/outbound/hmail.js +141 -0
  96. package/test/outbound/index.js +220 -0
  97. package/test/outbound/qfile.js +126 -0
  98. package/test/outbound_bounce_net_errors.js +142 -0
  99. package/{tests → test}/outbound_bounce_rfc3464.js +110 -122
  100. package/test/plugins/auth/auth_base.js +484 -0
  101. package/test/plugins/auth/auth_vpopmaild.js +83 -0
  102. package/test/plugins/early_talker.js +104 -0
  103. package/test/plugins/mail_from.is_resolvable.js +35 -0
  104. package/test/plugins/queue/smtp_forward.js +206 -0
  105. package/test/plugins/rcpt_to.host_list_base.js +122 -0
  106. package/test/plugins/rcpt_to.in_host_list.js +193 -0
  107. package/test/plugins/relay.js +303 -0
  108. package/test/plugins/status.js +130 -0
  109. package/test/plugins/tls.js +70 -0
  110. package/test/plugins.js +228 -0
  111. package/{tests → test}/queue/multibyte +0 -0
  112. package/{tests → test}/queue/plain +0 -0
  113. package/test/rfc1869.js +73 -0
  114. package/test/server.js +491 -0
  115. package/test/smtp_client.js +299 -0
  116. package/test/tls_socket.js +273 -0
  117. package/test/transaction.js +270 -0
  118. package/tls_socket.js +202 -252
  119. package/transaction.js +9 -24
  120. package/CONTRIBUTING.md +0 -1
  121. package/bin/dkimverify +0 -40
  122. package/config/access.domains +0 -13
  123. package/config/attachment.ctype.regex +0 -2
  124. package/config/attachment.filename.regex +0 -1
  125. package/config/avg.ini +0 -5
  126. package/config/bounce.ini +0 -15
  127. package/config/data.headers.ini +0 -61
  128. package/config/dkim/dkim_key_gen.sh +0 -78
  129. package/config/dkim_sign.ini +0 -4
  130. package/config/dkim_verify.ini +0 -7
  131. package/config/dnsbl.ini +0 -23
  132. package/config/greylist.ini +0 -43
  133. package/config/helo.checks.ini +0 -52
  134. package/config/lookup_rdns.strict.ini +0 -12
  135. package/config/lookup_rdns.strict.timeout +0 -1
  136. package/config/lookup_rdns.strict.whitelist +0 -1
  137. package/config/lookup_rdns.strict.whitelist_regex +0 -5
  138. package/config/messagesniffer.ini +0 -18
  139. package/config/rcpt_to.blocklist +0 -1
  140. package/config/rdns.allow_regexps +0 -0
  141. package/config/rdns.deny_regexps +0 -0
  142. package/config/spamassassin.ini +0 -56
  143. package/config.js +0 -6
  144. package/dkim.js +0 -614
  145. package/docs/plugins/avg.md +0 -35
  146. package/docs/plugins/bounce.md +0 -69
  147. package/docs/plugins/clamd.md +0 -147
  148. package/docs/plugins/esets.md +0 -8
  149. package/docs/plugins/greylist.md +0 -90
  150. package/docs/plugins/helo.checks.md +0 -135
  151. package/docs/plugins/messagesniffer.md +0 -163
  152. package/docs/plugins/relay_acl.md +0 -29
  153. package/docs/plugins/relay_all.md +0 -15
  154. package/docs/plugins/relay_force_routing.md +0 -33
  155. package/docs/plugins/spamassassin.md +0 -180
  156. package/outbound/mx_lookup.js +0 -70
  157. package/plugins/auth/auth_ldap.js +0 -3
  158. package/plugins/avg.js +0 -162
  159. package/plugins/backscatterer.js +0 -25
  160. package/plugins/bounce.js +0 -381
  161. package/plugins/clamd.js +0 -381
  162. package/plugins/data.headers.js +0 -4
  163. package/plugins/data.uribl.js +0 -4
  164. package/plugins/dkim_sign.js +0 -395
  165. package/plugins/dkim_verify.js +0 -62
  166. package/plugins/dns_list_base.js +0 -221
  167. package/plugins/dnsbl.js +0 -146
  168. package/plugins/dnswl.js +0 -58
  169. package/plugins/esets.js +0 -71
  170. package/plugins/graph.js +0 -5
  171. package/plugins/greylist.js +0 -645
  172. package/plugins/helo.checks.js +0 -533
  173. package/plugins/messagesniffer.js +0 -381
  174. package/plugins/rcpt_to.ldap.js +0 -3
  175. package/plugins/rcpt_to.max_count.js +0 -24
  176. package/plugins/relay_all.js +0 -13
  177. package/plugins/spamassassin.js +0 -384
  178. package/tests/config/dkim/example.com/dns +0 -29
  179. package/tests/config/dkim/example.com/private +0 -6
  180. package/tests/config/dkim/example.com/public +0 -4
  181. package/tests/config/dkim/example.com/selector +0 -1
  182. package/tests/config/dkim.private.key +0 -6
  183. package/tests/config/dkim_sign.ini +0 -4
  184. package/tests/config/helo.checks.ini +0 -52
  185. package/tests/connection.js +0 -327
  186. package/tests/endpoint.js +0 -128
  187. package/tests/fixtures/vm_harness.js +0 -59
  188. package/tests/logger.js +0 -327
  189. package/tests/outbound/hmail.js +0 -112
  190. package/tests/outbound/index.js +0 -324
  191. package/tests/outbound/qfile.js +0 -67
  192. package/tests/outbound_bounce_net_errors.js +0 -173
  193. package/tests/plugins/auth/auth_base.js +0 -463
  194. package/tests/plugins/auth/auth_vpopmaild.js +0 -91
  195. package/tests/plugins/bounce.js +0 -307
  196. package/tests/plugins/clamd.js +0 -224
  197. package/tests/plugins/deprecated/relay_acl.js +0 -140
  198. package/tests/plugins/deprecated/relay_all.js +0 -59
  199. package/tests/plugins/dkim_sign.js +0 -315
  200. package/tests/plugins/dkim_signer.js +0 -108
  201. package/tests/plugins/dns_list_base.js +0 -259
  202. package/tests/plugins/dnsbl.js +0 -101
  203. package/tests/plugins/early_talker.js +0 -115
  204. package/tests/plugins/greylist.js +0 -58
  205. package/tests/plugins/helo.checks.js +0 -525
  206. package/tests/plugins/mail_from.is_resolvable.js +0 -116
  207. package/tests/plugins/queue/smtp_forward.js +0 -221
  208. package/tests/plugins/rcpt_to.host_list_base.js +0 -132
  209. package/tests/plugins/rcpt_to.in_host_list.js +0 -218
  210. package/tests/plugins/relay.js +0 -339
  211. package/tests/plugins/spamassassin.js +0 -171
  212. package/tests/plugins/status.js +0 -138
  213. package/tests/plugins/tls.js +0 -84
  214. package/tests/plugins.js +0 -247
  215. package/tests/rfc1869.js +0 -61
  216. package/tests/server.js +0 -510
  217. package/tests/smtp_client/auth.js +0 -105
  218. package/tests/smtp_client/basic.js +0 -101
  219. package/tests/smtp_client.js +0 -80
  220. package/tests/tls_socket.js +0 -333
  221. package/tests/transaction.js +0 -284
  222. /package/docs/{plugins → deprecated}/dkim_sign.md +0 -0
  223. /package/docs/{plugins → deprecated}/dkim_verify.md +0 -0
  224. /package/docs/{plugins → deprecated}/dnsbl.md +0 -0
  225. /package/docs/{plugins → deprecated}/dnswl.md +0 -0
  226. /package/docs/{plugins → deprecated}/rcpt_to.routes.md +0 -0
  227. /package/{tests → test}/.eslintrc.yaml +0 -0
  228. /package/{tests → test}/config/auth_flat_file.ini +0 -0
  229. /package/{tests → test}/config/dhparams.pem +0 -0
  230. /package/{tests → test}/config/host_list +0 -0
  231. /package/{tests → test}/config/outbound_tls_cert.pem +0 -0
  232. /package/{tests → test}/config/outbound_tls_key.pem +0 -0
  233. /package/{tests → test}/config/smtp_forward.ini +0 -0
  234. /package/{tests → test}/config/tls/ec.pem +0 -0
  235. /package/{tests → test}/config/tls/haraka.local.pem +0 -0
  236. /package/{tests → test}/config/tls/mismatched.pem +0 -0
  237. /package/{tests → test}/config/tls.ini +0 -0
  238. /package/{tests → test}/config/tls_cert.pem +0 -0
  239. /package/{tests → test}/config/tls_key.pem +0 -0
  240. /package/{tests → test}/fixtures/todo_qfile.txt +0 -0
  241. /package/{tests → test}/installation/config/test-plugin-flat +0 -0
  242. /package/{tests → test}/installation/config/test-plugin.ini +0 -0
  243. /package/{tests → test}/installation/config/tls.ini +0 -0
  244. /package/{tests → test}/installation/node_modules/load_first/index.js +0 -0
  245. /package/{tests → test}/installation/node_modules/load_first/package.json +0 -0
  246. /package/{tests → test}/installation/node_modules/test-plugin/config/test-plugin-flat +0 -0
  247. /package/{tests → test}/installation/node_modules/test-plugin/config/test-plugin.ini +0 -0
  248. /package/{tests → test}/installation/node_modules/test-plugin/package.json +0 -0
  249. /package/{tests → test}/installation/node_modules/test-plugin/test-plugin.js +0 -0
  250. /package/{tests → test}/installation/plugins/base_plugin.js +0 -0
  251. /package/{tests → test}/installation/plugins/folder_plugin/index.js +0 -0
  252. /package/{tests → test}/installation/plugins/folder_plugin/package.json +0 -0
  253. /package/{tests → test}/installation/plugins/inherits.js +0 -0
  254. /package/{tests → test}/installation/plugins/load_first.js +0 -0
  255. /package/{tests → test}/installation/plugins/plugin.js +0 -0
  256. /package/{tests → test}/installation/plugins/tls.js +0 -0
  257. /package/{tests → test}/loud/config/dhparams.pem +0 -0
  258. /package/{tests → test}/loud/config/tls/goobered.pem +0 -0
  259. /package/{tests → test}/loud/config/tls.ini +0 -0
  260. /package/{tests → test}/mail_specimen/base64-root-part.txt +0 -0
  261. /package/{tests → test}/mail_specimen/varied-fold-lengths-preserve-data.txt +0 -0
  262. /package/{tests → test}/queue/1507509981169_1507509981169_0_61403_e0Y0Ym_1_fixed +0 -0
  263. /package/{tests → test}/queue/1507509981169_1507509981169_0_61403_e0Y0Ym_1_haraka +0 -0
  264. /package/{tests → test}/queue/1508269674999_1508269674999_0_34002_socVUF_1_haraka +0 -0
  265. /package/{tests → test}/queue/1508455115683_1508455115683_0_90253_9Q4o4V_1_haraka +0 -0
  266. /package/{tests → test}/queue/zero-length +0 -0
  267. /package/{tests → test}/test-queue/delete-me +0 -0
@@ -1,19 +1,16 @@
1
- Transaction Object
2
- ==================
1
+ # Transaction Object
3
2
 
4
3
  An SMTP transaction is valid from MAIL FROM time until RSET or "final-dot".
5
4
 
6
- API
7
- ---
5
+ ## API
8
6
 
9
7
  * transaction.uuid
10
8
 
11
- A unique UUID for this transaction. Is equal to the connection.uuid + '.N'
12
- where N increments for each transaction on this connection.
9
+ A unique UUID for this transaction. Is equal to the connection.uuid + '.N' where N increments for each transaction on this connection.
13
10
 
14
11
  * transaction.mail\_from
15
12
 
16
- The value of the MAIL FROM command as an `Address`[1] object.
13
+ The value of the MAIL FROM command is an `Address`[1] object.
17
14
 
18
15
  * transaction.rcpt\_to
19
16
 
@@ -25,13 +22,13 @@ A node.js Readable Stream object for the message.
25
22
 
26
23
  You use it like this:
27
24
 
28
- transaction.message_stream.pipe(WritableStream, options)
25
+ ```js
26
+ transaction.message_stream.pipe(WritableStream, options)
27
+ ```
29
28
 
30
- Where WritableStream is a node.js Writable Stream object such as a
31
- net.socket, fs.writableStream, process.stdout/stderr or custom stream.
29
+ Where WritableStream is a node.js Writable Stream object such as a net.socket, fs.writableStream, process.stdout/stderr or custom stream.
32
30
 
33
- The options argument should be an object that overrides the following
34
- properties:
31
+ The options argument should be an object that overrides the following properties:
35
32
 
36
33
  * line_endings (default: "\r\n")
37
34
  * dot_stuffing (default: false)
@@ -42,7 +39,9 @@ properties:
42
39
 
43
40
  e.g.
44
41
 
45
- transaction.message_stream.pipe(socket, { dot_stuffing: true, ending_dot: true });
42
+ ```js
43
+ transaction.message_stream.pipe(socket, { dot_stuffing: true, ending_dot: true });
44
+ ```
46
45
 
47
46
  * transaction.data\_bytes
48
47
 
@@ -50,8 +49,7 @@ The number of bytes in the email after DATA.
50
49
 
51
50
  * transaction.add\_data(line)
52
51
 
53
- Adds a line of data to the email. Note this is RAW email - it isn't useful
54
- for adding banners to the email.
52
+ Adds a line of data to the email. Note this is RAW email - it isn't useful for adding banners to the email.
55
53
 
56
54
  * transaction.notes
57
55
 
@@ -59,8 +57,7 @@ A safe place to store transaction specific values. See also [haraka-results](htt
59
57
 
60
58
  * transaction.add\_leading\_header(key, value)
61
59
 
62
- Adds a header to the top of the header list. This should only be used in
63
- very specific cases. Most people will want to use `add_header()` instead.
60
+ Adds a header to the top of the header list. This should only be used in very specific cases. Most cases will use `add_header()` instead.
64
61
 
65
62
  * transaction.add\_header(key, value)
66
63
 
@@ -76,8 +73,7 @@ The header of the email. See `Header Object`.
76
73
 
77
74
  * transaction.parse\_body = true|false [default: false]
78
75
 
79
- Set to `true` to enable parsing of the mail body. Make sure you set this in
80
- hook\_data or before.
76
+ Set to `true` to enable parsing of the mail body. Make sure you set this in hook\_data or before. Storing a transaction hook (with transaction.attachment\_hooks) will set this to true.
81
77
 
82
78
  * transaction.body
83
79
 
@@ -85,81 +81,62 @@ The body of the email if you set `parse_body` above. See `Body Object`.
85
81
 
86
82
  * transaction.attachment\_hooks(start)
87
83
 
88
- Sets a callback for when we see an attachment if `parse_body` has been set.
89
-
90
- The `start` event will receive `(content_type, filename, body, stream)` as
91
- parameters.
92
-
93
- The stream is a `ReadableStream` - see http://nodejs.org/api/stream.html for
94
- details on how this works.
95
-
96
- If you set stream.connection then the stream will apply backpressure to the
97
- connection, allowing you to process attachments before the connection has
98
- ended. Here is an example which stores attachments in temporary files using
99
- the `tmp` library from npm and tells us the size of the file:
100
-
101
- exports.hook_data = function (next, connection) {
102
- // enable mail body parsing
103
- connection.transaction.parse_body = true;
104
- connection.transaction.attachment_hooks(
105
- function (ct, fn, body, stream) {
106
- start_att(connection, ct, fn, body, stream)
107
- }
108
- );
109
- next();
110
- }
111
-
112
- function start_att (connection, ct, fn, body, stream) {
113
- connection.loginfo("Got attachment: " + ct + ", " + fn + " for user id: " + connection.transaction.notes.hubdoc_user.email);
114
- connection.transaction.notes.attachment_count++;
115
-
116
- stream.connection = connection; // Allow backpressure
117
- stream.pause();
118
-
119
- var tmp = require('tmp');
120
-
121
- tmp.file(function (err, path, fd) {
122
- connection.loginfo("Got tempfile: " + path + " (" + fd + ")");
123
- var ws = fs.createWriteStream(path);
124
- stream.pipe(ws);
125
- stream.resume();
126
- ws.on('close', function () {
127
- connection.loginfo("End of stream reached");
128
- fs.fstat(fd, function (err, stats) {
129
- connection.loginfo("Got data of length: " + stats.size);
130
- // Close the tmp file descriptor
131
- fs.close(fd, function(){});
132
- });
84
+ Sets a callback for when we see an attachment.
85
+
86
+ The `start` event will receive `(content_type, filename, body, stream)` as parameters.
87
+
88
+ The stream is a [ReadableStream](http://nodejs.org/api/stream.html)
89
+
90
+ If you set stream.connection then the stream will apply backpressure to the connection, allowing you to process attachments before the connection has ended. Here is an example which stores attachments in temporary files using the `tmp` library from npm and tells us the size of the file:
91
+
92
+ ```js
93
+ exports.hook_data = function (next, connection) {
94
+ // enable mail body parsing
95
+ connection.transaction.attachment_hooks(
96
+ function (ct, fn, body, stream) {
97
+ start_att(connection, ct, fn, body, stream)
98
+ }
99
+ );
100
+ next();
101
+ }
102
+
103
+ function start_att (connection, ct, fn, body, stream) {
104
+ connection.loginfo(`Got attachment: ${ct}, ${fn} for user id: ${connection.transaction.notes.hubdoc_user.email}`)
105
+ connection.transaction.notes.attachment_count++
106
+
107
+ stream.connection = connection; // Allow backpressure
108
+ stream.pause();
109
+
110
+ require('tmp').file((err, path, fd) => {
111
+ connection.loginfo(`Got tempfile: ${path} (${fd})`)
112
+ const ws = fs.createWriteStream(path)
113
+ stream.pipe(ws);
114
+ stream.resume();
115
+ ws.on('close', () => {
116
+ connection.loginfo("End of stream reached");
117
+ fs.fstat(fd, (err, stats) => {
118
+ connection.loginfo(`Got data of length: ${stats.size}`);
119
+ fs.close(fd, () => {}); // Close the tmp file descriptor
133
120
  });
134
121
  });
135
- }
122
+ });
123
+ }
124
+ ```
136
125
 
137
126
  * transaction.discard\_data = true|false [default: false]
138
127
 
139
- Set this flag to true to discard all data as it arrives and not store in
140
- memory or on disk (in the message\_stream property). You can still access
141
- the attachments and body if you set parse\_body to true. This is useful
142
- for systems which do not need the full email, just the attachments or
143
- mail text.
128
+ Set this flag to true to discard all data as it arrives and not store in memory or on disk (in the message\_stream property). You can still access the attachments and body if you set parse\_body to true. This is useful for systems which do not need the full email, just the attachments or mail text.
144
129
 
145
130
  * transaction.set\_banner(text, html)
146
131
 
147
- Sets a banner to be added to the end of the email. If the html part is not
148
- given (optional) then the text part will have each line ending replaced with
149
- `<br/>` when being inserted into HTML parts.
132
+ Sets a banner to be added to the end of the email. If the html part is not given (optional) then the text part will have each line ending replaced with `<br/>` when being inserted into HTML parts.
150
133
 
151
134
  * transaction.add\_body\_filter(ct_match, filter)
152
135
 
153
- Adds a filter to be applied to body parts in the email. ct\_match should be a
154
- regular expression to match against the full content-type line, or a string to
155
- match at the start, e.g. `/^text\/html/` or `'text/plain'`. filter will be
156
- called when each body part matching ct_match is complete. It receives three
157
- parameters, the content-type line, the encoding name, and a buffer with the
158
- full body part. It should return a buffer with the desired contents of the
159
- body in the same encoding.
136
+ Adds a filter to be applied to body parts in the email. ct\_match should be a regular expression to match against the full content-type line, or a string to match at the start, e.g. `/^text\/html/` or `'text/plain'`. filter will be called when each body part matching ct_match is complete. It receives three parameters: the content-type line, the encoding name, and a buffer with the full body part. It should return a buffer with the desired contents of the body in the same encoding.
160
137
 
161
138
  * transaction.results
162
139
 
163
- Store results of processing in a structured format. See [docs/Results](http://haraka.github.io/manual/Results.html)
140
+ Store [results](https://github.com/haraka/haraka-results) of processing in a structured format.
164
141
 
165
- [1]: `Address` objects are address-rfc2821 objects. See https://github.com/haraka/node-address-rfc2821
142
+ [1]: `Address` objects are [address-rfc2821](https://github.com/haraka/node-address-rfc2821) objects.
@@ -1,6 +1,6 @@
1
1
  ## DEPRECATION NOTICE
2
2
 
3
- See the [access](http://haraka.github.io/manual/plugins/access.html) plugin
3
+ See [haraka-plugin-access](https://github.com/haraka/haraka-plugin-access)
4
4
  for upgrade instructions.
5
5
 
6
6
 
@@ -1,6 +1,6 @@
1
1
  ## DEPRECATION NOTICE
2
2
 
3
- See the [access](http://haraka.github.io/manual/plugins/access.html) plugin
3
+ See [haraka-plugin-access](https://github.com/haraka/haraka-plugin-access)
4
4
  for upgrade instructions.
5
5
 
6
6
 
@@ -1,6 +1,6 @@
1
1
  ## DEPRECATION NOTICE
2
2
 
3
- See the [access](http://haraka.github.io/manual/plugins/access.html) plugin
3
+ See [haraka-plugin-access](https://github.com/haraka/haraka-plugin-access)
4
4
  for upgrade instructions.
5
5
 
6
6
 
@@ -1,26 +1,20 @@
1
- auth/auth\_vpopmaild
2
- ===============
1
+ # auth/auth\_vpopmaild
3
2
 
4
- The `auth/vpopmaild` plugin allows you to authenticate against a vpopmaild
5
- daemon.
3
+ The `auth/vpopmaild` plugin allows SMTP users to authenticate against a vpopmaild daemon.
6
4
 
7
5
  ## Configuration
8
6
 
9
- Configuration is stored in `config/auth_vpopmaild.ini` and uses INI
10
- style formatting.
7
+ The configuration file is stored in `config/auth_vpopmaild.ini`.
11
8
 
12
- There are three configuration settings:
9
+ ### settings
13
10
 
14
11
  * host: The host/IP that vpopmaild is listening on (default: localhost).
15
12
 
16
13
  * port: The TCP port that vpopmaild is listening on (default: 89).
17
14
 
18
- * sysadmin: A colon separated username:password of a vpopmail user with
19
- SYSADMIN privileges (see vpopmail/bin/vmoduser -S). This is **only**
20
- necessary to support CRAM-MD5 which requires access to the clear text
21
- password. On new installs, it's best not to use CRAM-MD5, as it requires
22
- storing clear text passwords. Legacy clients with MUAs configured
23
- to authenticate with CRAM-MD5 will need this enabled.
15
+ * sysadmin: A colon separated username:password of a vpopmail user with SYSADMIN privileges (see vpopmail/bin/vmoduser -S). This is **only** necessary to support CRAM-MD5 which requires access to the clear text password. On new installs, it's best not to use CRAM-MD5, as it requires storing clear text passwords. Legacy clients with MUAs configured to authenticate with CRAM-MD5 will need this enabled.
16
+
17
+ * constrain_sender: (default: true). For outbound messages (due to successful AUTH), constrain the envelope sender (MAIL FROM) to the same domain as the authenticated user. This setting, combined with `rate_rcpt_sender` in the [limit](https://github.com/haraka/haraka-plugin-limit) plugin can dramatically reduce the amount of backscatter and spam sent when an email account is compromised.
24
18
 
25
19
 
26
20
  ### Per-domain Configuration
@@ -29,10 +23,12 @@ Additionally, domains can each have their own configuration for connecting
29
23
  to vpopmaild. The defaults are the same, so only the differences needs to
30
24
  be declared. Example:
31
25
 
32
- [example.com]
33
- host=192.168.0.1
34
- port=999
26
+ ```ini
27
+ [example.com]
28
+ host=192.168.0.1
29
+ port=999
35
30
 
36
- [example2.com]
37
- host=192.168.0.2
38
- sysadmin=postmaster@example2.com:sekret
31
+ [example2.com]
32
+ host=192.168.0.2
33
+ sysadmin=postmaster@example2.com:sekret
34
+ ```
@@ -1,47 +1,40 @@
1
- auth/flat\_file
2
- ==============
1
+ # auth/flat\_file
3
2
 
4
- The `auth/flat_file` plugin allows you to create a file containing username
5
- and password combinations, and have relaying users authenticate from that
6
- file.
3
+ The `auth/flat_file` plugin allows you to create a file containing username and password combinations, and have relaying users authenticate from that file.
7
4
 
8
- Note that passwords are stored in clear-text, so this may not be a great idea
9
- for large scale systems. However the plugin would be a good start for someone
10
- looking to implement authentication using some other form of auth.
5
+ Note that passwords are stored in clear-text, so this may not be a great idea for large scale systems. However the plugin would be a good start for someone looking to implement authentication using some other form of auth.
11
6
 
12
- **Security** - it is recommended to switch to [auth-encfile][url-authencflat]
13
- to protect your user credentials.
7
+ **Security** - it is recommended to switch to [auth-encfile][url-authencflat] to protect your user credentials.
14
8
 
15
- **IMPORANT NOTE** - this plugin requires that STARTTLS be used via the tls plugin
16
- before it will advertise AUTH capabilities by the EHLO command. This is to
17
- improve security out-of-the-box. Localhost and any IP in RFC1918 ranges
18
- are automatically exempt from this rule.
9
+ **IMPORANT NOTE** - this plugin requires that STARTTLS be used via the tls plugin before it will advertise AUTH capabilities by the EHLO command. Localhost and IPs in RFC1918 ranges
10
+ are exempt from this rule.
19
11
 
20
- Configuration
21
- -------------
12
+ ## Configuration
22
13
 
23
- Configuration is stored in `config/auth_flat_file.ini` and uses the INI
24
- style formatting.
14
+ Configuration is stored in `config/auth_flat_file.ini`.
25
15
 
26
- Authentication methods are listed in the `[core]` section under `methods`
27
- parameter. Lists of authentification methods are comma separated. Currently
28
- supported methods are: `CRAM-MD5`, `PLAIN` and `LOGIN`. The `PLAIN`
29
- and `LOGIN` methods are not secure. That is why TLS is required before AUTH is
30
- offered.
16
+ * [core]methods
31
17
 
32
- Example:
18
+ Authentication methods are listed in the `[core]methods` parameter. Authentification methods are comma separated. Currently supported methods are: `CRAM-MD5`, `PLAIN` and `LOGIN`. The `PLAIN` and `LOGIN` methods are insecure and require TLS to be enabled.
19
+
20
+ * [core]constrain_sender: (default: true). For outbound messages (due to successful AUTH), constrain the envelope sender (MAIL FROM) to the same domain as the authenticated user. This setting, combined with `rate_rcpt_sender` in the [limit](https://github.com/haraka/haraka-plugin-limit) plugin can dramatically reduce the amount of backscatter and spam sent when an email account is compromised.
33
21
 
34
- [core]
35
- methods=PLAIN,LOGIN,CRAM-MD5
22
+ Example:
36
23
 
24
+ ```ini
25
+ [core]
26
+ methods=PLAIN,LOGIN,CRAM-MD5
27
+ constrain_sender=true
28
+ ```
37
29
 
38
30
  Users are stored in the `[users]` section.
39
31
 
40
32
  Example:
41
33
 
42
- [users]
43
- user1=password1
44
- user@domain.com=password2
45
-
34
+ ```ini
35
+ [users]
36
+ user1=password1
37
+ user@domain.com=password2
38
+ ```
46
39
 
47
40
  [url-authencflat]: https://github.com/AuspeXeu/haraka-plugin-auth-enc-file
@@ -36,5 +36,12 @@ Configuration
36
36
  durable = true
37
37
  autoDelete = false
38
38
 
39
+ ; Optional queue arguments
40
+ ; More information about x-arguments can be found at https://www.rabbitmq.com/queues.html#optional-arguments
41
+ [queue_args]
42
+ x-dead-letter-exchange =
43
+ x-dead-letter-routing-key = emails_dlq
44
+ x-overflow = reject-publish
45
+ x-queue-type = quorum
39
46
 
40
47
  More information about RabbitMQ can be found at https://www.rabbitmq.com/
@@ -100,4 +100,4 @@ enable\_outbound can be set or unset on a per-domain level to enable or disable
100
100
 
101
101
  # Split host forward routing
102
102
 
103
- When an incoming email transaction has multiple recipients with different forward routes, recipients to subsequent forward routes are deferred. Example: an incoming email transaction has recipients user@example1.com, user@example2.com, and user@example3.com. The first two recipients will be accepted (they share the same forward destination) and the latter will be deferred. It will arrive in a future delivery attempt by the remote.
103
+ When an incoming email transaction has multiple recipients with different forward routes, recipients to subsequent forward routes are deferred. Example: an incoming email transaction has recipients user@example1.com, user@example2.com, and user@example3.com. The first two recipients will be accepted (they share the same forward destination) and the latter will be deferred. It will arrive in a future delivery attempt by the remote.
@@ -1,16 +1,11 @@
1
1
  # queue/smtp\_proxy
2
2
  ================
3
3
 
4
- This plugin delivers to another mail server. This is a common setup when you
5
- want to have a mail server with a solid pedigree of outbound delivery to
6
- other hosts, and inbound delivery to users.
7
-
8
- In comparison to `queue/smtp_forward`, this plugin makes a connection at
9
- MAIL FROM time to the ongoing SMTP server. This can be a benefit in that
10
- you get any SMTP-time filtering that the ongoing server provides, in
11
- particular one important facility to some setups is recipient filtering.
12
- However be aware that other than connect and HELO-time filtering, you will
13
- have as many connections to your ongoing SMTP server as you have to Haraka.
4
+ This plugin delivers to another mail server. This is a common setup when you want to have a mail server with a solid pedigree of outbound delivery to other hosts, and inbound delivery to users.
5
+
6
+ In comparison to `queue/smtp_forward`, this plugin makes a connection at MAIL FROM time to the ongoing SMTP server. This can be a benefit in that you get any SMTP-time filtering that the ongoing server provides, in particular one important facility to some setups is recipient filtering.
7
+
8
+ Be aware that other than connect and HELO-time filtering, you will have as many connections to your ongoing SMTP server as you have to Haraka.
14
9
 
15
10
  ## Configuration
16
11
  -------------
@@ -8,7 +8,7 @@ This **relay** plugin provides Haraka with options for managing relay permission
8
8
 
9
9
  ## Authentication
10
10
 
11
- One way to enable relaying is [authentication](http://haraka.github.io/manual.html) via the auth plugins. Successful authentication enables relaying during _that_ SMTP connection. To securely offer SMTP AUTH, the [tls](http://haraka.github.io/manual/plugins/tls.html) plugin and at least one auth plugin must be enabled and properly configured. When that requirement is met, the AUTH SMTP extension will be advertised to SMTP clients.
11
+ One way to enable relaying is authentication via the [auth plugins](http://haraka.github.io/plugins). Successful authentication enables relaying during _that_ SMTP connection. To securely offer SMTP AUTH, the [tls](http://haraka.github.io/plugins/tls) plugin and at least one auth plugin must be enabled and properly configured. When that requirement is met, the AUTH SMTP extension will be advertised to SMTP clients.
12
12
 
13
13
  % nc mail.example.com 587
14
14
  220 mail.example.com ESMTP Haraka 2.4.0 ready
@@ -118,7 +118,7 @@ Example:
118
118
  [domains]
119
119
  test.com = { "action": "accept" }
120
120
 
121
- I think of *accept* as the equivalent of qmail's *rcpthosts*, or a misplaced Haraka `rcpt_to.*` plugin. The *accept* mechanism is another way to tell Haraka that a particular domain is one we accept mail for. The difference between this and the [rcpt_to.in_host_list](http://haraka.github.io/manual/plugins/rcpt_to.in_host_list.html) plugin is that this one also enables relaying.
121
+ Think of *accept* as the equivalent of qmail's *rcpthosts*, or a misplaced Haraka `rcpt_to.*` plugin. The *accept* mechanism is another way to tell Haraka that a particular domain is one we accept mail for. The difference between this and the [rcpt_to.in_host_list](http://haraka.github.io/plugins/rcpt_to.in_host_list) plugin is that this one also enables relaying.
122
122
 
123
123
  * continue (mails are subject to further checks)
124
124
 
@@ -4,9 +4,11 @@ This plugin enables the use of TLS (via `STARTTLS`) in Haraka.
4
4
 
5
5
  For this plugin to work you must have SSL certificates installed correctly.
6
6
 
7
+ Haraka has [SNI](https://en.wikipedia.org/wiki/Server_Name_Indication) support. When the remote MUA/MTA presents a servername during the TLS handshake and a TLS certificate with that Common Name matches, that certificate will be presented. If no match is found, the default certificate (see Certificate Files) is presented.
8
+
7
9
  ## Certificate Files
8
10
 
9
- Defaults are shown and can be overridden in `config/tls.ini`.
11
+ Defaults settings are shown and can be overridden in `config/tls.ini`.
10
12
 
11
13
  ```ini
12
14
  key=tls_key.pem
@@ -16,20 +18,39 @@ dhparam=dhparams.pem
16
18
 
17
19
  ## Certificate Directory
18
20
 
19
- If the directory `config/tls` exists, each file within the directory is expected to be a PEM encoded TLS bundle. Generate the PEM bundles in The Usual Way[TM] by concatenating the key, certificate, and CA/chain certs in that order. Example:
21
+ If the directory `config/tls` exists, files within the directory are PEM encoded TLS files in one of two formats: bundles or Wild Wild West.
22
+
23
+ ### Certificate bundles
24
+
25
+ Generate PEM bundles in The Usual Way[TM] by concatenating the key, certificate, and CA/chain certs in that order. Example:
20
26
 
21
27
  ```sh
22
- cat example.com.key example.com.crt ca.crt > config/tls/example.com.pem
28
+ cat example.com.key example.com.crt ca-int.crt > haraka/config/tls/example.com.pem
23
29
  ```
24
30
 
25
- An example [acme.sh](https://acme.sh) deployment [script](https://github.com/msimerson/Mail-Toaster-6/blob/master/provision/letsencrypt.sh) demonstrates how to install [Let's Encrypt](https://letsencrypt.org) certificates to the Haraka `config/tls`directory.
31
+ An example [acme.sh](https://acme.sh) deployment [script](https://github.com/msimerson/Mail-Toaster-6/blob/master/provision/letsencrypt.sh) installs [Let's Encrypt](https://letsencrypt.org) certificate bundles to the Haraka `config/tls`directory.
32
+
33
+ ### Wild Wild West
34
+
35
+ PEM encoded TLS certificates and keys can be stored in files in `config/tls`. The certificate loader is recursive, so TLS files can be in subdirs like `config/tls/mx1.example.com`. The certificate names are parsed from the 1st cert in each file and indexed by the certs Common Name(s). Subject Alternate Names are supported. The file name containing the certificates does *not* matter. Additional certificates within each file are presumed to be CA chain (intermediate) certificates.
36
+
37
+ If the TLS key is stored in the same file as the matching certificate, then the name of the file does not matter. If the TLS key is alone in a file, the file MUST be named with the keys Common Name. The file extension does not matter, `.pem` and `.key` are common. If the key is used for multiple CNs, the key must be stored in a file name matching each CN. Examples of working TLS key/cert file pairs for the Common Name mx1.example.com:
26
38
 
27
- Haraka has [SNI](https://en.wikipedia.org/wiki/Server_Name_Indication) support. When the remote MUA/MTA presents a servername during the TLS handshake and a TLS certificate with that Common Name matches, that certificate will be presented. If no match is found, the default certificate (see Certificate Files above) is presented.
39
+ 1. certificate bundle (see above), key & cert in same file
40
+ - config/tls/mx1.example.com.pem (recommended)
41
+ - config/tls/any-unique-name.pem (CN is extracted from 1st cert)
42
+ 2. files in TLS dir
43
+ - config/tls/mx1.example.com.crt
44
+ - config/tls/mx1.example.com.key
45
+ 3. files in subdir
46
+ - config/tls/example.com/mx1.cert
47
+ - config/tls/example.com/mx1.example.com.key
48
+ 4. wildcard bundle on Windows platform (* is not allowed in file names)
49
+ - config/tls/_.example.com.pem
28
50
 
29
51
  ## Purchased Certificate
30
52
 
31
- If you have a purchased certificate, append any intermediate/chained/ca-cert
32
- files to the certificate in this order:
53
+ For purchased certificate, append any intermediate/chained/ca-cert files to the certificate in this order:
33
54
 
34
55
  1. The CA signed SSL cert
35
56
  2. Any intermediate certificates
@@ -39,8 +60,7 @@ See also [Setting Up TLS](https://github.com/haraka/Haraka/wiki/Setting-up-TLS-w
39
60
 
40
61
  ## Self Issued (unsigned) Certificate
41
62
 
42
- Create a certificate and key file in the config directory with the following
43
- command:
63
+ Create a certificate and key file in the config directory with the following command:
44
64
 
45
65
  openssl req -x509 -nodes -days 2190 -newkey rsa:2048 \
46
66
  -keyout config/tls_key.pem -out config/tls_cert.pem
package/endpoint.js CHANGED
@@ -1,7 +1,7 @@
1
1
  'use strict';
2
2
  // Socket address parser/formatter and server binding helper
3
3
 
4
- const fs = require('fs');
4
+ const fs = require('node:fs/promises');
5
5
  const sockaddr = require('sockaddr');
6
6
 
7
7
  module.exports = function endpoint (addr, defaultPort) {
@@ -46,21 +46,24 @@ class Endpoint {
46
46
  }
47
47
 
48
48
  // Make server listen on this endpoint, w/optional options
49
- bind (server, opts) {
50
- let done;
51
- opts = Object.assign({}, opts || {});
49
+ async bind (server, opts) {
50
+ opts = {...opts};
51
+
52
+ const mode = this.mode ? parseInt(this.mode, 8) : false;
52
53
  if (this.path) {
53
- const path = opts.path = this.path;
54
- const mode = this.mode ? parseInt(this.mode, 8) : false;
55
- if (mode) {
56
- done = () => fs.chmodSync(path, mode);
57
- }
58
- if (fs.existsSync(path)) fs.unlinkSync(path);
59
- }
60
- else {
54
+ opts.path = this.path;
55
+ await fs.rm(this.path, { force: true }); // errors are ignored when force is true
56
+ } else {
61
57
  opts.host = this.host;
62
58
  opts.port = this.port;
63
59
  }
64
- server.listen(opts, done);
60
+
61
+ return new Promise((resolve, reject) => {
62
+ server.listen(opts, async (err) => {
63
+ if(err) return reject(err);
64
+ if (mode) await fs.chmod(opts.path, mode);
65
+ resolve()
66
+ });
67
+ });
65
68
  }
66
69
  }
package/haraka.js CHANGED
@@ -20,20 +20,18 @@ catch (e) {
20
20
  require('module')._initPaths(); // Horrible hack
21
21
  }
22
22
 
23
- const fs = require('fs');
23
+ const utils = require('haraka-utils');
24
24
  const logger = require('./logger');
25
25
  const server = require('./server');
26
26
 
27
- exports.version = JSON.parse(
28
- fs.readFileSync(path.join(__dirname, './package.json'), 'utf8')
29
- ).version;
27
+ exports.version = utils.getVersion(__dirname)
30
28
 
31
29
  process.on('uncaughtException', err => {
32
30
  if (err.stack) {
33
- err.stack.split("\n").forEach(line => logger.logcrit(line));
31
+ err.stack.split("\n").forEach(line => logger.crit(line));
34
32
  }
35
33
  else {
36
- logger.logcrit(`Caught exception: ${JSON.stringify(err)}`);
34
+ logger.crit(`Caught exception: ${JSON.stringify(err)}`);
37
35
  }
38
36
  logger.dump_and_exit(1);
39
37
  });
@@ -41,18 +39,16 @@ process.on('uncaughtException', err => {
41
39
  let shutting_down = false;
42
40
  const signals = ['SIGINT'];
43
41
 
44
- if (process.pid === 1) {
45
- signals.push('SIGTERM')
46
- }
42
+ if (process.pid === 1) signals.push('SIGTERM')
47
43
 
48
- signals.forEach((sig) => {
44
+ for (const sig of signals) {
49
45
  process.on(sig, () => {
50
46
  if (shutting_down) return process.exit(1);
51
47
  shutting_down = true;
52
48
  const [, filename] = process.argv;
53
49
  process.title = path.basename(filename, '.js');
54
50
 
55
- logger.lognotice(`${sig} received`);
51
+ logger.notice(`${sig} received`);
56
52
  logger.dump_and_exit(() => {
57
53
  if (server.cluster?.isMaster) {
58
54
  server.performShutdown();
@@ -62,10 +58,10 @@ signals.forEach((sig) => {
62
58
  }
63
59
  });
64
60
  });
65
- });
61
+ }
66
62
 
67
63
  process.on('SIGHUP', () => {
68
- logger.lognotice('Flushing the temp fail queue');
64
+ logger.notice('Flushing the temp fail queue');
69
65
  server.flushQueue();
70
66
  });
71
67
 
@@ -74,7 +70,7 @@ process.on('exit', code => {
74
70
  const [, filename] = process.argv;
75
71
  process.title = path.basename(filename, '.js');
76
72
 
77
- logger.lognotice('Shutting down');
73
+ logger.notice('Shutting down');
78
74
  logger.dump_logs();
79
75
  });
80
76