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
|
@@ -4,26 +4,26 @@
|
|
|
4
4
|
|
|
5
5
|
// Note: You can disable setting `connection.notes.auth_passwd` by `plugin.blankout_password = true`
|
|
6
6
|
|
|
7
|
-
const crypto = require('node:crypto')
|
|
7
|
+
const crypto = require('node:crypto')
|
|
8
8
|
|
|
9
|
-
const tlds
|
|
10
|
-
const utils
|
|
9
|
+
const tlds = require('haraka-tld')
|
|
10
|
+
const utils = require('haraka-utils')
|
|
11
11
|
|
|
12
|
-
const AUTH_COMMAND = 'AUTH'
|
|
13
|
-
const AUTH_METHOD_CRAM_MD5 = 'CRAM-MD5'
|
|
14
|
-
const AUTH_METHOD_PLAIN = 'PLAIN'
|
|
15
|
-
const AUTH_METHOD_LOGIN = 'LOGIN'
|
|
16
|
-
const LOGIN_STRING1 = 'VXNlcm5hbWU6'
|
|
17
|
-
const LOGIN_STRING2 = 'UGFzc3dvcmQ6'
|
|
12
|
+
const AUTH_COMMAND = 'AUTH'
|
|
13
|
+
const AUTH_METHOD_CRAM_MD5 = 'CRAM-MD5'
|
|
14
|
+
const AUTH_METHOD_PLAIN = 'PLAIN'
|
|
15
|
+
const AUTH_METHOD_LOGIN = 'LOGIN'
|
|
16
|
+
const LOGIN_STRING1 = 'VXNlcm5hbWU6' //Username: base64 coded
|
|
17
|
+
const LOGIN_STRING2 = 'UGFzc3dvcmQ6' //Password: base64 coded
|
|
18
18
|
|
|
19
19
|
exports.hook_capabilities = (next, connection) => {
|
|
20
20
|
// Don't offer AUTH capabilities unless session is encrypted
|
|
21
|
-
if (!connection.tls.enabled) return next()
|
|
21
|
+
if (!connection.tls.enabled) return next()
|
|
22
22
|
|
|
23
|
-
const methods = [
|
|
24
|
-
connection.capabilities.push(`AUTH ${methods.join(' ')}`)
|
|
25
|
-
connection.notes.allowed_auth_methods = methods
|
|
26
|
-
next()
|
|
23
|
+
const methods = ['PLAIN', 'LOGIN', 'CRAM-MD5']
|
|
24
|
+
connection.capabilities.push(`AUTH ${methods.join(' ')}`)
|
|
25
|
+
connection.notes.allowed_auth_methods = methods
|
|
26
|
+
next()
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
// Override this at a minimum. Run cb(passwd) to provide a password.
|
|
@@ -31,138 +31,137 @@ exports.get_plain_passwd = (user, connection, cb) => cb()
|
|
|
31
31
|
|
|
32
32
|
exports.hook_unrecognized_command = function (next, connection, params) {
|
|
33
33
|
if (params[0].toUpperCase() === AUTH_COMMAND && params[1]) {
|
|
34
|
-
return this.select_auth_method(next, connection, params.slice(1).join(' '))
|
|
34
|
+
return this.select_auth_method(next, connection, params.slice(1).join(' '))
|
|
35
35
|
}
|
|
36
|
-
if (!connection.notes.authenticating) return next()
|
|
36
|
+
if (!connection.notes.authenticating) return next()
|
|
37
37
|
|
|
38
|
-
const am = connection.notes.auth_method
|
|
38
|
+
const am = connection.notes.auth_method
|
|
39
39
|
if (am === AUTH_METHOD_CRAM_MD5 && connection.notes.auth_ticket) {
|
|
40
|
-
return this.auth_cram_md5(next, connection, params)
|
|
40
|
+
return this.auth_cram_md5(next, connection, params)
|
|
41
41
|
}
|
|
42
42
|
if (am === AUTH_METHOD_LOGIN) {
|
|
43
|
-
return this.auth_login(next, connection, params)
|
|
43
|
+
return this.auth_login(next, connection, params)
|
|
44
44
|
}
|
|
45
45
|
if (am === AUTH_METHOD_PLAIN) {
|
|
46
|
-
return this.auth_plain(next, connection, params)
|
|
46
|
+
return this.auth_plain(next, connection, params)
|
|
47
47
|
}
|
|
48
|
-
next()
|
|
48
|
+
next()
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
exports.check_plain_passwd = function (connection, user, passwd, cb) {
|
|
52
|
-
function callback
|
|
53
|
-
cb(plain_pw === null ? false : plain_pw === passwd)
|
|
52
|
+
function callback(plain_pw) {
|
|
53
|
+
cb(plain_pw === null ? false : plain_pw === passwd)
|
|
54
54
|
}
|
|
55
55
|
if (this.get_plain_passwd.length == 2) {
|
|
56
|
-
this.get_plain_passwd(user, callback)
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
else {
|
|
62
|
-
throw 'Invalid number of arguments for get_plain_passwd';
|
|
56
|
+
this.get_plain_passwd(user, callback)
|
|
57
|
+
} else if (this.get_plain_passwd.length == 3) {
|
|
58
|
+
this.get_plain_passwd(user, connection, callback)
|
|
59
|
+
} else {
|
|
60
|
+
throw 'Invalid number of arguments for get_plain_passwd'
|
|
63
61
|
}
|
|
64
62
|
}
|
|
65
63
|
|
|
66
64
|
exports.check_cram_md5_passwd = function (connection, user, passwd, cb) {
|
|
67
|
-
function callback
|
|
68
|
-
if (plain_pw == null) return cb(false)
|
|
65
|
+
function callback(plain_pw) {
|
|
66
|
+
if (plain_pw == null) return cb(false)
|
|
69
67
|
|
|
70
|
-
const hmac = crypto.createHmac('md5', plain_pw.toString())
|
|
71
|
-
hmac.update(connection.notes.auth_ticket)
|
|
68
|
+
const hmac = crypto.createHmac('md5', plain_pw.toString())
|
|
69
|
+
hmac.update(connection.notes.auth_ticket)
|
|
72
70
|
|
|
73
|
-
if (hmac.digest('hex') === passwd) return cb(true)
|
|
71
|
+
if (hmac.digest('hex') === passwd) return cb(true)
|
|
74
72
|
|
|
75
|
-
cb(false)
|
|
73
|
+
cb(false)
|
|
76
74
|
}
|
|
77
75
|
if (this.get_plain_passwd.length == 2) {
|
|
78
|
-
this.get_plain_passwd(user, callback)
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
else {
|
|
84
|
-
throw 'Invalid number of arguments for get_plain_passwd';
|
|
76
|
+
this.get_plain_passwd(user, callback)
|
|
77
|
+
} else if (this.get_plain_passwd.length == 3) {
|
|
78
|
+
this.get_plain_passwd(user, connection, callback)
|
|
79
|
+
} else {
|
|
80
|
+
throw 'Invalid number of arguments for get_plain_passwd'
|
|
85
81
|
}
|
|
86
82
|
}
|
|
87
83
|
|
|
88
84
|
exports.check_user = function (next, connection, credentials, method) {
|
|
89
|
-
const plugin = this
|
|
90
|
-
connection.notes.authenticating = false
|
|
85
|
+
const plugin = this
|
|
86
|
+
connection.notes.authenticating = false
|
|
91
87
|
if (!(credentials[0] && credentials[1])) {
|
|
92
88
|
connection.respond(504, 'Invalid AUTH string', () => {
|
|
93
|
-
connection.reset_transaction(() => next(OK))
|
|
94
|
-
})
|
|
95
|
-
return
|
|
89
|
+
connection.reset_transaction(() => next(OK))
|
|
90
|
+
})
|
|
91
|
+
return
|
|
96
92
|
}
|
|
97
93
|
|
|
98
94
|
// valid: (true|false)
|
|
99
95
|
// opts: ({ message, code }|String)
|
|
100
|
-
function passwd_ok
|
|
101
|
-
const status_code = (typeof
|
|
102
|
-
const status_message =
|
|
103
|
-
|
|
96
|
+
function passwd_ok(valid, opts) {
|
|
97
|
+
const status_code = (typeof opts === 'object' && opts.code) || (valid ? 235 : 535)
|
|
98
|
+
const status_message =
|
|
99
|
+
(typeof opts === 'object' ? opts.message : opts) ||
|
|
100
|
+
(valid ? '2.7.0 Authentication successful' : '5.7.8 Authentication failed')
|
|
104
101
|
|
|
105
102
|
if (valid) {
|
|
106
|
-
connection.relaying = true
|
|
107
|
-
connection.results.add({name:'relay'}, {pass: plugin.name})
|
|
108
|
-
|
|
109
|
-
connection.results.add(
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
103
|
+
connection.relaying = true
|
|
104
|
+
connection.results.add({ name: 'relay' }, { pass: plugin.name })
|
|
105
|
+
|
|
106
|
+
connection.results.add(
|
|
107
|
+
{ name: 'auth' },
|
|
108
|
+
{
|
|
109
|
+
pass: plugin.name,
|
|
110
|
+
method,
|
|
111
|
+
user: credentials[0],
|
|
112
|
+
},
|
|
113
|
+
)
|
|
114
114
|
|
|
115
115
|
connection.respond(status_code, status_message, () => {
|
|
116
|
-
connection.authheader =
|
|
117
|
-
connection.auth_results(`auth=pass (${method.toLowerCase()})`)
|
|
118
|
-
connection.notes.auth_user = credentials[0]
|
|
119
|
-
if (!plugin.blankout_password) connection.notes.auth_passwd = credentials[1]
|
|
120
|
-
next(OK)
|
|
121
|
-
})
|
|
122
|
-
return
|
|
116
|
+
connection.authheader = '(authenticated bits=0)\n'
|
|
117
|
+
connection.auth_results(`auth=pass (${method.toLowerCase()})`)
|
|
118
|
+
connection.notes.auth_user = credentials[0]
|
|
119
|
+
if (!plugin.blankout_password) connection.notes.auth_passwd = credentials[1]
|
|
120
|
+
next(OK)
|
|
121
|
+
})
|
|
122
|
+
return
|
|
123
123
|
}
|
|
124
124
|
|
|
125
|
-
if (!connection.notes.auth_fails) connection.notes.auth_fails = 0
|
|
125
|
+
if (!connection.notes.auth_fails) connection.notes.auth_fails = 0
|
|
126
126
|
|
|
127
|
-
connection.notes.auth_fails
|
|
128
|
-
connection.results.add({name: 'auth'}, { fail
|
|
127
|
+
connection.notes.auth_fails++
|
|
128
|
+
connection.results.add({ name: 'auth' }, { fail: `${plugin.name}/${method}` })
|
|
129
129
|
|
|
130
|
-
let delay = Math.pow(2, connection.notes.auth_fails - 1)
|
|
130
|
+
let delay = Math.pow(2, connection.notes.auth_fails - 1)
|
|
131
131
|
if (plugin.timeout && delay >= plugin.timeout) {
|
|
132
|
-
delay = plugin.timeout - 1
|
|
132
|
+
delay = plugin.timeout - 1
|
|
133
133
|
}
|
|
134
|
-
connection.lognotice(plugin, `delaying for ${delay} seconds`)
|
|
134
|
+
connection.lognotice(plugin, `delaying for ${delay} seconds`)
|
|
135
135
|
// here we include the username, as shown in RFC 5451 example
|
|
136
|
-
connection.auth_results(`auth=fail (${method.toLowerCase()}) smtp.auth=${credentials[0]}`)
|
|
136
|
+
connection.auth_results(`auth=fail (${method.toLowerCase()}) smtp.auth=${credentials[0]}`)
|
|
137
137
|
setTimeout(() => {
|
|
138
138
|
connection.respond(status_code, status_message, () => {
|
|
139
|
-
connection.reset_transaction(() => next(OK))
|
|
140
|
-
})
|
|
141
|
-
}, delay * 1000)
|
|
139
|
+
connection.reset_transaction(() => next(OK))
|
|
140
|
+
})
|
|
141
|
+
}, delay * 1000)
|
|
142
142
|
}
|
|
143
143
|
|
|
144
144
|
if (method === AUTH_METHOD_PLAIN || method === AUTH_METHOD_LOGIN) {
|
|
145
|
-
plugin.check_plain_passwd(connection, credentials[0], credentials[1], passwd_ok)
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
plugin.check_cram_md5_passwd(connection, credentials[0], credentials[1], passwd_ok);
|
|
145
|
+
plugin.check_plain_passwd(connection, credentials[0], credentials[1], passwd_ok)
|
|
146
|
+
} else if (method === AUTH_METHOD_CRAM_MD5) {
|
|
147
|
+
plugin.check_cram_md5_passwd(connection, credentials[0], credentials[1], passwd_ok)
|
|
149
148
|
}
|
|
150
149
|
}
|
|
151
150
|
|
|
152
151
|
exports.select_auth_method = function (next, connection, method) {
|
|
153
|
-
const split = method.split(/\s+/)
|
|
154
|
-
method = split.shift().toUpperCase()
|
|
155
|
-
if (!connection.notes.allowed_auth_methods) return next()
|
|
156
|
-
if (!connection.notes.allowed_auth_methods.includes(method)) return next()
|
|
152
|
+
const split = method.split(/\s+/)
|
|
153
|
+
method = split.shift().toUpperCase()
|
|
154
|
+
if (!connection.notes.allowed_auth_methods) return next()
|
|
155
|
+
if (!connection.notes.allowed_auth_methods.includes(method)) return next()
|
|
157
156
|
|
|
158
|
-
if (connection.notes.authenticating) return next(DENYDISCONNECT, 'bad protocol')
|
|
157
|
+
if (connection.notes.authenticating) return next(DENYDISCONNECT, 'bad protocol')
|
|
159
158
|
|
|
160
|
-
connection.notes.authenticating = true
|
|
161
|
-
connection.notes.auth_method = method
|
|
159
|
+
connection.notes.authenticating = true
|
|
160
|
+
connection.notes.auth_method = method
|
|
162
161
|
|
|
163
|
-
if (method === AUTH_METHOD_PLAIN) return this.auth_plain(next, connection, split)
|
|
164
|
-
if (method === AUTH_METHOD_LOGIN) return this.auth_login(next, connection, split)
|
|
165
|
-
if (method === AUTH_METHOD_CRAM_MD5) return this.auth_cram_md5(next, connection)
|
|
162
|
+
if (method === AUTH_METHOD_PLAIN) return this.auth_plain(next, connection, split)
|
|
163
|
+
if (method === AUTH_METHOD_LOGIN) return this.auth_login(next, connection, split)
|
|
164
|
+
if (method === AUTH_METHOD_CRAM_MD5) return this.auth_cram_md5(next, connection)
|
|
166
165
|
}
|
|
167
166
|
|
|
168
167
|
exports.auth_plain = function (next, connection, params) {
|
|
@@ -172,72 +171,69 @@ exports.auth_plain = function (next, connection, params) {
|
|
|
172
171
|
//...
|
|
173
172
|
// <param>
|
|
174
173
|
if (params[0]) {
|
|
175
|
-
const credentials = utils.unbase64(params[0]).split(/\0/)
|
|
176
|
-
credentials.shift()
|
|
177
|
-
this.check_user(next, connection, credentials, AUTH_METHOD_PLAIN)
|
|
174
|
+
const credentials = utils.unbase64(params[0]).split(/\0/)
|
|
175
|
+
credentials.shift() // Discard authid
|
|
176
|
+
this.check_user(next, connection, credentials, AUTH_METHOD_PLAIN)
|
|
178
177
|
return
|
|
179
178
|
}
|
|
180
179
|
|
|
181
180
|
if (connection.notes.auth_plain_asked_login) {
|
|
182
|
-
return next(DENYDISCONNECT, 'bad protocol')
|
|
181
|
+
return next(DENYDISCONNECT, 'bad protocol')
|
|
183
182
|
}
|
|
184
183
|
|
|
185
184
|
connection.respond(334, ' ', () => {
|
|
186
|
-
connection.notes.auth_plain_asked_login = true
|
|
187
|
-
next(OK)
|
|
188
|
-
})
|
|
185
|
+
connection.notes.auth_plain_asked_login = true
|
|
186
|
+
next(OK)
|
|
187
|
+
})
|
|
189
188
|
}
|
|
190
189
|
|
|
191
190
|
exports.auth_login = function (next, connection, params) {
|
|
192
|
-
if (
|
|
193
|
-
(
|
|
194
|
-
|
|
191
|
+
if (
|
|
192
|
+
(!connection.notes.auth_login_asked_login && params[0]) ||
|
|
193
|
+
(connection.notes.auth_login_asked_login && !connection.notes.auth_login_userlogin)
|
|
194
|
+
) {
|
|
195
|
+
if (!params[0]) return next(DENYDISCONNECT, 'bad protocol')
|
|
195
196
|
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
const login = utils.unbase64(params[0]);
|
|
197
|
+
const login = utils.unbase64(params[0])
|
|
199
198
|
connection.respond(334, LOGIN_STRING2, () => {
|
|
200
|
-
connection.notes.auth_login_userlogin = login
|
|
201
|
-
connection.notes.auth_login_asked_login = true
|
|
202
|
-
next(OK)
|
|
203
|
-
})
|
|
204
|
-
return
|
|
199
|
+
connection.notes.auth_login_userlogin = login
|
|
200
|
+
connection.notes.auth_login_asked_login = true
|
|
201
|
+
next(OK)
|
|
202
|
+
})
|
|
203
|
+
return
|
|
205
204
|
}
|
|
206
205
|
|
|
207
206
|
if (connection.notes.auth_login_userlogin) {
|
|
208
|
-
const credentials = [
|
|
209
|
-
connection.notes.auth_login_userlogin,
|
|
210
|
-
utils.unbase64(params[0])
|
|
211
|
-
];
|
|
207
|
+
const credentials = [connection.notes.auth_login_userlogin, utils.unbase64(params[0])]
|
|
212
208
|
|
|
213
|
-
connection.notes.auth_login_userlogin = null
|
|
214
|
-
connection.notes.auth_login_asked_login = false
|
|
209
|
+
connection.notes.auth_login_userlogin = null
|
|
210
|
+
connection.notes.auth_login_asked_login = false
|
|
215
211
|
|
|
216
|
-
return this.check_user(next, connection, credentials, AUTH_METHOD_LOGIN)
|
|
212
|
+
return this.check_user(next, connection, credentials, AUTH_METHOD_LOGIN)
|
|
217
213
|
}
|
|
218
214
|
|
|
219
215
|
connection.respond(334, LOGIN_STRING1, () => {
|
|
220
|
-
connection.notes.auth_login_asked_login = true
|
|
221
|
-
next(OK)
|
|
222
|
-
})
|
|
216
|
+
connection.notes.auth_login_asked_login = true
|
|
217
|
+
next(OK)
|
|
218
|
+
})
|
|
223
219
|
}
|
|
224
220
|
|
|
225
221
|
exports.auth_cram_md5 = function (next, connection, params) {
|
|
226
222
|
if (params) {
|
|
227
|
-
const credentials = utils.unbase64(params[0]).split(' ')
|
|
228
|
-
return this.check_user(next, connection, credentials, AUTH_METHOD_CRAM_MD5)
|
|
223
|
+
const credentials = utils.unbase64(params[0]).split(' ')
|
|
224
|
+
return this.check_user(next, connection, credentials, AUTH_METHOD_CRAM_MD5)
|
|
229
225
|
}
|
|
230
226
|
|
|
231
|
-
const ticket = `<${this.hexi(Math.floor(Math.random() * 1000000))}.${this.hexi(Date.now())}@${connection.local.host}
|
|
227
|
+
const ticket = `<${this.hexi(Math.floor(Math.random() * 1000000))}.${this.hexi(Date.now())}@${connection.local.host}>`
|
|
232
228
|
|
|
233
|
-
connection.loginfo(this, `ticket: ${ticket}`)
|
|
229
|
+
connection.loginfo(this, `ticket: ${ticket}`)
|
|
234
230
|
connection.respond(334, utils.base64(ticket), () => {
|
|
235
|
-
connection.notes.auth_ticket = ticket
|
|
236
|
-
next(OK)
|
|
237
|
-
})
|
|
231
|
+
connection.notes.auth_ticket = ticket
|
|
232
|
+
next(OK)
|
|
233
|
+
})
|
|
238
234
|
}
|
|
239
235
|
|
|
240
|
-
exports.hexi = number => String(Math.abs(parseInt(number)).toString(16))
|
|
236
|
+
exports.hexi = (number) => String(Math.abs(parseInt(number)).toString(16))
|
|
241
237
|
|
|
242
238
|
exports.constrain_sender = function (next, connection, params) {
|
|
243
239
|
if (this?.cfg?.main?.constrain_sender === false) return next()
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
// Bridge AUTH requests to SMTP server
|
|
2
2
|
|
|
3
3
|
exports.register = function () {
|
|
4
|
-
this.inherits('auth/auth_proxy')
|
|
5
|
-
this.load_flat_ini()
|
|
4
|
+
this.inherits('auth/auth_proxy')
|
|
5
|
+
this.load_flat_ini()
|
|
6
6
|
}
|
|
7
7
|
|
|
8
8
|
exports.load_flat_ini = function () {
|
|
9
9
|
this.cfg = this.config.get('smtp_bridge.ini', () => {
|
|
10
|
-
this.load_flat_ini()
|
|
11
|
-
})
|
|
10
|
+
this.load_flat_ini()
|
|
11
|
+
})
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
exports.check_plain_passwd = function (connection, user, passwd, cb) {
|
|
15
|
-
let { host } = this.cfg.main
|
|
15
|
+
let { host } = this.cfg.main
|
|
16
16
|
if (this.cfg.main.port) {
|
|
17
|
-
host = `${host}:${this.cfg.main.port}
|
|
17
|
+
host = `${host}:${this.cfg.main.port}`
|
|
18
18
|
}
|
|
19
|
-
this.try_auth_proxy(connection, host, user, passwd, cb)
|
|
19
|
+
this.try_auth_proxy(connection, host, user, passwd, cb)
|
|
20
20
|
}
|