haraka 0.0.33 → 3.3.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 (254) hide show
  1. package/.githooks/pre-commit +41 -0
  2. package/.prettierignore +7 -0
  3. package/.qlty/.gitignore +7 -0
  4. package/.qlty/configs/.shellcheckrc +1 -0
  5. package/.qlty/qlty.toml +15 -0
  6. package/CHANGELOG.md +1898 -0
  7. package/CONTRIBUTORS.md +34 -0
  8. package/Dockerfile +50 -0
  9. package/LICENSE +22 -0
  10. package/Plugins.md +227 -0
  11. package/README.md +119 -4
  12. package/SECURITY.md +178 -0
  13. package/TODO +22 -0
  14. package/bin/haraka +593 -0
  15. package/bin/haraka_grep +32 -0
  16. package/config/aliases +2 -0
  17. package/config/auth_flat_file.ini +7 -0
  18. package/config/auth_vpopmaild.ini +9 -0
  19. package/config/connection.ini +79 -0
  20. package/config/delay_deny.ini +7 -0
  21. package/config/host_list +3 -0
  22. package/config/host_list_regex +6 -0
  23. package/config/http.ini +11 -0
  24. package/config/lmtp.ini +7 -0
  25. package/config/log.ini +11 -0
  26. package/config/outbound.bounce_message +18 -0
  27. package/config/outbound.bounce_message_html +36 -0
  28. package/config/outbound.bounce_message_image +106 -0
  29. package/config/outbound.ini +24 -0
  30. package/config/plugins +67 -0
  31. package/config/smtp.ini +37 -0
  32. package/config/smtp_bridge.ini +4 -0
  33. package/config/smtp_forward.ini +31 -0
  34. package/config/smtp_proxy.ini +27 -0
  35. package/config/tarpit.timeout +1 -0
  36. package/config/tls.ini +83 -0
  37. package/config/watch.ini +12 -0
  38. package/config/xclient.hosts +2 -0
  39. package/connection.js +1865 -0
  40. package/contrib/Haraka.cf +6 -0
  41. package/contrib/Haraka.pm +35 -0
  42. package/contrib/bad_smtp_server.pl +25 -0
  43. package/contrib/bsd-rc.d/haraka +63 -0
  44. package/contrib/debian-init.d/haraka +87 -0
  45. package/contrib/haraka.init +96 -0
  46. package/contrib/haraka.service +23 -0
  47. package/contrib/plugin2npm.sh +81 -0
  48. package/contrib/ubuntu-upstart/haraka.conf +27 -0
  49. package/docs/Body.md +1 -0
  50. package/docs/Config.md +1 -0
  51. package/docs/Connection.md +153 -0
  52. package/docs/CoreConfig.md +96 -0
  53. package/docs/CustomReturnCodes.md +3 -0
  54. package/docs/HAProxy.md +62 -0
  55. package/docs/Header.md +1 -0
  56. package/docs/Logging.md +129 -0
  57. package/docs/Outbound.md +210 -0
  58. package/docs/Plugins.md +372 -0
  59. package/docs/Results.md +7 -0
  60. package/docs/Transaction.md +135 -0
  61. package/docs/Tutorial.md +183 -0
  62. package/docs/deprecated/access.md +3 -0
  63. package/docs/deprecated/backscatterer.md +9 -0
  64. package/docs/deprecated/connect.rdns_access.md +53 -0
  65. package/docs/deprecated/data.headers.md +3 -0
  66. package/docs/deprecated/data.nomsgid.md +7 -0
  67. package/docs/deprecated/data.noreceived.md +11 -0
  68. package/docs/deprecated/data.rfc5322_header_checks.md +11 -0
  69. package/docs/deprecated/dkim_sign.md +97 -0
  70. package/docs/deprecated/dkim_verify.md +28 -0
  71. package/docs/deprecated/dnsbl.md +80 -0
  72. package/docs/deprecated/dnswl.md +73 -0
  73. package/docs/deprecated/lookup_rdns.strict.md +67 -0
  74. package/docs/deprecated/mail_from.access.md +52 -0
  75. package/docs/deprecated/mail_from.blocklist.md +18 -0
  76. package/docs/deprecated/mail_from.nobounces.md +8 -0
  77. package/docs/deprecated/rcpt_to.access.md +53 -0
  78. package/docs/deprecated/rcpt_to.blocklist.md +18 -0
  79. package/docs/deprecated/rcpt_to.routes.md +3 -0
  80. package/docs/deprecated/rdns.regexp.md +30 -0
  81. package/docs/plugins/aliases.md +3 -0
  82. package/docs/plugins/auth/auth_bridge.md +34 -0
  83. package/docs/plugins/auth/auth_ldap.md +4 -0
  84. package/docs/plugins/auth/auth_proxy.md +36 -0
  85. package/docs/plugins/auth/auth_vpopmaild.md +33 -0
  86. package/docs/plugins/auth/flat_file.md +40 -0
  87. package/docs/plugins/block_me.md +18 -0
  88. package/docs/plugins/data.signatures.md +11 -0
  89. package/docs/plugins/delay_deny.md +23 -0
  90. package/docs/plugins/max_unrecognized_commands.md +6 -0
  91. package/docs/plugins/prevent_credential_leaks.md +22 -0
  92. package/docs/plugins/process_title.md +42 -0
  93. package/docs/plugins/queue/deliver.md +3 -0
  94. package/docs/plugins/queue/discard.md +32 -0
  95. package/docs/plugins/queue/lmtp.md +24 -0
  96. package/docs/plugins/queue/qmail-queue.md +16 -0
  97. package/docs/plugins/queue/quarantine.md +87 -0
  98. package/docs/plugins/queue/smtp_bridge.md +32 -0
  99. package/docs/plugins/queue/smtp_forward.md +127 -0
  100. package/docs/plugins/queue/smtp_proxy.md +68 -0
  101. package/docs/plugins/queue/test.md +7 -0
  102. package/docs/plugins/rcpt_to.in_host_list.md +34 -0
  103. package/docs/plugins/rcpt_to.max_count.md +3 -0
  104. package/docs/plugins/record_envelope_addresses.md +20 -0
  105. package/docs/plugins/relay.md +3 -0
  106. package/docs/plugins/reseed_rng.md +16 -0
  107. package/docs/plugins/status.md +41 -0
  108. package/docs/plugins/tarpit.md +50 -0
  109. package/docs/plugins/tls.md +235 -0
  110. package/docs/plugins/toobusy.md +27 -0
  111. package/docs/plugins/xclient.md +10 -0
  112. package/docs/tutorials/Migrating_from_v1_to_v2.md +96 -0
  113. package/docs/tutorials/SettingUpOutbound.md +62 -0
  114. package/eslint.config.mjs +2 -0
  115. package/haraka.js +74 -0
  116. package/haraka.sh +2 -0
  117. package/http/html/404.html +58 -0
  118. package/http/html/index.html +47 -0
  119. package/http/package.json +21 -0
  120. package/line_socket.js +24 -0
  121. package/logger.js +322 -0
  122. package/outbound/client_pool.js +59 -0
  123. package/outbound/config.js +134 -0
  124. package/outbound/hmail.js +1504 -0
  125. package/outbound/index.js +349 -0
  126. package/outbound/qfile.js +93 -0
  127. package/outbound/queue.js +399 -0
  128. package/outbound/tls.js +85 -0
  129. package/outbound/todo.js +17 -0
  130. package/package.json +100 -4
  131. package/plugins/.eslintrc.yaml +3 -0
  132. package/plugins/auth/auth_base.js +261 -0
  133. package/plugins/auth/auth_bridge.js +20 -0
  134. package/plugins/auth/auth_proxy.js +227 -0
  135. package/plugins/auth/auth_vpopmaild.js +162 -0
  136. package/plugins/auth/flat_file.js +44 -0
  137. package/plugins/block_me.js +88 -0
  138. package/plugins/data.signatures.js +30 -0
  139. package/plugins/delay_deny.js +153 -0
  140. package/plugins/prevent_credential_leaks.js +61 -0
  141. package/plugins/process_title.js +197 -0
  142. package/plugins/profile.js +11 -0
  143. package/plugins/queue/deliver.js +12 -0
  144. package/plugins/queue/discard.js +27 -0
  145. package/plugins/queue/lmtp.js +45 -0
  146. package/plugins/queue/qmail-queue.js +93 -0
  147. package/plugins/queue/quarantine.js +133 -0
  148. package/plugins/queue/smtp_bridge.js +45 -0
  149. package/plugins/queue/smtp_forward.js +371 -0
  150. package/plugins/queue/smtp_proxy.js +142 -0
  151. package/plugins/queue/test.js +15 -0
  152. package/plugins/rcpt_to.host_list_base.js +65 -0
  153. package/plugins/rcpt_to.in_host_list.js +56 -0
  154. package/plugins/record_envelope_addresses.js +17 -0
  155. package/plugins/reseed_rng.js +7 -0
  156. package/plugins/status.js +274 -0
  157. package/plugins/tarpit.js +45 -0
  158. package/plugins/tls.js +164 -0
  159. package/plugins/toobusy.js +47 -0
  160. package/plugins/xclient.js +124 -0
  161. package/plugins.js +605 -0
  162. package/run_tests +11 -0
  163. package/server.js +827 -0
  164. package/smtp_client.js +504 -0
  165. package/test/.eslintrc.yaml +11 -0
  166. package/test/config/auth_flat_file.ini +5 -0
  167. package/test/config/block_me.recipient +1 -0
  168. package/test/config/block_me.senders +1 -0
  169. package/test/config/dhparams.pem +8 -0
  170. package/test/config/host_list +2 -0
  171. package/test/config/outbound_tls_cert.pem +1 -0
  172. package/test/config/outbound_tls_key.pem +1 -0
  173. package/test/config/plugins +7 -0
  174. package/test/config/smtp.ini +11 -0
  175. package/test/config/smtp_forward.ini +30 -0
  176. package/test/config/tls/example.com/_.example.com.key +28 -0
  177. package/test/config/tls/example.com/example.com.crt +25 -0
  178. package/test/config/tls/haraka.local.pem +51 -0
  179. package/test/config/tls.ini +45 -0
  180. package/test/config/tls_cert.pem +21 -0
  181. package/test/config/tls_key.pem +28 -0
  182. package/test/connection.js +820 -0
  183. package/test/fixtures/haproxy_allowed/config/connection.ini +3 -0
  184. package/test/fixtures/haproxy_disabled/config/connection.ini +3 -0
  185. package/test/fixtures/haproxy_untrusted/config/connection.ini +3 -0
  186. package/test/fixtures/line_socket.js +21 -0
  187. package/test/fixtures/todo_qfile.txt +0 -0
  188. package/test/fixtures/util_hmailitem.js +156 -0
  189. package/test/installation/config/test-plugin-flat +1 -0
  190. package/test/installation/config/test-plugin.ini +10 -0
  191. package/test/installation/config/tls.ini +1 -0
  192. package/test/installation/node_modules/load_first/index.js +5 -0
  193. package/test/installation/node_modules/load_first/package.json +11 -0
  194. package/test/installation/node_modules/test-plugin/config/test-plugin-flat +1 -0
  195. package/test/installation/node_modules/test-plugin/config/test-plugin.ini +9 -0
  196. package/test/installation/node_modules/test-plugin/package.json +5 -0
  197. package/test/installation/node_modules/test-plugin/test-plugin.js +5 -0
  198. package/test/installation/plugins/base_plugin.js +3 -0
  199. package/test/installation/plugins/folder_plugin/index.js +3 -0
  200. package/test/installation/plugins/folder_plugin/package.json +11 -0
  201. package/test/installation/plugins/inherits.js +7 -0
  202. package/test/installation/plugins/load_first.js +3 -0
  203. package/test/installation/plugins/plugin.js +1 -0
  204. package/test/installation/plugins/tls.js +3 -0
  205. package/test/logger.js +217 -0
  206. package/test/loud/config/dhparams.pem +0 -0
  207. package/test/loud/config/tls/goobered.pem +45 -0
  208. package/test/loud/config/tls.ini +43 -0
  209. package/test/mail_specimen/base64-root-part.txt +23 -0
  210. package/test/mail_specimen/varied-fold-lengths-preserve-data.txt +283 -0
  211. package/test/outbound/bounce_net_errors.js +133 -0
  212. package/test/outbound/bounce_rfc3464.js +226 -0
  213. package/test/outbound/hmail.js +210 -0
  214. package/test/outbound/index.js +385 -0
  215. package/test/outbound/qfile.js +124 -0
  216. package/test/outbound/queue.js +325 -0
  217. package/test/plugins/auth/auth_base.js +620 -0
  218. package/test/plugins/auth/auth_bridge.js +80 -0
  219. package/test/plugins/auth/auth_vpopmaild.js +81 -0
  220. package/test/plugins/auth/flat_file.js +123 -0
  221. package/test/plugins/block_me.js +141 -0
  222. package/test/plugins/data.signatures.js +111 -0
  223. package/test/plugins/delay_deny.js +262 -0
  224. package/test/plugins/prevent_credential_leaks.js +174 -0
  225. package/test/plugins/process_title.js +141 -0
  226. package/test/plugins/queue/deliver.js +98 -0
  227. package/test/plugins/queue/discard.js +78 -0
  228. package/test/plugins/queue/lmtp.js +137 -0
  229. package/test/plugins/queue/qmail-queue.js +98 -0
  230. package/test/plugins/queue/quarantine.js +80 -0
  231. package/test/plugins/queue/smtp_bridge.js +152 -0
  232. package/test/plugins/queue/smtp_forward.js +1023 -0
  233. package/test/plugins/queue/smtp_proxy.js +138 -0
  234. package/test/plugins/rcpt_to.host_list_base.js +102 -0
  235. package/test/plugins/rcpt_to.in_host_list.js +186 -0
  236. package/test/plugins/record_envelope_addresses.js +66 -0
  237. package/test/plugins/reseed_rng.js +34 -0
  238. package/test/plugins/status.js +207 -0
  239. package/test/plugins/tarpit.js +90 -0
  240. package/test/plugins/tls.js +86 -0
  241. package/test/plugins/toobusy.js +198 -0
  242. package/test/plugins/xclient.js +119 -0
  243. package/test/plugins.js +230 -0
  244. package/test/queue/1507509981169_1507509981169_0_61403_e0Y0Ym_1_fixed +0 -0
  245. package/test/queue/1507509981169_1507509981169_0_61403_e0Y0Ym_1_haraka +0 -0
  246. package/test/queue/1508269674999_1508269674999_0_34002_socVUF_1_haraka +0 -0
  247. package/test/queue/1508455115683_1508455115683_0_90253_9Q4o4V_1_haraka +0 -0
  248. package/test/queue/zero-length +0 -0
  249. package/test/server.js +1012 -0
  250. package/test/smtp_client.js +1303 -0
  251. package/test/tls_socket.js +321 -0
  252. package/test/transaction.js +554 -0
  253. package/tls_socket.js +771 -0
  254. package/transaction.js +267 -0
@@ -0,0 +1,3 @@
1
+ [haproxy]
2
+ enabled=true
3
+ hosts[] = 127.0.0.1
@@ -0,0 +1,3 @@
1
+ [haproxy]
2
+ enabled=false
3
+ hosts[] = 127.0.0.1
@@ -0,0 +1,3 @@
1
+ [haproxy]
2
+ enabled=true
3
+ hosts[] = 192.0.2.1
@@ -0,0 +1,21 @@
1
+ 'use strict'
2
+
3
+ const events = require('node:events')
4
+ const fixtures = require('haraka-test-fixtures')
5
+ const { stub } = fixtures.stub
6
+
7
+ class Socket extends events.EventEmitter {
8
+ constructor(port, host) {
9
+ super()
10
+ this.port = port
11
+ this.host = host
12
+ this.setTimeout = stub()
13
+ this.setKeepAlive = stub()
14
+ this.destroy = stub()
15
+ this.end = stub()
16
+ }
17
+ }
18
+
19
+ exports.Socket = Socket
20
+
21
+ exports.connect = (port, host) => new Socket(port, host)
Binary file
@@ -0,0 +1,156 @@
1
+ 'use strict'
2
+
3
+ const assert = require('node:assert')
4
+
5
+ const { Address } = require('@haraka/email-address')
6
+ const fixtures = require('haraka-test-fixtures')
7
+
8
+ /**
9
+ * Creates a HMailItem instance, which is passed to callback. Reports error on test param if creation fails.
10
+ *
11
+ * @param outbound_context
12
+ * @param options
13
+ * @param callback
14
+ */
15
+ exports.newMockHMailItem = (outbound_context, done, options, callback) => {
16
+ const opts = options || {}
17
+ exports.createHMailItem(outbound_context, opts, (err, hmail) => {
18
+ if (err) {
19
+ assert.ok(false, `Could not create HMailItem: ${err}`)
20
+ done()
21
+ return
22
+ }
23
+ if (!hmail.todo) {
24
+ hmail.once('ready', () => {
25
+ setImmediate(() => {
26
+ callback(hmail)
27
+ })
28
+ })
29
+ } else {
30
+ callback(hmail)
31
+ }
32
+ })
33
+ }
34
+
35
+ /**
36
+ * Creates a HMailItem instance for testing purpose
37
+ *
38
+ * @param outbound_context: The context of outbound, e.g. from require('outbound/index.js')
39
+ * @param options
40
+ * @param callback(err, hmail)
41
+ */
42
+ exports.createHMailItem = (outbound_context, options, callback) => {
43
+ const mail_from = options.mail_from || 'sender@domain'
44
+ const delivery_domain = options.delivery_domain || 'domain'
45
+ const mail_recipients = options.mail_recipients || [new Address('recipient@domain')]
46
+
47
+ const conn = fixtures.makeConnection({ withTxn: true })
48
+ conn.transaction.mail_from = new Address(mail_from)
49
+
50
+ const todo = new outbound_context.TODOItem(delivery_domain, mail_recipients, conn.transaction)
51
+ todo.uuid = `${todo.uuid}.1`
52
+
53
+ let contents = [
54
+ `From: ${mail_from}`,
55
+ `To: ${mail_recipients.join(', ')}`,
56
+ 'MIME-Version: 1.0',
57
+ 'Content-type: text/plain; charset=us-ascii',
58
+ 'Subject: Some subject here',
59
+ '',
60
+ 'Some email body here',
61
+ '',
62
+ ].join('\n')
63
+ let match
64
+ const re = /^([^\n]*\n?)/
65
+ while ((match = re.exec(contents))) {
66
+ let line = match[1]
67
+ line = line.replace(/\r?\n?$/, '\r\n') // make sure it ends in \r\n
68
+ conn.transaction.add_data(Buffer.from(line))
69
+ contents = contents.substring(match[1].length)
70
+ if (contents.length === 0) {
71
+ break
72
+ }
73
+ }
74
+ conn.transaction.message_stream.add_line_end()
75
+
76
+ const hmails = []
77
+ const ok_paths = []
78
+ outbound_context.exports
79
+ .process_delivery(ok_paths, todo, hmails)
80
+ .then(() => {
81
+ if (hmails.length == 0) {
82
+ callback('No hmail producted')
83
+ return
84
+ }
85
+ for (const hmail of hmails) {
86
+ hmail.hostlist = [delivery_domain]
87
+ callback(null, hmail)
88
+ }
89
+ })
90
+ .catch((err) => {
91
+ callback(`process_delivery error: ${err}`)
92
+ })
93
+ }
94
+
95
+ /**
96
+ * runs a socket.write
97
+ * @param socket
98
+ * @param test
99
+ * @param playbook
100
+ */
101
+ exports.playTestSmtpConversation = (hmail, socket, done, playbook, callback) => {
102
+ const testmx = {
103
+ bind_helo: 'haraka.test',
104
+ exchange: 'remote.testhost',
105
+ }
106
+ hmail.try_deliver_host_on_socket(testmx, 'testhost', 'testport', socket)
107
+
108
+ socket.write = (line) => {
109
+ //console.log('MockSocket.write(' + line.replace(/\n/, '\\n').replace(/\r/, '\\r') + ')');
110
+ if (playbook.length == 0) {
111
+ assert.ok(false, 'missing next playbook entry')
112
+ done()
113
+ return
114
+ }
115
+ let expected
116
+ while (false != (expected = getNextEntryFromPlaybook('haraka', playbook))) {
117
+ if (typeof expected.test === 'function') {
118
+ assert.ok(
119
+ expected.test(line),
120
+ expected.description || `Expected that line works with func: ${expected.test}`,
121
+ )
122
+ } else {
123
+ assert.equal(
124
+ `${expected.test}\r\n`,
125
+ line,
126
+ expected.description || `Expected that line equals: ${expected.test}`,
127
+ )
128
+ }
129
+ if (expected.end_test === true) {
130
+ setTimeout(() => {
131
+ callback()
132
+ }, 0)
133
+ return
134
+ }
135
+ }
136
+ setTimeout(() => {
137
+ let nextMessageFromServer
138
+ while (false != (nextMessageFromServer = getNextEntryFromPlaybook('remote', playbook))) {
139
+ socket.emit('line', `${nextMessageFromServer.line}\r\n`)
140
+ }
141
+ }, 0)
142
+ }
143
+
144
+ const welcome = getNextEntryFromPlaybook('remote', playbook)
145
+ socket.emit('line', welcome.line)
146
+ }
147
+
148
+ function getNextEntryFromPlaybook(ofType, playbook) {
149
+ if (playbook.length == 0) {
150
+ return false
151
+ }
152
+ if (playbook[0].from == ofType) {
153
+ return playbook.shift()
154
+ }
155
+ return false
156
+ }
@@ -0,0 +1 @@
1
+ flatisloaded
@@ -0,0 +1,10 @@
1
+ main2=blah
2
+
3
+ [sub1]
4
+ sub2=blah
5
+
6
+ [sub2]
7
+ sub2=foo
8
+
9
+ [sub3]
10
+ new=foo
@@ -0,0 +1 @@
1
+ ciphers=test
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+
3
+ exports.register = () => {
4
+ throw "This shouldn't get loaded";
5
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "load_first",
3
+ "version": "1.0.0",
4
+ "description": "This shouldn't get loaded",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "author": "",
10
+ "license": "MIT"
11
+ }
@@ -0,0 +1,9 @@
1
+ main1=foo
2
+ main2=bar
3
+
4
+ [sub1]
5
+ sub1=foo
6
+ sub2=bar
7
+
8
+ [sub2]
9
+ sub1=foo
@@ -0,0 +1,5 @@
1
+ {
2
+ "name": "test-plugin",
3
+ "version": "1.0.0",
4
+ "main": "test-plugin"
5
+ }
@@ -0,0 +1,5 @@
1
+ 'use strict';
2
+
3
+ exports.hook_init_master = next => {
4
+ next();
5
+ };
@@ -0,0 +1,3 @@
1
+ 'use strict'
2
+
3
+ exports.check_the_base = () => 'base'
@@ -0,0 +1,3 @@
1
+ 'use strict'
2
+
3
+ exports.register = () => {}
@@ -0,0 +1,11 @@
1
+ {
2
+ "name": "folder_plugin",
3
+ "version": "1.0.0",
4
+ "description": "Plugin in a folder",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "author": "",
10
+ "license": "MIT"
11
+ }
@@ -0,0 +1,7 @@
1
+ 'use strict'
2
+
3
+ exports.register = function () {
4
+ this.inherits('base_plugin')
5
+ }
6
+
7
+ exports.main_plugin_method = () => 'main'
@@ -0,0 +1,3 @@
1
+ exports.register = () => {}
2
+
3
+ exports.loaded_first = true
@@ -0,0 +1 @@
1
+ exports.register = () => {}
@@ -0,0 +1,3 @@
1
+ exports.register = () => {}
2
+
3
+ exports.core_override = true
package/test/logger.js ADDED
@@ -0,0 +1,217 @@
1
+ 'use strict'
2
+
3
+ const { describe, it, beforeEach } = require('node:test')
4
+ const assert = require('node:assert/strict')
5
+ const util = require('node:util')
6
+
7
+ const _set_up = () => {
8
+ this.logger = require('../logger')
9
+ }
10
+
11
+ describe('logger', () => {
12
+ beforeEach(_set_up)
13
+
14
+ describe('init', () => {
15
+ it('logger', () => {
16
+ assert.ok(this.logger)
17
+ })
18
+ })
19
+
20
+ describe('log', () => {
21
+ const formats = ['DEFAULT', 'LOGFMT', 'JSON']
22
+
23
+ for (const fmt of formats) {
24
+ it(`log in ${fmt} format`, () => {
25
+ this.logger.deferred_logs = []
26
+ this.logger.format = this.logger.formats[fmt]
27
+ assert.ok(this.logger.log('WARN', 'test warning'))
28
+ assert.equal(this.logger.deferred_logs.length, 1)
29
+ })
30
+
31
+ it(`log in ${fmt} format w/deferred`, () => {
32
+ this.logger.format = this.logger.formats[fmt]
33
+ this.logger.plugins = { plugin_list: true }
34
+ this.logger.deferred_logs.push({ level: 'INFO', data: 'log test info' })
35
+ assert.ok(this.logger.log('INFO', 'another test info'))
36
+ })
37
+ }
38
+ })
39
+
40
+ describe('level', () => {
41
+ it('both INFO and LOGINFO are log levels', () => {
42
+ assert.equal(this.logger.levels.INFO, 6)
43
+ assert.equal(this.logger.levels.LOGINFO, 6)
44
+ })
45
+ })
46
+
47
+ describe('set_format', () => {
48
+ // [input, expected format key]
49
+ const cases = [
50
+ ['DEFAULT', 'DEFAULT'],
51
+ ['LOGFMT', 'LOGFMT'],
52
+ ['JSON', 'JSON'],
53
+ ['', 'DEFAULT'], // empty → DEFAULT
54
+ ['default', 'DEFAULT'], // case-insensitive → DEFAULT
55
+ ['invalid', 'DEFAULT'], // unknown → DEFAULT
56
+ ]
57
+ for (const [input, expectedKey] of cases) {
58
+ it(`set_format(${JSON.stringify(input)}) → ${expectedKey}`, () => {
59
+ this.logger.format = ''
60
+ this.logger.set_format(input)
61
+ assert.equal(this.logger.format, this.logger.formats[expectedKey])
62
+ })
63
+ }
64
+ })
65
+
66
+ describe('set_loglevel', () => {
67
+ // [input, expected level key or null for numeric assertion]
68
+ const cases = [
69
+ ['LOGINFO', 'LOGINFO'],
70
+ ['INFO', 'INFO'],
71
+ ['emerg', 'EMERG'], // case-insensitive
72
+ [6, null], // numeric passthrough
73
+ ['invalid', 'WARN'], // unknown → WARN
74
+ ]
75
+ for (const [input, expectedKey] of cases) {
76
+ it(`set_loglevel(${JSON.stringify(input)}) → ${expectedKey ?? input}`, () => {
77
+ this.logger.set_loglevel(input)
78
+ const expected = expectedKey ? this.logger.levels[expectedKey] : input
79
+ assert.equal(this.logger.loglevel, expected)
80
+ })
81
+ }
82
+ })
83
+
84
+ describe('set_timestamps', () => {
85
+ it('set timestamps to false', () => {
86
+ this.logger.timestamps = undefined
87
+ this.logger.set_timestamps(false)
88
+ assert.equal(this.logger.timestamps, false)
89
+ })
90
+
91
+ it('set timestamps to true', () => {
92
+ this.logger.timestamps = undefined
93
+ this.logger.set_timestamps(true)
94
+ assert.equal(this.logger.timestamps, true)
95
+ })
96
+ })
97
+
98
+ describe('would_log', () => {
99
+ it('should', () => {
100
+ this.logger.loglevel = 4
101
+ assert.equal(false, this.logger.would_log(7))
102
+ assert.equal(false, this.logger.would_log(6))
103
+ assert.equal(false, this.logger.would_log(5))
104
+ })
105
+
106
+ it('should not', () => {
107
+ this.logger.loglevel = 4
108
+ assert.equal(true, this.logger.would_log(4))
109
+ assert.equal(true, this.logger.would_log(3))
110
+ assert.equal(true, this.logger.would_log(2))
111
+ assert.equal(true, this.logger.would_log(1))
112
+ })
113
+ })
114
+
115
+ describe('log_respond', () => {
116
+ it('invalid retval', () => {
117
+ assert.equal(false, this.logger.log_respond(901))
118
+ })
119
+
120
+ it('valid retval', () => {
121
+ const data = { level: 'INFO', data: 'test data' }
122
+ assert.equal(true, this.logger.log_respond(900, 'test msg', data))
123
+ })
124
+ })
125
+
126
+ describe('dump_logs', () => {
127
+ it('empty', () => {
128
+ assert.ok(this.logger.dump_logs(0))
129
+ })
130
+
131
+ it('with deferred', () => {
132
+ this.logger.deferred_logs.push({
133
+ level: 'info',
134
+ data: 'test info',
135
+ })
136
+ this.logger.deferred_logs.push({
137
+ level: 'INFO',
138
+ data: 'test info, color',
139
+ })
140
+ this.logger.deferred_logs.push({
141
+ level: 'WARN',
142
+ data: 'test warn, color',
143
+ })
144
+ assert.ok(this.logger.dump_logs(0))
145
+ assert.ok(this.logger.deferred_logs.length === 0)
146
+ })
147
+ })
148
+
149
+ describe('colors', () => {
150
+ it('colors', () => {
151
+ assert.ok(this.logger.colors)
152
+ })
153
+
154
+ it('colorize', () => {
155
+ assert.ok(this.logger.colorize)
156
+ assert.equal('function', typeof this.logger.colorize)
157
+ assert.equal('error', this.logger.colorize('bad-color', 'error'))
158
+ const expected = util.inspect.colors ? '\u001b[34mgood\u001b[39m' : 'good'
159
+ assert.equal(expected, this.logger.colorize('blue', 'good'))
160
+ })
161
+ })
162
+
163
+ describe('log_if_level', () => {
164
+ it('is a function', () => {
165
+ assert.equal(typeof this.logger.log_if_level, 'function')
166
+ })
167
+
168
+ it('returns a logging function', () => {
169
+ this.logger.loglevel = 9
170
+ const f = this.logger.log_if_level('INFO', 'LOGINFO')
171
+ assert.equal(typeof f, 'function')
172
+ })
173
+
174
+ // Each of these runs independently with a fresh deferred_logs
175
+ for (const [label, msg] of [
176
+ ['string', 'test info message'],
177
+ ['null', null],
178
+ ['false', false],
179
+ ['0 (falsy number)', 0],
180
+ ]) {
181
+ it(`logs ${label} value and appends to deferred_logs`, () => {
182
+ this.logger.loglevel = 9
183
+ this.logger.deferred_logs = []
184
+ const f = this.logger.log_if_level('INFO', 'LOGINFO')
185
+ assert.ok(f(msg))
186
+ assert.equal(this.logger.deferred_logs.length, 1)
187
+ })
188
+ }
189
+
190
+ it('records correct level in deferred log entry', () => {
191
+ this.logger.loglevel = 9
192
+ this.logger.deferred_logs = []
193
+ const f = this.logger.log_if_level('INFO', 'LOGINFO')
194
+ f('test info message')
195
+ assert.equal(this.logger.deferred_logs[0].level, 'INFO')
196
+ })
197
+ })
198
+
199
+ describe('add_log_methods', () => {
200
+ it('ignores non-objects', () => {
201
+ assert.equal(undefined, this.logger.add_log_methods(''))
202
+ assert.equal(
203
+ undefined,
204
+ this.logger.add_log_methods(function foo() {}),
205
+ )
206
+ })
207
+
208
+ it('adds functions to an object', () => {
209
+ const testObj = {}
210
+ this.logger.add_log_methods(testObj)
211
+ const levels = ['DATA', 'PROTOCOL', 'DEBUG', 'INFO', 'NOTICE', 'WARN', 'ERROR', 'CRIT', 'ALERT', 'EMERG']
212
+ for (const level of levels) {
213
+ assert.ok('function' === typeof testObj[`log${level.toLowerCase()}`])
214
+ }
215
+ })
216
+ })
217
+ })
File without changes
@@ -0,0 +1,45 @@
1
+ -----BEGIN PRIVATE KEY-----
2
+ MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDcg5h5TVO1gECK
3
+ yNCXbpJduNqJvhE6hyVb9q0WRR8zKHE7DnOog9JqOcrz4mv3TmszDZ2511mGxo/v
4
+ j2dAYakU7HxEuSqKX1CsjbDP3xa7IvVCaKQbcMImq7dzmenXkCdPivuglZmooZen
5
+ c18QZ6YkrunDeh/OcP8WAA+9yYXp82lmKPzKNkJETfGVXff0loXWR5SSjGXYvjqm
6
+ XK6IXqPcuNriUTmylLx2149O6RWJPaZ2YYxTOHTeV5OMeEHjLpAOShCfZi4VYvAe
7
+ GZSFq5UdMv5QD1k6BueS1Ruf6ChCLjfqkMcCAw8DOY8oxvzovgM/sgBcx3L00/pe
8
+ QeSegG+3AgMBAAECggEAW9qJEcYvH0SMHgNmOB375ARTK9s7S/jti/Aly0gBpgqr
9
+ l+D+NmyqokruikZ/mKVWrA546+eTSDu/yxcd+Eh16NxVKz9CRB9N+IKQ6xXPXyZB
10
+ D/jXYW7pcafOGT0PTbHxUMrUxahhAjKKfPt3Y7JVcQKBgQDzIhmN7SbQvu2dl54X
11
+ XezrgKteDVd4q7VYVpiAjNEZA+kNdBcXC6k2T5WMNPesNwyFIoDLDFWUg4FMG/Mc
12
+ KA1eArBocGQ0gQvLlnlUxBy519e/AAj7jTspLi7gAwLqfTo0TGdTH/Hfq+1uCXys
13
+ dd3BKYnDKc4aDPTQCEkRzfPHDwKBgQDoLw7MZecGnNNrqArqsOaOO1uUKFysW6pi
14
+ 2ZU7KKj1x6vKGIW88YmzNBPCj4LU8XlXbR1isaSs5TaWgc6N0aAEXwA6TN/8PXhq
15
+ 6IXarR1WJIq2DEDtdBrj2AiaPoF8Y6hsebsQs+EpyLx8MCGLaucYJvqyK87ep000
16
+ mXQuyfgM2QKBgHCLy2qAaeRdTV8S7TKB3wcQ88LAyEnqqjJvO37eMHi076+zmnCn
17
+ jDfA1UgmyLNmdBw44YeceQ0bZsHVek8BV1a6RfDCfhAz4ELor9eGRInemVcn7ACN
18
+ 2uHwJ/C4VCQ5vbSx3W6ELhHM40Z5i8XFddZRpRy7gFVcxAJ8o15jiMIPAoGAHiq3
19
+ DoGS8b4AjjVILdQMMKCvtmFEITTLv4orpIMU6NInlNt4zOLJFFqI0reYtRgmvuAz
20
+ eDZCgiBJ5mY5Mx3wX4EEY47Hb1uBQMqzUYU6kY2v5BVVfkSelcnk3D2Qz1uXb3il
21
+ gHcOo0IskyohwZ6DJhUyb2HXwAAWvOXPPaEKNIkCgYAqWhzYCAoxZ6f7i2I3J1JO
22
+ 5OaMi4+9YR3ivTDcKVYp1ZOzANe0gsQlal/gf2fTjG35b9FyK3Lo5rp0QLKxv2vh
23
+ 6dR+sk+58jJhk8H1kPNIVzvA4SAd51YoE0x7edi7+5vDMwlz57yz5rwMQvN1wUOO
24
+ 5Ev9F9qrVJZFF4Ei+fRW9Q==
25
+ -----END PRIVATE KEY-----
26
+ -----BEGIN CERTIFICATE-----
27
+ MIIDzzCCAregAwIBAgIJAOa6xwibkwczMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNV
28
+ BAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQHDAdTZWF0dGxlMQ8w
29
+ DQYDVQQKDAZIYXJha2ExFTATBgNVBAMMDGhhcmFrYS5sb2NhbDEgMB4GCSqGSIb3
30
+ DQEJARYRbWF0dEBoYXJha2EubG9jYWwwHhcNMTcwMzA0MjMyODQ5WhcNMjMwMzAz
31
+ MjMyODQ5WjB+MQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjEQMA4G
32
+ A1UEBwwHU2VhdHRsZTEPMA0GA1UECgwGSGFyYWthMRUwEwYDVQQDDAxoYXJha2Eu
33
+ bG9jYWwxIDAeBgkqhkiG9w0BCQEWEW1hdHRAaGFyYWthLmxvY2FsMIIBIjANBgkq
34
+ FgAPvcmF6fNpZij8yjZCRE3xlV339JaF1keUkoxl2L46plyuiF6j3Lja4lE5spS8
35
+ dtePTukViT2mdmGMUzh03leTjHhB4y6QDkoQn2YuFWLwHhmUhauVHTL+UA9ZOgbn
36
+ ktUbn+goQi436pDHAgMPAzmPKMb86L4DP7IAXMdy9NP6XkHknoBvtwIDAQABo1Aw
37
+ TjAdBgNVHQ4EFgQUsfam5K8yKVyyJG7NQfKXjpr6gYEwHwYDVR0jBBgwFoAUsfam
38
+ 5K8yKVyyJG7NQfKXjpr6gYEwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC
39
+ AQEAL7vMH/sYj/rDzo+pYn8qK9eZBpTPQLsuiotNYqoH/tOJzaOBI2cMSrbGM3zG
40
+ aegTqKOduO6vpXun7MT4tGilOxt+1eve6RbsjKMeTkZr+A44rRRUZ4LHZe38oaGk
41
+ A8jB6YHiiefH1mgfSN1igcT7SkOxv8WM4jsCyOCy3wG8b4V8wvDytOtJOJo041hX
42
+ njmypWHaZ1IDYu1ybnb/Macnno0NMkEMx0uIlG/c3+KvJwpz2WHrKrKA5l5oGp/n
43
+ +F3pt6NhSJCDG0cktax07LIvxMpAoOaJ6cYSfwB/v0HiYh2733bEXEiQ2jxO5vXo
44
+ NS2fKRYBqs2ATDVHpzknBC1KcA==
45
+ -----END CERTIFICATE-----
@@ -0,0 +1,43 @@
1
+
2
+ key = tls_key.pem
3
+ cert = tls_cert.pem
4
+ dhparam = dhparams.pem
5
+
6
+ ciphers = ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384
7
+ minVersion = TLSv1
8
+ rejectUnauthorized=false
9
+ requestCert=true
10
+ honorCipherOrder=true
11
+ requireAuthorized[]=2465
12
+ requireAuthorized[]=2587
13
+
14
+ no_starttls_ports[]=2525
15
+
16
+ [redis]
17
+ ; options in this block require redis to be available.
18
+
19
+ ; remember when a remote fails STARTTLS. The next time they connect,
20
+ ; don't offer STARTTLS option (so message gets delivered).
21
+ ; pro: increases mail reliability
22
+ ; con: reduces security
23
+ ; default: false
24
+ ; disable_for_failed_hosts=true
25
+
26
+
27
+ ; no_tls_hosts - disable TLS for servers with broken TLS.
28
+ [no_tls_hosts]
29
+ ; 127.0.0.1
30
+ ; 192.168.1.1
31
+ ; 172.16.0.0/16
32
+
33
+ [outbound]
34
+ key = outbound_tls_key.pem
35
+ cert = outbound_tls_cert.pem
36
+ dhparam = dhparams.pem
37
+ ciphers = ECDHE-RSA-AES256-GCM-SHA384
38
+ minVersion = TLSv1
39
+ rejectUnauthorized=false
40
+ requestCert=false
41
+ honorCipherOrder=false
42
+ force_tls_hosts[]=first.example.com
43
+ force_tls_hosts[]=second.example.net
@@ -0,0 +1,23 @@
1
+ MIME-Version: 1.0
2
+ Content-Type: text/html;
3
+ Content-Transfer-Encoding: base64
4
+
5
+ PCFET0NUWVBFIGh0bWw+CjxodG1sPgo
6
+ 8aGVhZD4KCTx0aXRsZT5UaGlzIGlzIG
7
+ EgdGVzdDwvdGl0bGU+CjwvaGVhZD4KP
8
+ GJvZHk+Cgk8Yj5UaGlzIGlzIG9ubHkg
9
+ YSB0ZXN0PC9iPgoJPHA+CglUaGlzIGR
10
+ vY3VtZW50IGRlc2NyaWJlcyB0aGUgY2
11
+ 9tbW9ubHkgdXNlZCBiYXNlIDY0LCBiY
12
+ XNlIDMyLCBhbmQgYmFzZQoJMTYgZW5j
13
+ b2Rpbmcgc2NoZW1lcy4gIEl0IGFsc28
14
+ gZGlzY3Vzc2VzIHRoZSB1c2Ugb2YgbG
15
+ luZS1mZWVkcyBpbgoJZW5jb2RlZCBkY
16
+ XRhLCB1c2Ugb2YgcGFkZGluZyBpbiBl
17
+ bmNvZGVkIGRhdGEsIHVzZSBvZiBub24
18
+ tYWxwaGFiZXQKCWNoYXJhY3RlcnMgaW
19
+ 4gZW5jb2RlZCBkYXRhLCB1c2Ugb2YgZ
20
+ GlmZmVyZW50IGVuY29kaW5nIGFscGhh
21
+ YmV0cywgYW5kCgljYW5vbmljYWwgZW5
22
+ jb2RpbmdzLgoJPC9wPgo8L2JvZHk+Cj
23
+ wvaHRtbD4=