Haraka 3.1.4 → 3.1.6
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 +1 -1
- package/{Changes.md → CHANGELOG.md} +34 -0
- package/CONTRIBUTORS.md +26 -26
- package/README.md +68 -93
- package/SECURITY.md +178 -0
- package/bin/haraka +7 -14
- package/config/plugins +0 -3
- package/docs/Connection.md +126 -39
- package/docs/CoreConfig.md +92 -74
- package/docs/HAProxy.md +41 -25
- package/docs/Logging.md +68 -38
- package/docs/Outbound.md +124 -179
- package/docs/Plugins.md +38 -59
- package/docs/Transaction.md +78 -83
- package/docs/Tutorial.md +122 -209
- package/docs/plugins/aliases.md +1 -141
- package/docs/plugins/auth/auth_ldap.md +2 -39
- package/docs/plugins/max_unrecognized_commands.md +4 -18
- package/docs/plugins/process_title.md +3 -3
- package/docs/plugins/reseed_rng.md +11 -13
- package/docs/plugins/tls.md +7 -7
- package/docs/plugins/toobusy.md +10 -4
- package/docs/tutorials/SettingUpOutbound.md +40 -48
- package/endpoint.js +32 -2
- package/outbound/hmail.js +3 -2
- package/outbound/index.js +3 -0
- package/package.json +21 -34
- package/plugins/queue/smtp_forward.js +4 -4
- package/run_tests +3 -15
- package/server.js +17 -7
- package/smtp_client.js +8 -6
- package/test/connection.js +234 -0
- package/test/endpoint.js +32 -4
- package/test/host_pool.js +57 -31
- package/test/logger.js +75 -135
- package/test/outbound/bounce_net_errors.js +87 -131
- package/test/outbound/bounce_rfc3464.js +177 -254
- package/test/outbound/hmail.js +19 -0
- package/test/outbound/index.js +189 -0
- package/test/outbound/queue.js +92 -0
- package/test/plugins/auth/auth_base.js +39 -44
- package/test/plugins/auth/auth_vpopmaild.js +8 -9
- package/test/plugins/queue/smtp_forward.js +953 -183
- package/test/plugins/rcpt_to.host_list_base.js +58 -93
- package/test/plugins/rcpt_to.in_host_list.js +126 -175
- package/test/plugins/record_envelope_addresses.js +8 -8
- package/test/plugins/status.js +10 -10
- package/test/plugins/tls.js +9 -19
- package/test/plugins/xclient.js +75 -110
- package/test/plugins.js +10 -13
- package/test/rfc1869.js +50 -70
- package/test/server.js +438 -421
- package/test/smtp_client.js +1192 -218
- package/test/tls_socket.js +242 -0
- package/tls_socket.js +18 -22
package/test/outbound/index.js
CHANGED
|
@@ -152,6 +152,195 @@ describe('outbound', () => {
|
|
|
152
152
|
})
|
|
153
153
|
assert.ok(true)
|
|
154
154
|
})
|
|
155
|
+
|
|
156
|
+
it('waits for drain when stream backpressure is applied', async () => {
|
|
157
|
+
const todo = {
|
|
158
|
+
queue_time: Date.now(),
|
|
159
|
+
domain: 'example.com',
|
|
160
|
+
rcpt_to: [],
|
|
161
|
+
mail_from: {},
|
|
162
|
+
notes: {},
|
|
163
|
+
uuid: 'u1',
|
|
164
|
+
}
|
|
165
|
+
let drained = false
|
|
166
|
+
|
|
167
|
+
await new Promise((resolve) => {
|
|
168
|
+
const ws = {
|
|
169
|
+
write() {
|
|
170
|
+
return false
|
|
171
|
+
},
|
|
172
|
+
once(event, cb) {
|
|
173
|
+
assert.equal(event, 'drain')
|
|
174
|
+
setImmediate(() => {
|
|
175
|
+
drained = true
|
|
176
|
+
cb()
|
|
177
|
+
resolve()
|
|
178
|
+
})
|
|
179
|
+
},
|
|
180
|
+
}
|
|
181
|
+
outbound.build_todo(todo, ws, () => {})
|
|
182
|
+
})
|
|
183
|
+
|
|
184
|
+
assert.equal(drained, true)
|
|
185
|
+
})
|
|
186
|
+
})
|
|
187
|
+
|
|
188
|
+
describe('send_trans_email', () => {
|
|
189
|
+
const queueDir = path.resolve('test', 'test-queue')
|
|
190
|
+
|
|
191
|
+
beforeEach(() => {
|
|
192
|
+
process.env.HARAKA_TEST_DIR = path.resolve('test')
|
|
193
|
+
fs.mkdirSync(queueDir, { recursive: true })
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
afterEach(() => {
|
|
197
|
+
delete process.env.HARAKA_TEST_DIR
|
|
198
|
+
try {
|
|
199
|
+
for (const f of fs.readdirSync(queueDir)) {
|
|
200
|
+
fs.unlinkSync(path.join(queueDir, f))
|
|
201
|
+
}
|
|
202
|
+
} catch (ignore) {}
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
// Regression test for haraka/Haraka#3551:
|
|
206
|
+
// When dkim_verify (data_post) pipes the message_stream and DKIMVerifyStream
|
|
207
|
+
// fires its callback early via process.nextTick (no DKIM-Signature found),
|
|
208
|
+
// the chain runs synchronously into process_delivery → pipe() while the
|
|
209
|
+
// first pipe is still in flight. pre_send_trans_email_respond must yield
|
|
210
|
+
// (via setImmediate) before opening a new pipe.
|
|
211
|
+
it('yields to setImmediate before opening process_delivery pipes', async () => {
|
|
212
|
+
const stream = require('node:stream')
|
|
213
|
+
const Transaction = require('../../transaction')
|
|
214
|
+
const Address = require('address-rfc2821').Address
|
|
215
|
+
const outbound = require('../../outbound')
|
|
216
|
+
const plugins = require('../../plugins')
|
|
217
|
+
|
|
218
|
+
const txn = Transaction.createTransaction()
|
|
219
|
+
const origRunHooks = plugins.run_hooks
|
|
220
|
+
try {
|
|
221
|
+
txn.mail_from = new Address('<from@example.com>')
|
|
222
|
+
txn.rcpt_to = [new Address('<to@example.com>')]
|
|
223
|
+
txn.message_stream.add_line(Buffer.from('From: from@example.com\r\n'))
|
|
224
|
+
txn.message_stream.add_line(Buffer.from('To: to@example.com\r\n'))
|
|
225
|
+
txn.message_stream.add_line(Buffer.from('\r\n'))
|
|
226
|
+
txn.message_stream.add_line(Buffer.from('body\r\n'))
|
|
227
|
+
await new Promise((r) => txn.message_stream.add_line_end(r))
|
|
228
|
+
|
|
229
|
+
// Start a pipe on the message_stream and fire a synchronous callback
|
|
230
|
+
// before it drains — this models what dkim_verify does.
|
|
231
|
+
const verifierFiredCb = new Promise((resolve) => {
|
|
232
|
+
let scheduled = false
|
|
233
|
+
const verifier = new stream.Writable({
|
|
234
|
+
write(_chunk, _enc, cb) {
|
|
235
|
+
if (!scheduled) {
|
|
236
|
+
scheduled = true
|
|
237
|
+
process.nextTick(resolve)
|
|
238
|
+
}
|
|
239
|
+
cb()
|
|
240
|
+
},
|
|
241
|
+
})
|
|
242
|
+
txn.message_stream.pipe(verifier)
|
|
243
|
+
})
|
|
244
|
+
await verifierFiredCb
|
|
245
|
+
|
|
246
|
+
// Now invoke send_trans_email — its pre_send_trans_email_respond
|
|
247
|
+
// should yield (await setImmediate) before calling process_delivery,
|
|
248
|
+
// letting the verifier pipe drain so the new pipe can succeed.
|
|
249
|
+
await new Promise((resolve, reject) => {
|
|
250
|
+
// Stub the heavy bits: we only care that the chain doesn't throw
|
|
251
|
+
// "Cannot pipe while currently piping" before queuing happens.
|
|
252
|
+
plugins.run_hooks = (hook, obj) => {
|
|
253
|
+
if (hook === 'pre_send_trans_email') {
|
|
254
|
+
// Mimic empty-hook synchronous callback (no plugins)
|
|
255
|
+
obj.pre_send_trans_email_respond(constants.cont).catch(reject)
|
|
256
|
+
} else {
|
|
257
|
+
origRunHooks.call(plugins, hook, obj)
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
outbound.send_trans_email(txn, (retval) => {
|
|
262
|
+
if (retval === constants.ok) resolve()
|
|
263
|
+
else reject(new Error(`unexpected retval ${retval}`))
|
|
264
|
+
})
|
|
265
|
+
})
|
|
266
|
+
} finally {
|
|
267
|
+
plugins.run_hooks = origRunHooks
|
|
268
|
+
txn.message_stream.destroy()
|
|
269
|
+
}
|
|
270
|
+
})
|
|
271
|
+
|
|
272
|
+
it('adds missing Message-Id/Date and prepends Received before queueing', async () => {
|
|
273
|
+
process.env.HARAKA_TEST_DIR = path.resolve('test')
|
|
274
|
+
const Address = require('address-rfc2821').Address
|
|
275
|
+
const outbound = require('../../outbound')
|
|
276
|
+
const plugins = require('../../plugins')
|
|
277
|
+
|
|
278
|
+
const added = []
|
|
279
|
+
const leading = []
|
|
280
|
+
const queued = []
|
|
281
|
+
const transaction = {
|
|
282
|
+
uuid: 'txn-add-headers',
|
|
283
|
+
header: {
|
|
284
|
+
get_all(_name) {
|
|
285
|
+
return []
|
|
286
|
+
},
|
|
287
|
+
get() {
|
|
288
|
+
return null
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
rcpt_to: [new Address('<user@example.com>')],
|
|
292
|
+
notes: {},
|
|
293
|
+
add_header(name, value) {
|
|
294
|
+
added.push([name, value])
|
|
295
|
+
},
|
|
296
|
+
remove_header() {},
|
|
297
|
+
add_leading_header(name, value) {
|
|
298
|
+
leading.push([name, value])
|
|
299
|
+
},
|
|
300
|
+
results: {
|
|
301
|
+
add() {},
|
|
302
|
+
},
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
const originalRunHooks = plugins.run_hooks
|
|
306
|
+
const originalProcessDelivery = outbound.process_delivery
|
|
307
|
+
const originalPush = outbound.delivery_queue.push
|
|
308
|
+
outbound.delivery_queue.push = (hmail) => {
|
|
309
|
+
queued.push(hmail)
|
|
310
|
+
}
|
|
311
|
+
outbound.process_delivery = async (_okPaths, _todo, hmails) => {
|
|
312
|
+
hmails.push({ queued: true })
|
|
313
|
+
}
|
|
314
|
+
plugins.run_hooks = (hook, conn) => {
|
|
315
|
+
if (hook === 'pre_send_trans_email') {
|
|
316
|
+
conn.pre_send_trans_email_respond(constants.cont)
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
try {
|
|
321
|
+
const result = await new Promise((resolve) => {
|
|
322
|
+
outbound.send_trans_email(transaction, (retval, msg) => resolve({ retval, msg }))
|
|
323
|
+
})
|
|
324
|
+
|
|
325
|
+
assert.equal(result.retval, constants.ok)
|
|
326
|
+
assert.match(result.msg, /Message Queued/)
|
|
327
|
+
assert.equal(queued.length, 1)
|
|
328
|
+
assert.equal(
|
|
329
|
+
added.some(([name]) => name === 'Message-Id'),
|
|
330
|
+
true,
|
|
331
|
+
)
|
|
332
|
+
assert.equal(
|
|
333
|
+
added.some(([name]) => name === 'Date'),
|
|
334
|
+
true,
|
|
335
|
+
)
|
|
336
|
+
assert.equal(leading[0][0], 'Received')
|
|
337
|
+
} finally {
|
|
338
|
+
plugins.run_hooks = originalRunHooks
|
|
339
|
+
outbound.process_delivery = originalProcessDelivery
|
|
340
|
+
outbound.delivery_queue.push = originalPush
|
|
341
|
+
delete process.env.HARAKA_TEST_DIR
|
|
342
|
+
}
|
|
343
|
+
})
|
|
155
344
|
})
|
|
156
345
|
|
|
157
346
|
describe('timer_queue', () => {
|
package/test/outbound/queue.js
CHANGED
|
@@ -230,4 +230,96 @@ describe('outbound/queue', () => {
|
|
|
230
230
|
}
|
|
231
231
|
})
|
|
232
232
|
})
|
|
233
|
+
|
|
234
|
+
describe('queue maintenance', () => {
|
|
235
|
+
it('delete_dot_files removes leftover dot files only', async () => {
|
|
236
|
+
const tmpDir = path.join(os.tmpdir(), `haraka-dot-clean-${Date.now()}`)
|
|
237
|
+
fs.mkdirSync(tmpDir, { recursive: true })
|
|
238
|
+
const dotName = `${qfile.platformDOT}leftover`
|
|
239
|
+
const normalName = 'keep-me'
|
|
240
|
+
fs.writeFileSync(path.join(tmpDir, dotName), 'x')
|
|
241
|
+
fs.writeFileSync(path.join(tmpDir, normalName), 'x')
|
|
242
|
+
|
|
243
|
+
const originalQueueDir = queue.queue_dir
|
|
244
|
+
queue.queue_dir = tmpDir
|
|
245
|
+
try {
|
|
246
|
+
await queue.delete_dot_files()
|
|
247
|
+
assert.equal(fs.existsSync(path.join(tmpDir, dotName)), false)
|
|
248
|
+
assert.equal(fs.existsSync(path.join(tmpDir, normalName)), true)
|
|
249
|
+
} finally {
|
|
250
|
+
queue.queue_dir = originalQueueDir
|
|
251
|
+
fs.rmSync(tmpDir, { recursive: true, force: true })
|
|
252
|
+
}
|
|
253
|
+
})
|
|
254
|
+
|
|
255
|
+
it('_add_hmail pushes immediate items and schedules delayed ones', () => {
|
|
256
|
+
const originalPush = queue.delivery_queue.push
|
|
257
|
+
const originalAdd = queue.temp_fail_queue.add
|
|
258
|
+
const pushed = []
|
|
259
|
+
const delayed = []
|
|
260
|
+
let delayedCb
|
|
261
|
+
|
|
262
|
+
queue.delivery_queue.push = (item) => pushed.push(item)
|
|
263
|
+
queue.temp_fail_queue.add = (id, ms, cb) => {
|
|
264
|
+
delayed.push([id, ms])
|
|
265
|
+
delayedCb = cb
|
|
266
|
+
}
|
|
267
|
+
queue.cur_time = new Date()
|
|
268
|
+
|
|
269
|
+
const immediate = { filename: 'a', next_process: queue.cur_time - 1 }
|
|
270
|
+
const future = { filename: 'b', next_process: queue.cur_time.getTime() + 1000 }
|
|
271
|
+
|
|
272
|
+
try {
|
|
273
|
+
queue._add_hmail(immediate)
|
|
274
|
+
queue._add_hmail(future)
|
|
275
|
+
assert.equal(pushed.length, 1)
|
|
276
|
+
assert.equal(delayed.length, 1)
|
|
277
|
+
assert.equal(delayed[0][0], 'b')
|
|
278
|
+
delayedCb()
|
|
279
|
+
assert.equal(pushed.length, 2)
|
|
280
|
+
} finally {
|
|
281
|
+
queue.delivery_queue.push = originalPush
|
|
282
|
+
queue.temp_fail_queue.add = originalAdd
|
|
283
|
+
}
|
|
284
|
+
})
|
|
285
|
+
|
|
286
|
+
it('scan_queue_pids returns unique pids from queue files', async () => {
|
|
287
|
+
populateTestQueue()
|
|
288
|
+
const originalQueueDir = queue.queue_dir
|
|
289
|
+
queue.queue_dir = testQueueDir
|
|
290
|
+
|
|
291
|
+
try {
|
|
292
|
+
const pids = await queue.scan_queue_pids()
|
|
293
|
+
assert.ok(Array.isArray(pids))
|
|
294
|
+
assert.equal(pids.length >= 1, true)
|
|
295
|
+
} finally {
|
|
296
|
+
queue.queue_dir = originalQueueDir
|
|
297
|
+
clearTestQueue()
|
|
298
|
+
}
|
|
299
|
+
})
|
|
300
|
+
|
|
301
|
+
it('scan_queue_pids throws when queue dir cannot be read', async () => {
|
|
302
|
+
const originalQueueDir = queue.queue_dir
|
|
303
|
+
const badPath = path.join(os.tmpdir(), `queue-not-dir-${Date.now()}`)
|
|
304
|
+
fs.writeFileSync(badPath, 'x')
|
|
305
|
+
queue.queue_dir = badPath
|
|
306
|
+
try {
|
|
307
|
+
await assert.rejects(() => queue.scan_queue_pids())
|
|
308
|
+
} finally {
|
|
309
|
+
queue.queue_dir = originalQueueDir
|
|
310
|
+
fs.rmSync(badPath, { force: true })
|
|
311
|
+
}
|
|
312
|
+
})
|
|
313
|
+
|
|
314
|
+
it('delete_dot_files handles readdir errors without throwing', async () => {
|
|
315
|
+
const originalQueueDir = queue.queue_dir
|
|
316
|
+
queue.queue_dir = path.join(os.tmpdir(), `missing-dot-${Date.now()}`)
|
|
317
|
+
try {
|
|
318
|
+
await queue.delete_dot_files()
|
|
319
|
+
assert.ok(true)
|
|
320
|
+
} finally {
|
|
321
|
+
queue.queue_dir = originalQueueDir
|
|
322
|
+
}
|
|
323
|
+
})
|
|
324
|
+
})
|
|
233
325
|
})
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
'use strict'
|
|
2
2
|
const assert = require('node:assert')
|
|
3
|
+
const { describe, it, beforeEach } = require('node:test')
|
|
3
4
|
|
|
4
5
|
const { Address } = require('address-rfc2821')
|
|
5
6
|
const fixtures = require('haraka-test-fixtures')
|
|
6
7
|
const utils = require('haraka-utils')
|
|
7
8
|
|
|
8
|
-
const _set_up = (
|
|
9
|
+
const _set_up = () => {
|
|
9
10
|
this.plugin = new fixtures.plugin('auth/auth_base')
|
|
10
11
|
|
|
11
12
|
this.plugin.get_plain_passwd = (user, cb) => {
|
|
@@ -15,11 +16,9 @@ const _set_up = (done) => {
|
|
|
15
16
|
|
|
16
17
|
this.connection = fixtures.connection.createConnection()
|
|
17
18
|
this.connection.capabilities = null
|
|
18
|
-
|
|
19
|
-
done()
|
|
20
19
|
}
|
|
21
20
|
|
|
22
|
-
const _set_up_2 = (
|
|
21
|
+
const _set_up_2 = () => {
|
|
23
22
|
this.plugin = new fixtures.plugin('auth/auth_base')
|
|
24
23
|
|
|
25
24
|
this.plugin.get_plain_passwd = (user, connection, cb) => {
|
|
@@ -30,11 +29,9 @@ const _set_up_2 = (done) => {
|
|
|
30
29
|
|
|
31
30
|
this.connection = fixtures.connection.createConnection()
|
|
32
31
|
this.connection.capabilities = null
|
|
33
|
-
|
|
34
|
-
done()
|
|
35
32
|
}
|
|
36
33
|
|
|
37
|
-
const _set_up_custom_pwcb_opts = (
|
|
34
|
+
const _set_up_custom_pwcb_opts = () => {
|
|
38
35
|
this.plugin = new fixtures.plugin('auth/auth_base')
|
|
39
36
|
|
|
40
37
|
this.plugin.check_plain_passwd = (connection, user, passwd, pwok_cb) => {
|
|
@@ -63,15 +60,13 @@ const _set_up_custom_pwcb_opts = (done) => {
|
|
|
63
60
|
this.connection.notes.resp_strings.push([code, msg])
|
|
64
61
|
return cb()
|
|
65
62
|
}
|
|
66
|
-
|
|
67
|
-
done()
|
|
68
63
|
}
|
|
69
64
|
|
|
70
65
|
describe('auth_base', () => {
|
|
71
66
|
describe('hook_capabilities', () => {
|
|
72
67
|
beforeEach(_set_up)
|
|
73
68
|
|
|
74
|
-
it('no TLS, no auth', (done) => {
|
|
69
|
+
it('no TLS, no auth', (t, done) => {
|
|
75
70
|
this.plugin.hook_capabilities((rc, msg) => {
|
|
76
71
|
assert.equal(undefined, rc)
|
|
77
72
|
assert.equal(undefined, msg)
|
|
@@ -80,7 +75,7 @@ describe('auth_base', () => {
|
|
|
80
75
|
}, this.connection)
|
|
81
76
|
})
|
|
82
77
|
|
|
83
|
-
it('with TLS, auth is offered', (done) => {
|
|
78
|
+
it('with TLS, auth is offered', (t, done) => {
|
|
84
79
|
this.connection.tls.enabled = true
|
|
85
80
|
this.connection.capabilities = []
|
|
86
81
|
this.plugin.hook_capabilities((rc, msg) => {
|
|
@@ -97,13 +92,13 @@ describe('auth_base', () => {
|
|
|
97
92
|
describe('get_plain_passwd', () => {
|
|
98
93
|
beforeEach(_set_up)
|
|
99
94
|
|
|
100
|
-
it('get_plain_passwd, no result', (done) => {
|
|
95
|
+
it('get_plain_passwd, no result', (t, done) => {
|
|
101
96
|
this.plugin.get_plain_passwd('user', (pass) => {
|
|
102
97
|
assert.equal(pass, null)
|
|
103
98
|
done()
|
|
104
99
|
})
|
|
105
100
|
})
|
|
106
|
-
it('get_plain_passwd, test user', (done) => {
|
|
101
|
+
it('get_plain_passwd, test user', (t, done) => {
|
|
107
102
|
this.plugin.get_plain_passwd('test', (pass) => {
|
|
108
103
|
assert.equal(pass, 'testpass')
|
|
109
104
|
done()
|
|
@@ -114,21 +109,21 @@ describe('auth_base', () => {
|
|
|
114
109
|
describe('check_plain_passwd', () => {
|
|
115
110
|
beforeEach(_set_up)
|
|
116
111
|
|
|
117
|
-
it('valid password', (done) => {
|
|
112
|
+
it('valid password', (t, done) => {
|
|
118
113
|
this.plugin.check_plain_passwd(this.connection, 'test', 'testpass', (pass) => {
|
|
119
114
|
assert.equal(pass, true)
|
|
120
115
|
done()
|
|
121
116
|
})
|
|
122
117
|
})
|
|
123
118
|
|
|
124
|
-
it('wrong password', (done) => {
|
|
119
|
+
it('wrong password', (t, done) => {
|
|
125
120
|
this.plugin.check_plain_passwd(this.connection, 'test', 'test1pass', (pass) => {
|
|
126
121
|
assert.equal(pass, false)
|
|
127
122
|
done()
|
|
128
123
|
})
|
|
129
124
|
})
|
|
130
125
|
|
|
131
|
-
it('null password', (done) => {
|
|
126
|
+
it('null password', (t, done) => {
|
|
132
127
|
this.plugin.check_plain_passwd(this.connection, 'test', null, (pass) => {
|
|
133
128
|
assert.equal(pass, false)
|
|
134
129
|
done()
|
|
@@ -139,7 +134,7 @@ describe('auth_base', () => {
|
|
|
139
134
|
describe('select_auth_method', () => {
|
|
140
135
|
beforeEach(_set_up)
|
|
141
136
|
|
|
142
|
-
it('no auth methods yield no result', (done) => {
|
|
137
|
+
it('no auth methods yield no result', (t, done) => {
|
|
143
138
|
this.plugin.select_auth_method(
|
|
144
139
|
(code) => {
|
|
145
140
|
assert.equal(code, null)
|
|
@@ -151,7 +146,7 @@ describe('auth_base', () => {
|
|
|
151
146
|
)
|
|
152
147
|
})
|
|
153
148
|
|
|
154
|
-
it('invalid AUTH method, no result', (done) => {
|
|
149
|
+
it('invalid AUTH method, no result', (t, done) => {
|
|
155
150
|
this.connection.notes.allowed_auth_methods = ['PLAIN', 'LOGIN', 'CRAM-MD5']
|
|
156
151
|
this.plugin.select_auth_method(
|
|
157
152
|
(code) => {
|
|
@@ -164,7 +159,7 @@ describe('auth_base', () => {
|
|
|
164
159
|
)
|
|
165
160
|
})
|
|
166
161
|
|
|
167
|
-
it('valid AUTH method, valid attempt', (done) => {
|
|
162
|
+
it('valid AUTH method, valid attempt', (t, done) => {
|
|
168
163
|
const method = `PLAIN ${utils.base64('discard\0test\0testpass')}`
|
|
169
164
|
this.connection.notes.allowed_auth_methods = ['PLAIN', 'LOGIN']
|
|
170
165
|
this.plugin.select_auth_method(
|
|
@@ -182,7 +177,7 @@ describe('auth_base', () => {
|
|
|
182
177
|
describe('auth_plain', () => {
|
|
183
178
|
beforeEach(_set_up)
|
|
184
179
|
|
|
185
|
-
it('params type=string returns OK', (done) => {
|
|
180
|
+
it('params type=string returns OK', (t, done) => {
|
|
186
181
|
this.plugin.auth_plain(
|
|
187
182
|
(rc) => {
|
|
188
183
|
assert.equal(rc, OK)
|
|
@@ -194,7 +189,7 @@ describe('auth_base', () => {
|
|
|
194
189
|
)
|
|
195
190
|
})
|
|
196
191
|
|
|
197
|
-
it('params type=empty array, returns OK', (done) => {
|
|
192
|
+
it('params type=empty array, returns OK', (t, done) => {
|
|
198
193
|
this.plugin.auth_plain(
|
|
199
194
|
(rc) => {
|
|
200
195
|
assert.equal(rc, OK)
|
|
@@ -206,7 +201,7 @@ describe('auth_base', () => {
|
|
|
206
201
|
)
|
|
207
202
|
})
|
|
208
203
|
|
|
209
|
-
it('params type=array, successful auth', (done) => {
|
|
204
|
+
it('params type=array, successful auth', (t, done) => {
|
|
210
205
|
const method = utils.base64('discard\0test\0testpass')
|
|
211
206
|
this.plugin.auth_plain(
|
|
212
207
|
(rc) => {
|
|
@@ -219,7 +214,7 @@ describe('auth_base', () => {
|
|
|
219
214
|
)
|
|
220
215
|
})
|
|
221
216
|
|
|
222
|
-
it('params type=with two line login', (done) => {
|
|
217
|
+
it('params type=with two line login', (t, done) => {
|
|
223
218
|
this.plugin.auth_plain(
|
|
224
219
|
(rc) => {
|
|
225
220
|
assert.equal(this.connection.notes.auth_plain_asked_login, true)
|
|
@@ -235,7 +230,7 @@ describe('auth_base', () => {
|
|
|
235
230
|
describe('check_user', () => {
|
|
236
231
|
beforeEach(_set_up_2)
|
|
237
232
|
|
|
238
|
-
it('bad auth', (done) => {
|
|
233
|
+
it('bad auth', (t, done) => {
|
|
239
234
|
const credentials = ['matt', 'ttam']
|
|
240
235
|
this.plugin.check_user(
|
|
241
236
|
(code) => {
|
|
@@ -250,7 +245,7 @@ describe('auth_base', () => {
|
|
|
250
245
|
)
|
|
251
246
|
})
|
|
252
247
|
|
|
253
|
-
it('good auth', (done) => {
|
|
248
|
+
it('good auth', (t, done) => {
|
|
254
249
|
const credentials = ['test', 'testpass']
|
|
255
250
|
this.plugin.check_user(
|
|
256
251
|
(code) => {
|
|
@@ -269,7 +264,7 @@ describe('auth_base', () => {
|
|
|
269
264
|
describe('check_user_custom_opts', () => {
|
|
270
265
|
beforeEach(_set_up_custom_pwcb_opts)
|
|
271
266
|
|
|
272
|
-
it('legacyok_nomessage', (done) => {
|
|
267
|
+
it('legacyok_nomessage', (t, done) => {
|
|
273
268
|
this.plugin.check_user(
|
|
274
269
|
(code, msg) => {
|
|
275
270
|
assert.equal(code, OK)
|
|
@@ -283,7 +278,7 @@ describe('auth_base', () => {
|
|
|
283
278
|
)
|
|
284
279
|
})
|
|
285
280
|
|
|
286
|
-
it('legacyfail_nomessage', (done) => {
|
|
281
|
+
it('legacyfail_nomessage', (t, done) => {
|
|
287
282
|
this.plugin.check_user(
|
|
288
283
|
(code, msg) => {
|
|
289
284
|
assert.equal(code, OK)
|
|
@@ -297,7 +292,7 @@ describe('auth_base', () => {
|
|
|
297
292
|
)
|
|
298
293
|
})
|
|
299
294
|
|
|
300
|
-
it('legacyok_message', (done) => {
|
|
295
|
+
it('legacyok_message', (t, done) => {
|
|
301
296
|
this.plugin.check_user(
|
|
302
297
|
(code, msg) => {
|
|
303
298
|
assert.equal(code, OK)
|
|
@@ -311,7 +306,7 @@ describe('auth_base', () => {
|
|
|
311
306
|
)
|
|
312
307
|
})
|
|
313
308
|
|
|
314
|
-
it('legacyfail_message', (done) => {
|
|
309
|
+
it('legacyfail_message', (t, done) => {
|
|
315
310
|
this.plugin.check_user(
|
|
316
311
|
(code, msg) => {
|
|
317
312
|
assert.equal(code, OK)
|
|
@@ -325,7 +320,7 @@ describe('auth_base', () => {
|
|
|
325
320
|
)
|
|
326
321
|
})
|
|
327
322
|
|
|
328
|
-
it('newok', (done) => {
|
|
323
|
+
it('newok', (t, done) => {
|
|
329
324
|
this.plugin.check_user(
|
|
330
325
|
(code, msg) => {
|
|
331
326
|
assert.equal(code, OK)
|
|
@@ -339,7 +334,7 @@ describe('auth_base', () => {
|
|
|
339
334
|
)
|
|
340
335
|
})
|
|
341
336
|
|
|
342
|
-
it('newfail', (done) => {
|
|
337
|
+
it('newfail', (t, done) => {
|
|
343
338
|
this.plugin.check_user(
|
|
344
339
|
(code, msg) => {
|
|
345
340
|
assert.equal(code, OK)
|
|
@@ -357,7 +352,7 @@ describe('auth_base', () => {
|
|
|
357
352
|
describe('auth_notes_are_set', () => {
|
|
358
353
|
beforeEach(_set_up_2)
|
|
359
354
|
|
|
360
|
-
it('bad auth: no notes should be set', (done) => {
|
|
355
|
+
it('bad auth: no notes should be set', (t, done) => {
|
|
361
356
|
const credentials = ['matt', 'ttam']
|
|
362
357
|
this.plugin.check_user(
|
|
363
358
|
(code) => {
|
|
@@ -371,7 +366,7 @@ describe('auth_base', () => {
|
|
|
371
366
|
)
|
|
372
367
|
})
|
|
373
368
|
|
|
374
|
-
it('good auth: dont store password', (done) => {
|
|
369
|
+
it('good auth: dont store password', (t, done) => {
|
|
375
370
|
const creds = ['test', 'testpass']
|
|
376
371
|
this.plugin.blankout_password = true
|
|
377
372
|
this.plugin.check_user(
|
|
@@ -386,7 +381,7 @@ describe('auth_base', () => {
|
|
|
386
381
|
)
|
|
387
382
|
})
|
|
388
383
|
|
|
389
|
-
it('good auth: store password (default)', (done) => {
|
|
384
|
+
it('good auth: store password (default)', (t, done) => {
|
|
390
385
|
const creds = ['test', 'testpass']
|
|
391
386
|
this.plugin.check_user(
|
|
392
387
|
(code) => {
|
|
@@ -404,7 +399,7 @@ describe('auth_base', () => {
|
|
|
404
399
|
describe('hook_unrecognized_command', () => {
|
|
405
400
|
beforeEach(_set_up)
|
|
406
401
|
|
|
407
|
-
it('AUTH type FOO', (done) => {
|
|
402
|
+
it('AUTH type FOO', (t, done) => {
|
|
408
403
|
const params = ['AUTH', 'FOO']
|
|
409
404
|
this.connection.notes.allowed_auth_methods = ['PLAIN', 'LOGIN']
|
|
410
405
|
this.plugin.hook_unrecognized_command(
|
|
@@ -418,7 +413,7 @@ describe('auth_base', () => {
|
|
|
418
413
|
)
|
|
419
414
|
})
|
|
420
415
|
|
|
421
|
-
it('AUTH PLAIN', (done) => {
|
|
416
|
+
it('AUTH PLAIN', (t, done) => {
|
|
422
417
|
const params = ['AUTH', 'PLAIN', utils.base64('discard\0test\0testpass')]
|
|
423
418
|
this.connection.notes.allowed_auth_methods = ['PLAIN', 'LOGIN']
|
|
424
419
|
this.plugin.hook_unrecognized_command(
|
|
@@ -432,7 +427,7 @@ describe('auth_base', () => {
|
|
|
432
427
|
)
|
|
433
428
|
})
|
|
434
429
|
|
|
435
|
-
it('AUTH PLAIN, authenticating', (done) => {
|
|
430
|
+
it('AUTH PLAIN, authenticating', (t, done) => {
|
|
436
431
|
this.connection.notes.allowed_auth_methods = ['PLAIN', 'LOGIN']
|
|
437
432
|
this.connection.notes.authenticating = true
|
|
438
433
|
this.connection.notes.auth_method = 'PLAIN'
|
|
@@ -451,7 +446,7 @@ describe('auth_base', () => {
|
|
|
451
446
|
describe('auth_login', () => {
|
|
452
447
|
beforeEach(_set_up)
|
|
453
448
|
|
|
454
|
-
it('AUTH LOGIN', (done) => {
|
|
449
|
+
it('AUTH LOGIN', (t, done) => {
|
|
455
450
|
const params = ['AUTH', 'LOGIN']
|
|
456
451
|
this.connection.notes.allowed_auth_methods = ['PLAIN', 'LOGIN']
|
|
457
452
|
this.plugin.hook_unrecognized_command(
|
|
@@ -484,7 +479,7 @@ describe('auth_base', () => {
|
|
|
484
479
|
)
|
|
485
480
|
})
|
|
486
481
|
|
|
487
|
-
it('AUTH LOGIN <username>', (done) => {
|
|
482
|
+
it('AUTH LOGIN <username>', (t, done) => {
|
|
488
483
|
const params = ['AUTH', 'LOGIN', utils.base64('test')]
|
|
489
484
|
this.connection.notes.allowed_auth_methods = ['PLAIN', 'LOGIN']
|
|
490
485
|
this.plugin.hook_unrecognized_command(
|
|
@@ -509,7 +504,7 @@ describe('auth_base', () => {
|
|
|
509
504
|
)
|
|
510
505
|
})
|
|
511
506
|
|
|
512
|
-
it('AUTH LOGIN <username>, bad protocol', (done) => {
|
|
507
|
+
it('AUTH LOGIN <username>, bad protocol', (t, done) => {
|
|
513
508
|
const params = ['AUTH', 'LOGIN', utils.base64('test')]
|
|
514
509
|
this.connection.notes.allowed_auth_methods = ['PLAIN', 'LOGIN']
|
|
515
510
|
this.plugin.hook_unrecognized_command(
|
|
@@ -535,7 +530,7 @@ describe('auth_base', () => {
|
|
|
535
530
|
)
|
|
536
531
|
})
|
|
537
532
|
|
|
538
|
-
it('AUTH LOGIN, reauthentication', (done) => {
|
|
533
|
+
it('AUTH LOGIN, reauthentication', (t, done) => {
|
|
539
534
|
const params = ['AUTH', 'LOGIN', utils.base64('test')]
|
|
540
535
|
this.connection.notes.allowed_auth_methods = ['PLAIN', 'LOGIN']
|
|
541
536
|
this.plugin.hook_unrecognized_command(
|
|
@@ -583,7 +578,7 @@ describe('auth_base', () => {
|
|
|
583
578
|
describe('constrain_sender', () => {
|
|
584
579
|
beforeEach(_set_up)
|
|
585
580
|
|
|
586
|
-
it('constrain_sender, domain match', (done) => {
|
|
581
|
+
it('constrain_sender, domain match', (t, done) => {
|
|
587
582
|
this.mfrom = new Address('user@example.com')
|
|
588
583
|
this.connection.results.add({ name: 'auth' }, { user: 'user@example.com' })
|
|
589
584
|
this.plugin.constrain_sender(
|
|
@@ -596,7 +591,7 @@ describe('auth_base', () => {
|
|
|
596
591
|
)
|
|
597
592
|
})
|
|
598
593
|
|
|
599
|
-
it('constrain_sender, domain mismatch', (done) => {
|
|
594
|
+
it('constrain_sender, domain mismatch', (t, done) => {
|
|
600
595
|
this.mfrom = new Address('user@example.net')
|
|
601
596
|
this.connection.results.add({ name: 'auth' }, { user: 'user@example.com' })
|
|
602
597
|
this.plugin.constrain_sender(
|
|
@@ -609,7 +604,7 @@ describe('auth_base', () => {
|
|
|
609
604
|
[this.mfrom],
|
|
610
605
|
)
|
|
611
606
|
})
|
|
612
|
-
it('constrain_sender, no domain', (done) => {
|
|
607
|
+
it('constrain_sender, no domain', (t, done) => {
|
|
613
608
|
this.mfrom = new Address('user@example.com')
|
|
614
609
|
this.connection.results.add({ name: 'auth' }, { user: 'user' })
|
|
615
610
|
this.plugin.constrain_sender(
|