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.
- package/.prettierignore +4 -0
- package/CONTRIBUTORS.md +5 -5
- package/Changes.md +69 -50
- package/Plugins.md +3 -1
- package/README.md +1 -1
- package/bin/haraka +475 -478
- package/config/outbound.ini +3 -0
- package/connection.js +1072 -1108
- package/docs/Connection.md +29 -30
- package/docs/CoreConfig.md +38 -39
- package/docs/CustomReturnCodes.md +0 -1
- package/docs/HAProxy.md +2 -2
- package/docs/Header.md +1 -1
- package/docs/Logging.md +29 -5
- package/docs/Outbound.md +93 -78
- package/docs/Plugins.md +103 -108
- package/docs/Transaction.md +49 -51
- package/docs/Tutorial.md +127 -143
- package/docs/deprecated/access.md +0 -1
- package/docs/deprecated/backscatterer.md +2 -3
- package/docs/deprecated/connect.rdns_access.md +18 -27
- package/docs/deprecated/data.headers.md +0 -1
- package/docs/deprecated/data.nomsgid.md +1 -2
- package/docs/deprecated/data.noreceived.md +1 -2
- package/docs/deprecated/data.rfc5322_header_checks.md +1 -2
- package/docs/deprecated/dkim_sign.md +13 -17
- package/docs/deprecated/dkim_verify.md +9 -17
- package/docs/deprecated/dnsbl.md +36 -38
- package/docs/deprecated/dnswl.md +41 -43
- package/docs/deprecated/lookup_rdns.strict.md +21 -34
- package/docs/deprecated/mail_from.access.md +17 -25
- package/docs/deprecated/mail_from.blocklist.md +9 -12
- package/docs/deprecated/mail_from.nobounces.md +1 -2
- package/docs/deprecated/rcpt_to.access.md +20 -27
- package/docs/deprecated/rcpt_to.blocklist.md +10 -13
- package/docs/deprecated/rcpt_to.routes.md +0 -1
- package/docs/deprecated/rdns.regexp.md +13 -15
- package/docs/plugins/aliases.md +89 -89
- package/docs/plugins/auth/auth_bridge.md +5 -7
- package/docs/plugins/auth/auth_ldap.md +11 -14
- package/docs/plugins/auth/auth_proxy.md +10 -12
- package/docs/plugins/auth/auth_vpopmaild.md +5 -6
- package/docs/plugins/auth/flat_file.md +4 -4
- package/docs/plugins/block_me.md +3 -3
- package/docs/plugins/data.signatures.md +1 -2
- package/docs/plugins/delay_deny.md +3 -4
- package/docs/plugins/max_unrecognized_commands.md +4 -4
- package/docs/plugins/prevent_credential_leaks.md +6 -6
- package/docs/plugins/process_title.md +18 -18
- package/docs/plugins/queue/deliver.md +2 -3
- package/docs/plugins/queue/discard.md +4 -4
- package/docs/plugins/queue/lmtp.md +1 -3
- package/docs/plugins/queue/qmail-queue.md +7 -9
- package/docs/plugins/queue/quarantine.md +16 -21
- package/docs/plugins/queue/rabbitmq.md +8 -11
- package/docs/plugins/queue/rabbitmq_amqplib.md +43 -39
- package/docs/plugins/queue/smtp_bridge.md +7 -10
- package/docs/plugins/queue/smtp_forward.md +42 -34
- package/docs/plugins/queue/smtp_proxy.md +30 -29
- package/docs/plugins/queue/test.md +1 -3
- package/docs/plugins/rcpt_to.in_host_list.md +6 -6
- package/docs/plugins/rcpt_to.max_count.md +1 -1
- package/docs/plugins/record_envelope_addresses.md +3 -3
- package/docs/plugins/reseed_rng.md +6 -6
- package/docs/plugins/status.md +9 -8
- package/docs/plugins/tarpit.md +7 -11
- package/docs/plugins/tls.md +12 -17
- package/docs/plugins/toobusy.md +4 -4
- package/docs/plugins/xclient.md +3 -3
- package/docs/tutorials/Migrating_from_v1_to_v2.md +19 -41
- package/docs/tutorials/SettingUpOutbound.md +6 -9
- package/endpoint.js +35 -38
- package/eslint.config.mjs +22 -19
- package/haraka.js +42 -47
- package/host_pool.js +75 -79
- package/http/html/404.html +45 -49
- package/http/html/index.html +39 -28
- package/http/package.json +2 -4
- package/line_socket.js +27 -28
- package/logger.js +182 -201
- package/outbound/client_pool.js +34 -27
- package/outbound/config.js +64 -59
- package/outbound/fsync_writestream.js +24 -25
- package/outbound/hmail.js +888 -835
- package/outbound/index.js +194 -187
- package/outbound/qfile.js +49 -52
- package/outbound/queue.js +197 -190
- package/outbound/timer_queue.js +41 -43
- package/outbound/tls.js +68 -61
- package/outbound/todo.js +11 -11
- package/package.json +38 -33
- package/plugins/.eslintrc.yaml +0 -1
- package/plugins/auth/auth_base.js +123 -127
- package/plugins/auth/auth_bridge.js +7 -7
- package/plugins/auth/auth_proxy.js +121 -126
- package/plugins/auth/auth_vpopmaild.js +84 -85
- package/plugins/auth/flat_file.js +18 -17
- package/plugins/block_me.js +31 -31
- package/plugins/data.signatures.js +13 -13
- package/plugins/delay_deny.js +65 -61
- package/plugins/prevent_credential_leaks.js +23 -23
- package/plugins/process_title.js +125 -128
- package/plugins/profile.js +5 -5
- package/plugins/queue/deliver.js +3 -3
- package/plugins/queue/discard.js +13 -14
- package/plugins/queue/lmtp.js +16 -17
- package/plugins/queue/qmail-queue.js +54 -55
- package/plugins/queue/quarantine.js +68 -70
- package/plugins/queue/rabbitmq.js +80 -87
- package/plugins/queue/rabbitmq_amqplib.js +75 -54
- package/plugins/queue/smtp_bridge.js +16 -16
- package/plugins/queue/smtp_forward.js +175 -179
- package/plugins/queue/smtp_proxy.js +69 -71
- package/plugins/queue/test.js +9 -9
- package/plugins/rcpt_to.host_list_base.js +30 -34
- package/plugins/rcpt_to.in_host_list.js +19 -19
- package/plugins/record_envelope_addresses.js +4 -4
- package/plugins/reseed_rng.js +4 -4
- package/plugins/status.js +90 -97
- package/plugins/tarpit.js +25 -14
- package/plugins/tls.js +68 -68
- package/plugins/toobusy.js +21 -23
- package/plugins/xclient.js +51 -53
- package/plugins.js +276 -293
- package/rfc1869.js +30 -35
- package/server.js +308 -299
- package/smtp_client.js +244 -228
- package/test/.eslintrc.yaml +0 -1
- package/test/connection.js +127 -134
- package/test/endpoint.js +53 -47
- package/test/fixtures/line_socket.js +12 -12
- package/test/fixtures/util_hmailitem.js +89 -85
- package/test/host_pool.js +90 -92
- package/test/installation/plugins/base_plugin.js +2 -2
- package/test/installation/plugins/folder_plugin/index.js +2 -3
- package/test/installation/plugins/inherits.js +3 -3
- package/test/installation/plugins/load_first.js +2 -3
- package/test/installation/plugins/plugin.js +1 -3
- package/test/installation/plugins/tls.js +2 -4
- package/test/logger.js +135 -116
- package/test/outbound/hmail.js +49 -35
- package/test/outbound/index.js +118 -101
- package/test/outbound/qfile.js +51 -53
- package/test/outbound_bounce_net_errors.js +84 -69
- package/test/outbound_bounce_rfc3464.js +235 -165
- package/test/plugins/auth/auth_base.js +420 -279
- package/test/plugins/auth/auth_vpopmaild.js +38 -39
- package/test/plugins/queue/smtp_forward.js +126 -104
- package/test/plugins/rcpt_to.host_list_base.js +85 -67
- package/test/plugins/rcpt_to.in_host_list.js +159 -112
- package/test/plugins/status.js +71 -64
- package/test/plugins/tls.js +37 -34
- package/test/plugins.js +97 -92
- package/test/rfc1869.js +19 -26
- package/test/server.js +293 -272
- package/test/smtp_client.js +180 -176
- package/test/tls_socket.js +62 -66
- package/test/transaction.js +159 -160
- package/tls_socket.js +331 -333
- package/transaction.js +129 -137
package/test/server.js
CHANGED
|
@@ -1,107 +1,115 @@
|
|
|
1
1
|
const assert = require('node:assert')
|
|
2
|
-
const path = require('node:path')
|
|
2
|
+
const path = require('node:path')
|
|
3
3
|
|
|
4
|
-
const endpoint = require('../endpoint')
|
|
4
|
+
const endpoint = require('../endpoint')
|
|
5
5
|
const message = require('haraka-email-message')
|
|
6
6
|
|
|
7
7
|
const _set_up = (done) => {
|
|
8
|
-
this.config = require('haraka-config')
|
|
9
|
-
this.server = require('../server')
|
|
10
|
-
done()
|
|
8
|
+
this.config = require('haraka-config')
|
|
9
|
+
this.server = require('../server')
|
|
10
|
+
done()
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
const _setupServer = (ip_port, done) => {
|
|
14
|
-
process.env.YES_REALLY_DO_DISCARD=1
|
|
15
|
-
process.env.HARAKA_TEST_DIR=path.resolve('test')
|
|
14
|
+
process.env.YES_REALLY_DO_DISCARD = 1 // for queue/discard plugin
|
|
15
|
+
process.env.HARAKA_TEST_DIR = path.resolve('test')
|
|
16
16
|
|
|
17
17
|
// test sets the default path for plugin instances to the test dir
|
|
18
|
-
const test_cfg_path=path.resolve('test')
|
|
18
|
+
const test_cfg_path = path.resolve('test')
|
|
19
19
|
|
|
20
|
-
this.server = require('../server')
|
|
21
|
-
this.config = require('haraka-config').module_config(test_cfg_path)
|
|
22
|
-
this.server.logger.loglevel = 6
|
|
20
|
+
this.server = require('../server')
|
|
21
|
+
this.config = require('haraka-config').module_config(test_cfg_path)
|
|
22
|
+
this.server.logger.loglevel = 6 // INFO
|
|
23
23
|
|
|
24
24
|
// set the default path for the plugin loader
|
|
25
|
-
this.server.config = this.config.module_config(test_cfg_path)
|
|
26
|
-
this.server.plugins.config = this.config.module_config(test_cfg_path)
|
|
25
|
+
this.server.config = this.config.module_config(test_cfg_path)
|
|
26
|
+
this.server.plugins.config = this.config.module_config(test_cfg_path)
|
|
27
27
|
// this.server.outbound.config = this.config.module_config(this_cfg_path);
|
|
28
28
|
|
|
29
|
-
this.server.load_smtp_ini()
|
|
30
|
-
this.server.cfg.main.listen = ip_port
|
|
31
|
-
this.server.cfg.main.smtps_port = 2465
|
|
29
|
+
this.server.load_smtp_ini()
|
|
30
|
+
this.server.cfg.main.listen = ip_port
|
|
31
|
+
this.server.cfg.main.smtps_port = 2465
|
|
32
32
|
|
|
33
33
|
this.server.load_default_tls_config(() => {
|
|
34
|
-
this.server.createServer({})
|
|
34
|
+
this.server.createServer({})
|
|
35
35
|
setTimeout(() => {
|
|
36
|
-
done()
|
|
37
|
-
}, 200)
|
|
36
|
+
done()
|
|
37
|
+
}, 200)
|
|
38
38
|
})
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
const _tearDownServer = (done) => {
|
|
42
|
-
delete process.env.YES_REALLY_DO_DISCARD
|
|
43
|
-
delete process.env.HARAKA_TEST_DIR
|
|
44
|
-
this.server.stopListeners()
|
|
45
|
-
this.server.plugins.registered_hooks = {}
|
|
42
|
+
delete process.env.YES_REALLY_DO_DISCARD
|
|
43
|
+
delete process.env.HARAKA_TEST_DIR
|
|
44
|
+
this.server.stopListeners()
|
|
45
|
+
this.server.plugins.registered_hooks = {}
|
|
46
46
|
setTimeout(() => {
|
|
47
|
-
done()
|
|
48
|
-
}, 200)
|
|
47
|
+
done()
|
|
48
|
+
}, 200)
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
describe('server', () => {
|
|
52
|
-
|
|
53
52
|
describe('get_listen_addrs', () => {
|
|
54
53
|
beforeEach(_set_up)
|
|
55
54
|
|
|
56
55
|
it('IPv4 fully qualified', () => {
|
|
57
|
-
const listeners = this.server.get_listen_addrs({
|
|
58
|
-
|
|
56
|
+
const listeners = this.server.get_listen_addrs({
|
|
57
|
+
listen: '127.0.0.1:25',
|
|
58
|
+
})
|
|
59
|
+
assert.deepEqual(['127.0.0.1:25'], listeners)
|
|
59
60
|
})
|
|
60
61
|
|
|
61
62
|
it('IPv4, default port', () => {
|
|
62
|
-
const listeners = this.server.get_listen_addrs({
|
|
63
|
-
|
|
63
|
+
const listeners = this.server.get_listen_addrs({
|
|
64
|
+
listen: '127.0.0.1',
|
|
65
|
+
})
|
|
66
|
+
assert.deepEqual(['127.0.0.1:25'], listeners)
|
|
64
67
|
})
|
|
65
68
|
|
|
66
69
|
it('IPv4, custom port', () => {
|
|
67
|
-
const listeners = this.server.get_listen_addrs({ listen: '127.0.0.1'}, 250)
|
|
68
|
-
assert.deepEqual(['127.0.0.1:250'], listeners)
|
|
70
|
+
const listeners = this.server.get_listen_addrs({ listen: '127.0.0.1' }, 250)
|
|
71
|
+
assert.deepEqual(['127.0.0.1:250'], listeners)
|
|
69
72
|
})
|
|
70
73
|
|
|
71
74
|
it('IPv6 fully qualified', () => {
|
|
72
|
-
const listeners = this.server.get_listen_addrs({
|
|
73
|
-
|
|
75
|
+
const listeners = this.server.get_listen_addrs({
|
|
76
|
+
listen: '[::1]:25',
|
|
77
|
+
})
|
|
78
|
+
assert.deepEqual(['[::1]:25'], listeners)
|
|
74
79
|
})
|
|
75
80
|
|
|
76
81
|
it('IPv6, default port', () => {
|
|
77
|
-
const listeners = this.server.get_listen_addrs({listen: '[::1]'})
|
|
78
|
-
assert.deepEqual(['[::1]:25'], listeners)
|
|
82
|
+
const listeners = this.server.get_listen_addrs({ listen: '[::1]' })
|
|
83
|
+
assert.deepEqual(['[::1]:25'], listeners)
|
|
79
84
|
})
|
|
80
85
|
|
|
81
86
|
it('IPv6, custom port', () => {
|
|
82
|
-
const listeners = this.server.get_listen_addrs({listen: '[::1]'}, 250)
|
|
83
|
-
assert.deepEqual(['[::1]:250'], listeners)
|
|
87
|
+
const listeners = this.server.get_listen_addrs({ listen: '[::1]' }, 250)
|
|
88
|
+
assert.deepEqual(['[::1]:250'], listeners)
|
|
84
89
|
})
|
|
85
90
|
|
|
86
91
|
it('IPv4 & IPv6 fully qualified', () => {
|
|
87
92
|
const listeners = this.server.get_listen_addrs({
|
|
88
|
-
listen: '127.0.0.1:25,[::1]:25'
|
|
89
|
-
})
|
|
90
|
-
assert.deepEqual(['127.0.0.1:25','[::1]:25'], listeners)
|
|
93
|
+
listen: '127.0.0.1:25,[::1]:25',
|
|
94
|
+
})
|
|
95
|
+
assert.deepEqual(['127.0.0.1:25', '[::1]:25'], listeners)
|
|
91
96
|
})
|
|
92
97
|
|
|
93
98
|
it('IPv4 & IPv6, default port', () => {
|
|
94
99
|
const listeners = this.server.get_listen_addrs({
|
|
95
|
-
listen: '127.0.0.1:25,[::1]'
|
|
96
|
-
})
|
|
97
|
-
assert.deepEqual(['127.0.0.1:25','[::1]:25'], listeners)
|
|
100
|
+
listen: '127.0.0.1:25,[::1]',
|
|
101
|
+
})
|
|
102
|
+
assert.deepEqual(['127.0.0.1:25', '[::1]:25'], listeners)
|
|
98
103
|
})
|
|
99
104
|
|
|
100
105
|
it('IPv4 & IPv6, custom port', () => {
|
|
101
|
-
const listeners = this.server.get_listen_addrs(
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
106
|
+
const listeners = this.server.get_listen_addrs(
|
|
107
|
+
{
|
|
108
|
+
listen: '127.0.0.1,[::1]',
|
|
109
|
+
},
|
|
110
|
+
250,
|
|
111
|
+
)
|
|
112
|
+
assert.deepEqual(['127.0.0.1:250', '[::1]:250'], listeners)
|
|
105
113
|
})
|
|
106
114
|
})
|
|
107
115
|
|
|
@@ -109,60 +117,60 @@ describe('server', () => {
|
|
|
109
117
|
beforeEach(_set_up)
|
|
110
118
|
|
|
111
119
|
it('saves settings to Server.cfg', () => {
|
|
112
|
-
this.server.load_smtp_ini()
|
|
120
|
+
this.server.load_smtp_ini()
|
|
113
121
|
// console.log(this.server.cfg);
|
|
114
|
-
const c = this.server.cfg.main
|
|
115
|
-
assert.notEqual(c.daemonize, undefined)
|
|
116
|
-
assert.notEqual(c.daemon_log_file, undefined)
|
|
117
|
-
assert.notEqual(c.daemon_pid_file, undefined)
|
|
122
|
+
const c = this.server.cfg.main
|
|
123
|
+
assert.notEqual(c.daemonize, undefined)
|
|
124
|
+
assert.notEqual(c.daemon_log_file, undefined)
|
|
125
|
+
assert.notEqual(c.daemon_pid_file, undefined)
|
|
118
126
|
})
|
|
119
127
|
})
|
|
120
128
|
|
|
121
129
|
describe('get_smtp_server', () => {
|
|
122
130
|
beforeEach((done) => {
|
|
123
|
-
this.config = require('haraka-config')
|
|
124
|
-
this.config = this.config.module_config(path.resolve('test'))
|
|
131
|
+
this.config = require('haraka-config')
|
|
132
|
+
this.config = this.config.module_config(path.resolve('test'))
|
|
125
133
|
|
|
126
|
-
this.server = require('../server')
|
|
127
|
-
this.server.config = this.config
|
|
128
|
-
this.server.plugins.config = this.config
|
|
134
|
+
this.server = require('../server')
|
|
135
|
+
this.server.config = this.config
|
|
136
|
+
this.server.plugins.config = this.config
|
|
129
137
|
|
|
130
138
|
this.server.load_default_tls_config(() => {
|
|
131
139
|
setTimeout(() => {
|
|
132
|
-
done()
|
|
133
|
-
}, 200)
|
|
134
|
-
})
|
|
140
|
+
done()
|
|
141
|
+
}, 200)
|
|
142
|
+
})
|
|
135
143
|
})
|
|
136
144
|
|
|
137
145
|
it('gets a net server object', (done) => {
|
|
138
|
-
this.server.get_smtp_server(endpoint('0.0.0.0:2501'), 10).then(server => {
|
|
146
|
+
this.server.get_smtp_server(endpoint('0.0.0.0:2501'), 10).then((server) => {
|
|
139
147
|
if (!server) {
|
|
140
|
-
console.error('unable to bind to 0.0.0.0:2501')
|
|
148
|
+
console.error('unable to bind to 0.0.0.0:2501')
|
|
141
149
|
if (process.env.CI) return // can't bind to IP/port (fails on Travis)
|
|
142
150
|
}
|
|
143
|
-
assert.ok(server)
|
|
144
|
-
assert.equal(server.has_tls, false)
|
|
151
|
+
assert.ok(server)
|
|
152
|
+
assert.equal(server.has_tls, false)
|
|
145
153
|
server.getConnections((err, count) => {
|
|
146
|
-
assert.equal(0, count)
|
|
154
|
+
assert.equal(0, count)
|
|
147
155
|
done()
|
|
148
156
|
})
|
|
149
157
|
})
|
|
150
158
|
})
|
|
151
159
|
|
|
152
160
|
it('gets a TLS net server object', (done) => {
|
|
153
|
-
this.server.cfg.main.smtps_port = 2502
|
|
161
|
+
this.server.cfg.main.smtps_port = 2502
|
|
154
162
|
this.server.get_smtp_server(endpoint('0.0.0.0:2502'), 10).then((server) => {
|
|
155
163
|
if (!server) {
|
|
156
|
-
console.error('unable to bind to 0.0.0.0:2502')
|
|
164
|
+
console.error('unable to bind to 0.0.0.0:2502')
|
|
157
165
|
if (process.env.CI) return // can't bind to IP/port (fails on Travis)
|
|
158
166
|
}
|
|
159
|
-
assert.ok(server)
|
|
160
|
-
assert.equal(server.has_tls, true)
|
|
167
|
+
assert.ok(server)
|
|
168
|
+
assert.equal(server.has_tls, true)
|
|
161
169
|
server.getConnections((err, count) => {
|
|
162
|
-
assert.equal(0, count)
|
|
170
|
+
assert.equal(0, count)
|
|
163
171
|
done()
|
|
164
|
-
})
|
|
165
|
-
})
|
|
172
|
+
})
|
|
173
|
+
})
|
|
166
174
|
})
|
|
167
175
|
})
|
|
168
176
|
|
|
@@ -170,7 +178,7 @@ describe('server', () => {
|
|
|
170
178
|
beforeEach(_set_up)
|
|
171
179
|
|
|
172
180
|
it('gets a fs path', () => {
|
|
173
|
-
assert.ok(this.server.get_http_docroot())
|
|
181
|
+
assert.ok(this.server.get_http_docroot())
|
|
174
182
|
})
|
|
175
183
|
})
|
|
176
184
|
|
|
@@ -182,53 +190,52 @@ describe('server', () => {
|
|
|
182
190
|
afterEach(_tearDownServer)
|
|
183
191
|
|
|
184
192
|
it('accepts SMTP message', () => {
|
|
185
|
-
|
|
186
|
-
const server = { notes: { } };
|
|
193
|
+
const server = { notes: {} }
|
|
187
194
|
const cfg = {
|
|
188
195
|
connect_timeout: 2,
|
|
189
196
|
}
|
|
190
197
|
|
|
191
|
-
const smtp_client
|
|
192
|
-
|
|
193
|
-
smtp_client.get_client(
|
|
194
|
-
|
|
195
|
-
client
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
.on('helo', () => {
|
|
200
|
-
client.send_command('MAIL', 'FROM:<test@haraka.local>');
|
|
201
|
-
})
|
|
202
|
-
.on('mail', () => {
|
|
203
|
-
client.send_command('RCPT', 'TO:<nobody-will-see-this@haraka.local>');
|
|
204
|
-
})
|
|
205
|
-
.on('rcpt', () => {
|
|
206
|
-
client.send_command('DATA');
|
|
207
|
-
})
|
|
208
|
-
.on('data', () => {
|
|
209
|
-
const message_stream = new message.stream(
|
|
210
|
-
{ main : { spool_after : 1024 } }, "theMessageId"
|
|
211
|
-
);
|
|
212
|
-
|
|
213
|
-
message_stream.on('end', () => {
|
|
214
|
-
client.socket.write('.\r\n');
|
|
198
|
+
const smtp_client = require('../smtp_client')
|
|
199
|
+
|
|
200
|
+
smtp_client.get_client(
|
|
201
|
+
server,
|
|
202
|
+
(client) => {
|
|
203
|
+
client
|
|
204
|
+
.on('greeting', (command) => {
|
|
205
|
+
client.send_command('HELO', 'haraka.local')
|
|
215
206
|
})
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
207
|
+
.on('helo', () => {
|
|
208
|
+
client.send_command('MAIL', 'FROM:<test@haraka.local>')
|
|
209
|
+
})
|
|
210
|
+
.on('mail', () => {
|
|
211
|
+
client.send_command('RCPT', 'TO:<nobody-will-see-this@haraka.local>')
|
|
212
|
+
})
|
|
213
|
+
.on('rcpt', () => {
|
|
214
|
+
client.send_command('DATA')
|
|
215
|
+
})
|
|
216
|
+
.on('data', () => {
|
|
217
|
+
const message_stream = new message.stream({ main: { spool_after: 1024 } }, 'theMessageId')
|
|
218
|
+
|
|
219
|
+
message_stream.on('end', () => {
|
|
220
|
+
client.socket.write('.\r\n')
|
|
221
|
+
})
|
|
222
|
+
message_stream.add_line('Header: test\r\n')
|
|
223
|
+
message_stream.add_line('\r\n')
|
|
224
|
+
message_stream.add_line('I am body text\r\n')
|
|
225
|
+
message_stream.add_line_end()
|
|
226
|
+
|
|
227
|
+
client.start_data(message_stream)
|
|
228
|
+
})
|
|
229
|
+
.on('dot', () => {
|
|
230
|
+
assert.ok(1)
|
|
231
|
+
client.release()
|
|
232
|
+
})
|
|
233
|
+
.on('bad_code', (code, msg) => {
|
|
234
|
+
client.release()
|
|
235
|
+
})
|
|
236
|
+
},
|
|
237
|
+
{ port: 2500, host: 'localhost', cfg },
|
|
238
|
+
)
|
|
232
239
|
})
|
|
233
240
|
})
|
|
234
241
|
|
|
@@ -240,153 +247,158 @@ describe('server', () => {
|
|
|
240
247
|
afterEach(_tearDownServer)
|
|
241
248
|
|
|
242
249
|
it('accepts SMTP message', (done) => {
|
|
243
|
-
|
|
244
|
-
const nodemailer = require('nodemailer');
|
|
250
|
+
const nodemailer = require('nodemailer')
|
|
245
251
|
const transporter = nodemailer.createTransport({
|
|
246
252
|
host: '127.0.0.1',
|
|
247
253
|
port: 2503,
|
|
248
254
|
tls: {
|
|
249
255
|
// do not fail on invalid certs
|
|
250
|
-
rejectUnauthorized: false
|
|
251
|
-
}
|
|
252
|
-
});
|
|
253
|
-
transporter.sendMail({
|
|
254
|
-
from: '"Testalicious Matt" <harakamail@gmail.com>',
|
|
255
|
-
to: 'nobody-will-see-this@haraka.local',
|
|
256
|
-
envelope: {
|
|
257
|
-
from: 'Haraka Test <test@haraka.local>',
|
|
258
|
-
to: 'Discard Queue <discard@haraka.local>',
|
|
256
|
+
rejectUnauthorized: false,
|
|
259
257
|
},
|
|
260
|
-
subject: 'Hello ✔',
|
|
261
|
-
text: 'Hello world ?',
|
|
262
|
-
html: '<b>Hello world ?</b>',
|
|
263
|
-
},
|
|
264
|
-
(error, info) => {
|
|
265
|
-
if (error){
|
|
266
|
-
console.log(error);
|
|
267
|
-
return;
|
|
268
|
-
}
|
|
269
|
-
assert.deepEqual(info.accepted, [ 'discard@haraka.local' ]);
|
|
270
|
-
console.log(`Message sent: ${info.response}`);
|
|
271
|
-
done()
|
|
272
258
|
})
|
|
259
|
+
transporter.sendMail(
|
|
260
|
+
{
|
|
261
|
+
from: '"Testalicious Matt" <harakamail@gmail.com>',
|
|
262
|
+
to: 'nobody-will-see-this@haraka.local',
|
|
263
|
+
envelope: {
|
|
264
|
+
from: 'Haraka Test <test@haraka.local>',
|
|
265
|
+
to: 'Discard Queue <discard@haraka.local>',
|
|
266
|
+
},
|
|
267
|
+
subject: 'Hello ✔',
|
|
268
|
+
text: 'Hello world ?',
|
|
269
|
+
html: '<b>Hello world ?</b>',
|
|
270
|
+
},
|
|
271
|
+
(error, info) => {
|
|
272
|
+
if (error) {
|
|
273
|
+
console.log(error)
|
|
274
|
+
return
|
|
275
|
+
}
|
|
276
|
+
assert.deepEqual(info.accepted, ['discard@haraka.local'])
|
|
277
|
+
console.log(`Message sent: ${info.response}`)
|
|
278
|
+
done()
|
|
279
|
+
},
|
|
280
|
+
)
|
|
273
281
|
})
|
|
274
282
|
|
|
275
283
|
it('accepts authenticated SMTP', (done) => {
|
|
276
|
-
|
|
277
|
-
const nodemailer = require('nodemailer');
|
|
284
|
+
const nodemailer = require('nodemailer')
|
|
278
285
|
const transporter = nodemailer.createTransport({
|
|
279
286
|
host: '127.0.0.1',
|
|
280
287
|
port: 2503,
|
|
281
288
|
auth: {
|
|
282
289
|
user: 'matt',
|
|
283
|
-
pass: 'goodPass'
|
|
290
|
+
pass: 'goodPass',
|
|
284
291
|
},
|
|
285
292
|
requireTLS: true,
|
|
286
293
|
tls: {
|
|
287
294
|
// do not fail on invalid certs
|
|
288
|
-
rejectUnauthorized: false
|
|
289
|
-
}
|
|
295
|
+
rejectUnauthorized: false,
|
|
296
|
+
},
|
|
290
297
|
})
|
|
291
298
|
|
|
292
|
-
transporter.sendMail(
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
299
|
+
transporter.sendMail(
|
|
300
|
+
{
|
|
301
|
+
from: '"Testalicious Matt" <harakamail@gmail.com>',
|
|
302
|
+
to: 'nobody-will-see-this@haraka.local',
|
|
303
|
+
envelope: {
|
|
304
|
+
from: 'Haraka Test <test@haraka.local>',
|
|
305
|
+
to: 'Discard Queue <discard@haraka.local>',
|
|
306
|
+
},
|
|
307
|
+
subject: 'Hello ✔',
|
|
308
|
+
text: 'Hello world ?',
|
|
309
|
+
html: '<b>Hello world ?</b>',
|
|
298
310
|
},
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
console.log(
|
|
306
|
-
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
console.log(`Message sent: ${info.response}`);
|
|
310
|
-
done()
|
|
311
|
-
})
|
|
311
|
+
(error, info) => {
|
|
312
|
+
if (error) {
|
|
313
|
+
console.log(error)
|
|
314
|
+
return
|
|
315
|
+
}
|
|
316
|
+
assert.deepEqual(info.accepted, ['discard@haraka.local'])
|
|
317
|
+
console.log(`Message sent: ${info.response}`)
|
|
318
|
+
done()
|
|
319
|
+
},
|
|
320
|
+
)
|
|
312
321
|
})
|
|
313
322
|
|
|
314
323
|
it('rejects invalid auth', (done) => {
|
|
315
|
-
|
|
316
|
-
const nodemailer = require('nodemailer');
|
|
324
|
+
const nodemailer = require('nodemailer')
|
|
317
325
|
const transporter = nodemailer.createTransport({
|
|
318
326
|
host: '127.0.0.1',
|
|
319
327
|
port: 2503,
|
|
320
328
|
auth: {
|
|
321
329
|
user: 'matt',
|
|
322
|
-
pass: 'badPass'
|
|
330
|
+
pass: 'badPass',
|
|
323
331
|
},
|
|
324
332
|
tls: {
|
|
325
333
|
// do not fail on invalid certs
|
|
326
|
-
rejectUnauthorized: false
|
|
327
|
-
}
|
|
334
|
+
rejectUnauthorized: false,
|
|
335
|
+
},
|
|
328
336
|
})
|
|
329
337
|
|
|
330
|
-
transporter.sendMail(
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
338
|
+
transporter.sendMail(
|
|
339
|
+
{
|
|
340
|
+
from: '"Testalicious Matt" <harakamail@gmail.com>',
|
|
341
|
+
to: 'nobody-will-see-this@haraka.local',
|
|
342
|
+
envelope: {
|
|
343
|
+
from: 'Haraka Test <test@haraka.local>',
|
|
344
|
+
to: 'Discard Queue <discard@haraka.local>',
|
|
345
|
+
},
|
|
346
|
+
subject: 'Hello ✔',
|
|
347
|
+
text: 'Hello world ?',
|
|
348
|
+
html: '<b>Hello world ?</b>',
|
|
336
349
|
},
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
console.log(info.response);
|
|
348
|
-
done()
|
|
349
|
-
})
|
|
350
|
+
(error, info) => {
|
|
351
|
+
if (error) {
|
|
352
|
+
assert.equal(error.code, 'EAUTH')
|
|
353
|
+
// console.log(error);
|
|
354
|
+
return done()
|
|
355
|
+
}
|
|
356
|
+
console.log(info.response)
|
|
357
|
+
done()
|
|
358
|
+
},
|
|
359
|
+
)
|
|
350
360
|
})
|
|
351
361
|
|
|
352
362
|
it('DKIM validates signed message', (done) => {
|
|
353
|
-
|
|
354
|
-
const nodemailer = require('nodemailer');
|
|
363
|
+
const nodemailer = require('nodemailer')
|
|
355
364
|
const transporter = nodemailer.createTransport({
|
|
356
365
|
host: '127.0.0.1',
|
|
357
366
|
port: 2503,
|
|
358
367
|
tls: {
|
|
359
368
|
// do not fail on invalid certs
|
|
360
|
-
rejectUnauthorized: false
|
|
361
|
-
}
|
|
369
|
+
rejectUnauthorized: false,
|
|
370
|
+
},
|
|
362
371
|
})
|
|
363
372
|
|
|
364
|
-
transporter.sendMail(
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
373
|
+
transporter.sendMail(
|
|
374
|
+
{
|
|
375
|
+
from: '"Testalicious Matt" <harakamail@gmail.com>',
|
|
376
|
+
to: 'nobody-will-see-this@haraka.local',
|
|
377
|
+
envelope: {
|
|
378
|
+
from: 'Haraka Test <test@haraka.local>',
|
|
379
|
+
to: 'Discard Queue <discard@haraka.local>',
|
|
380
|
+
},
|
|
381
|
+
subject: 'Hello ✔',
|
|
382
|
+
text: 'Hello world ?',
|
|
383
|
+
html: '<b>Hello world ?</b>',
|
|
384
|
+
dkim: {
|
|
385
|
+
domainName: 'test.simerson.com',
|
|
386
|
+
keySelector: 'harakatest2017',
|
|
387
|
+
privateKey:
|
|
388
|
+
'-----BEGIN RSA PRIVATE KEY-----\nMIIEpAIBAAKCAQEAxqoUAnQ9GB3iNnkS7coj0Iggd0nyryW062tpK95NC5UXmmAwIpUMfkYdiHY2o2duWYGF0Bp237M/QXKhJYTXfsgkwP/bq9OGWtRZxHPHhbhdjbiI\nqObi6zvYcxrI77gpWDDvruhMeS9Hwa1R99pLUWd4PsuYTzbV/jwu2pz+XZXXXNEU\nVxzDAAj0yF7mwxHMLzQfR+hdhWcrgN0stUP0o7hm7hoOP8IWgcSW3JiQYavIKoI4\nm4+I9I1LzDJN2rHVnQvmjUrqqpG7X6SyFVFtuTWGaMqf1Cj/t8eSvU9VdgLFllS8\ntThqUZHq5S5hm8M8VzLuQLG9U0dtFolcFmJkbQIDAQABAoIBAB4fUbNhjpXmihM6\nXm1htfZ7fXi45Kw76me7vJGjPklgTNjidsn3kZJf7UBwtC4ok6nMos6ABMA8fH3e\n9KIst0QI8tG0ucke5INHKWlJKNqUrtK7RTVe9M84HsStLgRzBwnRObZqkJXbXmT2\nc7RCDCOGrcvPsQNpzB6lX3FUVpk3x24RXpQV1qSgH8yuHSPc1C6rssXwPAgnESfS\nK3MHRx2CLZvTTkq/YCsT+wS/O9RWPCVOYuWaa5DDDAIp3Yw1wYq9Upoh0BdIFC3U\nWm+5Cr3o9wxcvS6+W2RA6I51eymzvCU5ZakWt/bnUDb6/ByxsWOn5rL4WfPpCwE4\nnuC72v0CgYEA9imEq6a0GoaEsMoR7cxT7uXKimQH+Jaq3CGkuh0iN32F4FXhuUKz\nLYKSLCZzpb1MiDJv6BBchV6uSQ6ATo1cZ8WzYQISikk175bf0SPom591OZElvKA2\nSOrTrXtbl33YbWZEgyEcpTgelVi5ys9rj4eKkMvM0lwRmW6gctEFXRcCgYEAzpqc\nR/wqPjgPhpF1CZtdEwOZg4kkOig8CBcuQ7o/hDG7N69A9ZbeJO8eD+gKDrHRfkYr\nTH/UdkZGjilBk/lxnpIZpyBLxQ6UdhNPuwtxXKAvuSN+aQ0pdJn8tg03OSj2OzTK\nJ4hMsO/wt1xM8EDRobLZEosMadaYZUHzx8VU5RsCgYEAvFZbuXEcT0cocpLIUOaK\nOTf7VRLfvmSYaUAcZoEv0sDpExDiWPodWO6To8/vn5lL2tCsKiOKhkhAlIjRxkgF\nsSfj7I7HXKJS7/LBX6RXrem8qMTS2JTDs9pnBk5hb3DLjDg4pxNIdWiQjbeKvw8f\nvnr3m30yQqhKlte7Tt15exUCgYBzq7RbyR6Nfy2SFdYE7usJPjawohOaS/RwQyov\n2RK+nGlJH+GqnjD5VLbsCOm4mG3F2NtdFSSKo4XVCdwhUMMAGKQsIbTKOwN7qAw3\nmIx7Y2PUr76SakAPfDc0ZenJItnZBBE6WOE3Ht8Siaa5zFCRy2QlMZxdlTv1VRt7\neUuyiQKBgQDdXJO5+3h1HPxbYZcmNm/2CJUNw2ehU8vCiBXCcWPn7JukayHx+TXy\nyj0j/b1SvmKgjB+4JWluiqIU+QBjRjvb397QY1YoCEaGZd0zdFjTZwQksQ5AFst9\nCiD9OFXe/kkmIUQQra6aw1CoppyAfvAblp8uevLWb57xU3VUB3xeGg==\n-----END RSA PRIVATE KEY-----\n',
|
|
389
|
+
},
|
|
370
390
|
},
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
if (error){
|
|
383
|
-
console.log(error);
|
|
384
|
-
return;
|
|
385
|
-
}
|
|
386
|
-
assert.deepEqual(info.accepted, [ 'discard@haraka.local' ]);
|
|
387
|
-
console.log(`Message sent: ${info.response}`);
|
|
388
|
-
done()
|
|
389
|
-
})
|
|
391
|
+
(error, info) => {
|
|
392
|
+
// console.log(info);
|
|
393
|
+
if (error) {
|
|
394
|
+
console.log(error)
|
|
395
|
+
return
|
|
396
|
+
}
|
|
397
|
+
assert.deepEqual(info.accepted, ['discard@haraka.local'])
|
|
398
|
+
console.log(`Message sent: ${info.response}`)
|
|
399
|
+
done()
|
|
400
|
+
},
|
|
401
|
+
)
|
|
390
402
|
})
|
|
391
403
|
})
|
|
392
404
|
|
|
@@ -398,47 +410,52 @@ describe('server', () => {
|
|
|
398
410
|
afterEach(_tearDownServer)
|
|
399
411
|
|
|
400
412
|
it('rejects non-validated SMTPS connection', (done) => {
|
|
401
|
-
|
|
402
|
-
const nodemailer = require('nodemailer');
|
|
413
|
+
const nodemailer = require('nodemailer')
|
|
403
414
|
const transporter = nodemailer.createTransport({
|
|
404
415
|
host: '127.0.0.1',
|
|
405
416
|
port: 2465,
|
|
406
417
|
secure: true,
|
|
407
418
|
tls: {
|
|
408
419
|
// do not fail on invalid certs
|
|
409
|
-
rejectUnauthorized: false
|
|
410
|
-
}
|
|
420
|
+
rejectUnauthorized: false,
|
|
421
|
+
},
|
|
411
422
|
})
|
|
412
423
|
|
|
413
424
|
// give the SMTPS listener a second to start listening
|
|
414
425
|
setTimeout(() => {
|
|
415
|
-
transporter.sendMail(
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
426
|
+
transporter.sendMail(
|
|
427
|
+
{
|
|
428
|
+
from: '"Testalicious Matt" <harakamail@gmail.com>',
|
|
429
|
+
to: 'nobody-will-see-this@haraka.local',
|
|
430
|
+
envelope: {
|
|
431
|
+
from: 'Haraka Test <test@haraka.local>',
|
|
432
|
+
to: 'Discard Queue <discard@haraka.local>',
|
|
433
|
+
},
|
|
434
|
+
subject: 'Hello ✔',
|
|
435
|
+
text: 'Hello world ?',
|
|
436
|
+
html: '<b>Hello world ?</b>',
|
|
421
437
|
},
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
438
|
+
(error, info) => {
|
|
439
|
+
if (error) {
|
|
440
|
+
// console.log(error);
|
|
441
|
+
if (error.message === 'socket hang up') {
|
|
442
|
+
// node 6 & 8
|
|
443
|
+
assert.equal(error.message, 'socket hang up')
|
|
444
|
+
} else if (/alert certificate required/.test(error.message)) {
|
|
445
|
+
// node 18
|
|
446
|
+
assert.ok(/alert certificate required/.test(error.message))
|
|
447
|
+
} else {
|
|
448
|
+
// node 10+
|
|
449
|
+
assert.equal(
|
|
450
|
+
error.message,
|
|
451
|
+
'Client network socket disconnected before secure TLS connection was established',
|
|
452
|
+
)
|
|
453
|
+
}
|
|
434
454
|
}
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
done()
|
|
440
|
-
})
|
|
441
|
-
}, 500);
|
|
455
|
+
done()
|
|
456
|
+
},
|
|
457
|
+
)
|
|
458
|
+
}, 500)
|
|
442
459
|
})
|
|
443
460
|
})
|
|
444
461
|
|
|
@@ -448,44 +465,48 @@ describe('server', () => {
|
|
|
448
465
|
})
|
|
449
466
|
|
|
450
467
|
it('rejects non-validated STARTTLS connection', (done) => {
|
|
451
|
-
|
|
452
|
-
const nodemailer = require('nodemailer');
|
|
468
|
+
const nodemailer = require('nodemailer')
|
|
453
469
|
const transporter = nodemailer.createTransport({
|
|
454
470
|
host: '127.0.0.1',
|
|
455
471
|
port: 2587,
|
|
456
472
|
secure: false,
|
|
457
473
|
tls: {
|
|
458
474
|
// do not fail on invalid certs
|
|
459
|
-
rejectUnauthorized: false
|
|
460
|
-
}
|
|
461
|
-
})
|
|
475
|
+
rejectUnauthorized: false,
|
|
476
|
+
},
|
|
477
|
+
})
|
|
462
478
|
|
|
463
479
|
// give the SMTPS listener a half second to start listening
|
|
464
480
|
setTimeout(() => {
|
|
465
|
-
transporter.sendMail(
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
481
|
+
transporter.sendMail(
|
|
482
|
+
{
|
|
483
|
+
from: '"Testalicious Matt" <harakamail@gmail.com>',
|
|
484
|
+
to: 'nobody-will-see-this@haraka.local',
|
|
485
|
+
envelope: {
|
|
486
|
+
from: 'Haraka Test <test@haraka.local>',
|
|
487
|
+
to: 'Discard Queue <discard@haraka.local>',
|
|
488
|
+
},
|
|
489
|
+
subject: 'Hello ✔',
|
|
490
|
+
text: 'Hello world ?',
|
|
491
|
+
html: '<b>Hello world ?</b>',
|
|
471
492
|
},
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
493
|
+
(error, info) => {
|
|
494
|
+
if (error) {
|
|
495
|
+
// console.log(error);
|
|
496
|
+
if (/alert certificate required/.test(error.message)) {
|
|
497
|
+
// node 18
|
|
498
|
+
assert.ok(/alert certificate required/.test(error.message))
|
|
499
|
+
} else {
|
|
500
|
+
assert.equal(
|
|
501
|
+
error.message,
|
|
502
|
+
'Client network socket disconnected before secure TLS connection was established',
|
|
503
|
+
)
|
|
504
|
+
}
|
|
484
505
|
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
}, 500)
|
|
506
|
+
done()
|
|
507
|
+
},
|
|
508
|
+
)
|
|
509
|
+
}, 500)
|
|
489
510
|
})
|
|
490
511
|
})
|
|
491
512
|
})
|