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.
Files changed (160) hide show
  1. package/.prettierignore +4 -0
  2. package/CONTRIBUTORS.md +5 -5
  3. package/Changes.md +69 -50
  4. package/Plugins.md +3 -1
  5. package/README.md +1 -1
  6. package/bin/haraka +475 -478
  7. package/config/outbound.ini +3 -0
  8. package/connection.js +1072 -1108
  9. package/docs/Connection.md +29 -30
  10. package/docs/CoreConfig.md +38 -39
  11. package/docs/CustomReturnCodes.md +0 -1
  12. package/docs/HAProxy.md +2 -2
  13. package/docs/Header.md +1 -1
  14. package/docs/Logging.md +29 -5
  15. package/docs/Outbound.md +93 -78
  16. package/docs/Plugins.md +103 -108
  17. package/docs/Transaction.md +49 -51
  18. package/docs/Tutorial.md +127 -143
  19. package/docs/deprecated/access.md +0 -1
  20. package/docs/deprecated/backscatterer.md +2 -3
  21. package/docs/deprecated/connect.rdns_access.md +18 -27
  22. package/docs/deprecated/data.headers.md +0 -1
  23. package/docs/deprecated/data.nomsgid.md +1 -2
  24. package/docs/deprecated/data.noreceived.md +1 -2
  25. package/docs/deprecated/data.rfc5322_header_checks.md +1 -2
  26. package/docs/deprecated/dkim_sign.md +13 -17
  27. package/docs/deprecated/dkim_verify.md +9 -17
  28. package/docs/deprecated/dnsbl.md +36 -38
  29. package/docs/deprecated/dnswl.md +41 -43
  30. package/docs/deprecated/lookup_rdns.strict.md +21 -34
  31. package/docs/deprecated/mail_from.access.md +17 -25
  32. package/docs/deprecated/mail_from.blocklist.md +9 -12
  33. package/docs/deprecated/mail_from.nobounces.md +1 -2
  34. package/docs/deprecated/rcpt_to.access.md +20 -27
  35. package/docs/deprecated/rcpt_to.blocklist.md +10 -13
  36. package/docs/deprecated/rcpt_to.routes.md +0 -1
  37. package/docs/deprecated/rdns.regexp.md +13 -15
  38. package/docs/plugins/aliases.md +89 -89
  39. package/docs/plugins/auth/auth_bridge.md +5 -7
  40. package/docs/plugins/auth/auth_ldap.md +11 -14
  41. package/docs/plugins/auth/auth_proxy.md +10 -12
  42. package/docs/plugins/auth/auth_vpopmaild.md +5 -6
  43. package/docs/plugins/auth/flat_file.md +4 -4
  44. package/docs/plugins/block_me.md +3 -3
  45. package/docs/plugins/data.signatures.md +1 -2
  46. package/docs/plugins/delay_deny.md +3 -4
  47. package/docs/plugins/max_unrecognized_commands.md +4 -4
  48. package/docs/plugins/prevent_credential_leaks.md +6 -6
  49. package/docs/plugins/process_title.md +18 -18
  50. package/docs/plugins/queue/deliver.md +2 -3
  51. package/docs/plugins/queue/discard.md +4 -4
  52. package/docs/plugins/queue/lmtp.md +1 -3
  53. package/docs/plugins/queue/qmail-queue.md +7 -9
  54. package/docs/plugins/queue/quarantine.md +16 -21
  55. package/docs/plugins/queue/rabbitmq.md +8 -11
  56. package/docs/plugins/queue/rabbitmq_amqplib.md +43 -39
  57. package/docs/plugins/queue/smtp_bridge.md +7 -10
  58. package/docs/plugins/queue/smtp_forward.md +42 -34
  59. package/docs/plugins/queue/smtp_proxy.md +30 -29
  60. package/docs/plugins/queue/test.md +1 -3
  61. package/docs/plugins/rcpt_to.in_host_list.md +6 -6
  62. package/docs/plugins/rcpt_to.max_count.md +1 -1
  63. package/docs/plugins/record_envelope_addresses.md +3 -3
  64. package/docs/plugins/reseed_rng.md +6 -6
  65. package/docs/plugins/status.md +9 -8
  66. package/docs/plugins/tarpit.md +7 -11
  67. package/docs/plugins/tls.md +12 -17
  68. package/docs/plugins/toobusy.md +4 -4
  69. package/docs/plugins/xclient.md +3 -3
  70. package/docs/tutorials/Migrating_from_v1_to_v2.md +19 -41
  71. package/docs/tutorials/SettingUpOutbound.md +6 -9
  72. package/endpoint.js +35 -38
  73. package/eslint.config.mjs +22 -19
  74. package/haraka.js +42 -47
  75. package/host_pool.js +75 -79
  76. package/http/html/404.html +45 -49
  77. package/http/html/index.html +39 -28
  78. package/http/package.json +2 -4
  79. package/line_socket.js +27 -28
  80. package/logger.js +182 -201
  81. package/outbound/client_pool.js +34 -27
  82. package/outbound/config.js +64 -59
  83. package/outbound/fsync_writestream.js +24 -25
  84. package/outbound/hmail.js +888 -835
  85. package/outbound/index.js +194 -187
  86. package/outbound/qfile.js +49 -52
  87. package/outbound/queue.js +197 -190
  88. package/outbound/timer_queue.js +41 -43
  89. package/outbound/tls.js +68 -61
  90. package/outbound/todo.js +11 -11
  91. package/package.json +38 -33
  92. package/plugins/.eslintrc.yaml +0 -1
  93. package/plugins/auth/auth_base.js +123 -127
  94. package/plugins/auth/auth_bridge.js +7 -7
  95. package/plugins/auth/auth_proxy.js +121 -126
  96. package/plugins/auth/auth_vpopmaild.js +84 -85
  97. package/plugins/auth/flat_file.js +18 -17
  98. package/plugins/block_me.js +31 -31
  99. package/plugins/data.signatures.js +13 -13
  100. package/plugins/delay_deny.js +65 -61
  101. package/plugins/prevent_credential_leaks.js +23 -23
  102. package/plugins/process_title.js +125 -128
  103. package/plugins/profile.js +5 -5
  104. package/plugins/queue/deliver.js +3 -3
  105. package/plugins/queue/discard.js +13 -14
  106. package/plugins/queue/lmtp.js +16 -17
  107. package/plugins/queue/qmail-queue.js +54 -55
  108. package/plugins/queue/quarantine.js +68 -70
  109. package/plugins/queue/rabbitmq.js +80 -87
  110. package/plugins/queue/rabbitmq_amqplib.js +75 -54
  111. package/plugins/queue/smtp_bridge.js +16 -16
  112. package/plugins/queue/smtp_forward.js +175 -179
  113. package/plugins/queue/smtp_proxy.js +69 -71
  114. package/plugins/queue/test.js +9 -9
  115. package/plugins/rcpt_to.host_list_base.js +30 -34
  116. package/plugins/rcpt_to.in_host_list.js +19 -19
  117. package/plugins/record_envelope_addresses.js +4 -4
  118. package/plugins/reseed_rng.js +4 -4
  119. package/plugins/status.js +90 -97
  120. package/plugins/tarpit.js +25 -14
  121. package/plugins/tls.js +68 -68
  122. package/plugins/toobusy.js +21 -23
  123. package/plugins/xclient.js +51 -53
  124. package/plugins.js +276 -293
  125. package/rfc1869.js +30 -35
  126. package/server.js +308 -299
  127. package/smtp_client.js +244 -228
  128. package/test/.eslintrc.yaml +0 -1
  129. package/test/connection.js +127 -134
  130. package/test/endpoint.js +53 -47
  131. package/test/fixtures/line_socket.js +12 -12
  132. package/test/fixtures/util_hmailitem.js +89 -85
  133. package/test/host_pool.js +90 -92
  134. package/test/installation/plugins/base_plugin.js +2 -2
  135. package/test/installation/plugins/folder_plugin/index.js +2 -3
  136. package/test/installation/plugins/inherits.js +3 -3
  137. package/test/installation/plugins/load_first.js +2 -3
  138. package/test/installation/plugins/plugin.js +1 -3
  139. package/test/installation/plugins/tls.js +2 -4
  140. package/test/logger.js +135 -116
  141. package/test/outbound/hmail.js +49 -35
  142. package/test/outbound/index.js +118 -101
  143. package/test/outbound/qfile.js +51 -53
  144. package/test/outbound_bounce_net_errors.js +84 -69
  145. package/test/outbound_bounce_rfc3464.js +235 -165
  146. package/test/plugins/auth/auth_base.js +420 -279
  147. package/test/plugins/auth/auth_vpopmaild.js +38 -39
  148. package/test/plugins/queue/smtp_forward.js +126 -104
  149. package/test/plugins/rcpt_to.host_list_base.js +85 -67
  150. package/test/plugins/rcpt_to.in_host_list.js +159 -112
  151. package/test/plugins/status.js +71 -64
  152. package/test/plugins/tls.js +37 -34
  153. package/test/plugins.js +97 -92
  154. package/test/rfc1869.js +19 -26
  155. package/test/server.js +293 -272
  156. package/test/smtp_client.js +180 -176
  157. package/test/tls_socket.js +62 -66
  158. package/test/transaction.js +159 -160
  159. package/tls_socket.js +331 -333
  160. package/transaction.js +129 -137
@@ -2,163 +2,161 @@
2
2
 
3
3
  const net = require('node:net')
4
4
 
5
- const utils = require('haraka-utils');
5
+ const utils = require('haraka-utils')
6
6
  const net_utils = require('haraka-net-utils')
7
7
 
8
- const smtp_regexp = /^(\d{3})([ -])(.*)/;
8
+ const tls_socket = require('./tls_socket')
9
+
10
+ const smtp_regexp = /^(\d{3})([ -])(.*)/
9
11
 
10
12
  exports.register = function () {
11
- this.inherits('auth/auth_base');
12
- this.load_tls_ini();
13
+ this.inherits('auth/auth_base')
14
+ this.load_tls_ini()
13
15
  }
14
16
 
15
17
  exports.load_tls_ini = function () {
16
18
  this.tls_cfg = this.config.get('tls.ini', () => {
17
- this.load_tls_ini();
18
- });
19
+ this.load_tls_ini()
20
+ })
19
21
  }
20
22
 
21
23
  exports.hook_capabilities = (next, connection) => {
22
24
  if (connection.tls.enabled) {
23
- const methods = [ 'PLAIN', 'LOGIN' ];
24
- connection.capabilities.push(`AUTH ${methods.join(' ')}`);
25
- connection.notes.allowed_auth_methods = methods;
25
+ const methods = ['PLAIN', 'LOGIN']
26
+ connection.capabilities.push(`AUTH ${methods.join(' ')}`)
27
+ connection.notes.allowed_auth_methods = methods
26
28
  }
27
- next();
29
+ next()
28
30
  }
29
31
 
30
32
  exports.check_plain_passwd = function (connection, user, passwd, cb) {
31
- let domain = /@([^@]+)$/.exec(user);
33
+ let domain = /@([^@]+)$/.exec(user)
32
34
  if (domain) {
33
- domain = domain[1].toLowerCase();
34
- }
35
- else {
35
+ domain = domain[1].toLowerCase()
36
+ } else {
36
37
  // AUTH user not in user@domain.com format
37
- connection.logerror(this, `AUTH user="${user}" error="not in required format"`);
38
- return cb(false);
38
+ connection.logerror(this, `AUTH user="${user}" error="not in required format"`)
39
+ return cb(false)
39
40
  }
40
41
 
41
42
  // Check if domain exists in configuration file
42
- const config = this.config.get('auth_proxy.ini');
43
+ const config = this.config.get('auth_proxy.ini')
43
44
  if (!config.domains[domain]) {
44
- connection.logerror(this, `AUTH user="${user}" error="domain '${domain}' is not defined"`);
45
- return cb(false);
45
+ connection.logerror(this, `AUTH user="${user}" error="domain '${domain}' is not defined"`)
46
+ return cb(false)
46
47
  }
47
48
 
48
- this.try_auth_proxy(connection, config.domains[domain].split(/[,; ]/), user, passwd, cb);
49
+ this.try_auth_proxy(connection, config.domains[domain].split(/[,; ]/), user, passwd, cb)
49
50
  }
50
51
 
51
52
  exports.try_auth_proxy = function (connection, hosts, user, passwd, cb) {
52
- if (!hosts || (hosts && !hosts.length)) return cb(false);
53
+ if (!hosts || (hosts && !hosts.length)) return cb(false)
53
54
  if (typeof hosts !== 'object') {
54
- hosts = [ hosts ];
55
+ hosts = [hosts]
55
56
  }
56
57
 
57
- const self = this;
58
- let [ host, port ] = hosts.shift().split(':'); /* eslint prefer-const: 0 */
58
+ const self = this
59
+ let [host, port] = hosts.shift().split(':') /* eslint prefer-const: 0 */
59
60
  if (!port) port = 25
60
- let methods = [];
61
- let auth_complete = false;
62
- let auth_success = false;
63
- let command = 'connect';
64
- let response = [];
65
- let secure = false;
66
-
67
- const socket = net.connect({ host, port });
61
+ let methods = []
62
+ let auth_complete = false
63
+ let auth_success = false
64
+ let command = 'connect'
65
+ let response = []
66
+ let secure = false
67
+
68
+ const socket = tls_socket.connect({ host, port })
68
69
  net_utils.add_line_processor(socket)
69
- connection.logdebug(this, `attempting connection to host=${host} port=${port}`);
70
- socket.setTimeout(30 * 1000);
71
- socket.on('connect', () => { });
70
+ connection.logdebug(this, `attempting connection to host=${host} port=${port}`)
71
+ socket.setTimeout(30 * 1000)
72
+ socket.on('connect', () => {})
72
73
  socket.on('close', () => {
73
74
  if (!auth_complete) {
74
75
  // Try next host
75
- return this.try_auth_proxy(connection, hosts, user, passwd, cb);
76
+ return this.try_auth_proxy(connection, hosts, user, passwd, cb)
76
77
  }
77
- connection.loginfo(this, `AUTH user="${user}" host="${host}" success=${auth_success}`);
78
- cb(auth_success);
79
- });
78
+ connection.loginfo(this, `AUTH user="${user}" host="${host}" success=${auth_success}`)
79
+ cb(auth_success)
80
+ })
80
81
  socket.on('timeout', () => {
81
- connection.logerror(this, "connection timed out");
82
- socket.end();
82
+ connection.logerror(this, 'connection timed out')
83
+ socket.end()
83
84
  // Try next host
84
- this.try_auth_proxy(connection, hosts, user, passwd, cb);
85
- });
86
- socket.on('error', err => {
87
- connection.logerror(this, `connection failed to host ${host}: ${err}`);
88
- socket.end();
89
- });
85
+ this.try_auth_proxy(connection, hosts, user, passwd, cb)
86
+ })
87
+ socket.on('error', (err) => {
88
+ connection.logerror(this, `connection failed to host ${host}: ${err}`)
89
+ socket.end()
90
+ })
90
91
  socket.send_command = function (cmd, data) {
91
- let line = cmd + (data ? (` ${data}`) : '');
92
+ let line = cmd + (data ? ` ${data}` : '')
92
93
  if (cmd === 'dot') {
93
- line = '.';
94
+ line = '.'
94
95
  }
95
- connection.logprotocol(self, `C: ${line}`);
96
- command = cmd.toLowerCase();
97
- this.write(`${line}\r\n`);
96
+ connection.logprotocol(self, `C: ${line}`)
97
+ command = cmd.toLowerCase()
98
+ this.write(`${line}\r\n`)
98
99
  // Clear response buffer from previous command
99
- response = [];
100
- };
100
+ response = []
101
+ }
101
102
  socket.on('line', function (line) {
102
- connection.logprotocol(self, `S: ${line}`);
103
- const matches = smtp_regexp.exec(line);
103
+ connection.logprotocol(self, `S: ${line}`)
104
+ const matches = smtp_regexp.exec(line)
104
105
  if (!matches) {
105
- connection.logerror(self, `unrecognised response: ${line}`);
106
- socket.end();
107
- return;
106
+ connection.logerror(self, `unrecognised response: ${line}`)
107
+ socket.end()
108
+ return
108
109
  }
109
110
 
110
- const code = matches[1];
111
- const cont = matches[2];
112
- const rest = matches[3];
113
- response.push(rest);
114
- if (cont !== ' ') return;
111
+ const code = matches[1]
112
+ const cont = matches[2]
113
+ const rest = matches[3]
114
+ response.push(rest)
115
+ if (cont !== ' ') return
115
116
 
116
- let key;
117
- let cert;
117
+ let key
118
+ let cert
118
119
 
119
- connection.logdebug(self, `command state: ${command}`);
120
+ connection.logdebug(self, `command state: ${command}`)
120
121
  if (command === 'ehlo') {
121
122
  if (code.startsWith('5')) {
122
123
  // EHLO command rejected; abort
123
- socket.send_command('QUIT');
124
- return;
124
+ socket.send_command('QUIT')
125
+ return
125
126
  }
126
127
  // Parse CAPABILITIES
127
128
  for (const i in response) {
128
129
  if (/^STARTTLS/.test(response[i])) {
129
- if (secure) continue; // silly remote, we've already upgraded
130
+ if (secure) continue // silly remote, we've already upgraded
130
131
  // Use TLS opportunistically if we found the key and certificate
131
- key = self.config.get(self.tls_cfg.main.key || 'tls_key.pem', 'binary');
132
- cert = self.config.get(self.tls_cfg.main.cert || 'tls_cert.pem', 'binary');
132
+ key = self.config.get(self.tls_cfg.main.key || 'tls_key.pem', 'binary')
133
+ cert = self.config.get(self.tls_cfg.main.cert || 'tls_cert.pem', 'binary')
133
134
  if (key && cert) {
134
135
  this.on('secure', () => {
135
- if (secure) return;
136
- secure = true;
137
- socket.send_command('EHLO', connection.local.host);
138
- });
139
- socket.send_command('STARTTLS');
140
- return;
136
+ if (secure) return
137
+ secure = true
138
+ socket.send_command('EHLO', connection.local.host)
139
+ })
140
+ socket.send_command('STARTTLS')
141
+ return
141
142
  }
142
- }
143
- else if (/^AUTH /.test(response[i])) {
143
+ } else if (/^AUTH /.test(response[i])) {
144
144
  // Parse supported AUTH methods
145
- const parse = /^AUTH (.+)$/.exec(response[i]);
146
- methods = parse[1].split(/\s+/);
147
- connection.logdebug(self, `found supported AUTH methods: ${methods}`);
145
+ const parse = /^AUTH (.+)$/.exec(response[i])
146
+ methods = parse[1].split(/\s+/)
147
+ connection.logdebug(self, `found supported AUTH methods: ${methods}`)
148
148
  // Prefer PLAIN as it's easiest
149
149
  if (methods.includes('PLAIN')) {
150
- socket.send_command('AUTH',`PLAIN ${utils.base64(`\0${user}\0${passwd}`)}`);
151
- return;
152
- }
153
- else if (methods.includes('LOGIN')) {
154
- socket.send_command('AUTH','LOGIN');
155
- return;
156
- }
157
- else {
150
+ socket.send_command('AUTH', `PLAIN ${utils.base64(`\0${user}\0${passwd}`)}`)
151
+ return
152
+ } else if (methods.includes('LOGIN')) {
153
+ socket.send_command('AUTH', 'LOGIN')
154
+ return
155
+ } else {
158
156
  // No compatible methods; abort...
159
- connection.logdebug(self, 'no compatible AUTH methods');
160
- socket.send_command('QUIT');
161
- return;
157
+ connection.logdebug(self, 'no compatible AUTH methods')
158
+ socket.send_command('QUIT')
159
+ return
162
160
  }
163
161
  }
164
162
  }
@@ -167,60 +165,57 @@ exports.try_auth_proxy = function (connection, hosts, user, passwd, cb) {
167
165
  // Handle LOGIN
168
166
  if (code.startsWith('3') && response[0] === 'VXNlcm5hbWU6') {
169
167
  // Write to the socket directly to keep the state at 'auth'
170
- this.write(`${utils.base64(user)}\r\n`);
171
- response = [];
172
- return;
173
- }
174
- else if (code.startsWith('3') && response[0] === 'UGFzc3dvcmQ6') {
175
- this.write(`${utils.base64(passwd)}\r\n`);
176
- response = [];
177
- return;
168
+ this.write(`${utils.base64(user)}\r\n`)
169
+ response = []
170
+ return
171
+ } else if (code.startsWith('3') && response[0] === 'UGFzc3dvcmQ6') {
172
+ this.write(`${utils.base64(passwd)}\r\n`)
173
+ response = []
174
+ return
178
175
  }
179
176
  if (code.startsWith('5')) {
180
177
  // Initial attempt failed; strip domain and retry.
181
178
  const u = /^([^@]+)@.+$/.exec(user)
182
179
  if (u) {
183
- user = u[1];
180
+ user = u[1]
184
181
  if (methods.includes('PLAIN')) {
185
- socket.send_command('AUTH', `PLAIN ${utils.base64(`\0${user}\0${passwd}`)}`);
182
+ socket.send_command('AUTH', `PLAIN ${utils.base64(`\0${user}\0${passwd}`)}`)
183
+ } else if (methods.includes('LOGIN')) {
184
+ socket.send_command('AUTH', 'LOGIN')
186
185
  }
187
- else if (methods.includes('LOGIN')) {
188
- socket.send_command('AUTH', 'LOGIN');
189
- }
190
- return;
191
- }
192
- else {
186
+ return
187
+ } else {
193
188
  // Don't attempt any other hosts
194
- auth_complete = true;
189
+ auth_complete = true
195
190
  }
196
191
  }
197
192
  }
198
193
  if (/^[345]/.test(code)) {
199
194
  // Got an unhandled error
200
- connection.logdebug(self, `error: ${line}`);
201
- socket.send_command('QUIT');
202
- return;
195
+ connection.logdebug(self, `error: ${line}`)
196
+ socket.send_command('QUIT')
197
+ return
203
198
  }
204
199
  switch (command) {
205
200
  case 'starttls':
206
- this.upgrade({ key, cert });
207
- break;
201
+ this.upgrade({ key, cert })
202
+ break
208
203
  case 'connect':
209
- socket.send_command('EHLO', connection.local.host);
210
- break;
204
+ socket.send_command('EHLO', connection.local.host)
205
+ break
211
206
  case 'auth':
212
207
  // AUTH was successful
213
- auth_complete = true;
214
- auth_success = true;
215
- socket.send_command('QUIT');
216
- break;
208
+ auth_complete = true
209
+ auth_success = true
210
+ socket.send_command('QUIT')
211
+ break
217
212
  case 'ehlo':
218
213
  case 'helo':
219
214
  case 'quit':
220
- socket.end();
221
- break;
215
+ socket.end()
216
+ break
222
217
  default:
223
- throw new Error(`[auth/auth_proxy] unknown command: ${command}`);
218
+ throw new Error(`[auth/auth_proxy] unknown command: ${command}`)
224
219
  }
225
- });
220
+ })
226
221
  }
@@ -1,12 +1,12 @@
1
1
  // Auth against vpopmaild
2
2
 
3
- const net = require('node:net');
3
+ const net = require('node:net')
4
4
 
5
5
  exports.register = function () {
6
- this.inherits('auth/auth_base');
7
- this.blankout_password=true
6
+ this.inherits('auth/auth_base')
7
+ this.blankout_password = true
8
8
 
9
- this.load_vpopmaild_ini();
9
+ this.load_vpopmaild_ini()
10
10
 
11
11
  if (this.cfg.main.constrain_sender) {
12
12
  this.register_hook('mail', 'constrain_sender')
@@ -14,150 +14,149 @@ exports.register = function () {
14
14
  }
15
15
 
16
16
  exports.load_vpopmaild_ini = function () {
17
- this.cfg = this.config.get('auth_vpopmaild.ini', {
18
- booleans: [
19
- '+main.constrain_sender',
20
- ]
21
- },
22
- () => {
23
- this.load_vpopmaild_ini();
24
- });
17
+ this.cfg = this.config.get(
18
+ 'auth_vpopmaild.ini',
19
+ {
20
+ booleans: ['+main.constrain_sender'],
21
+ },
22
+ () => {
23
+ this.load_vpopmaild_ini()
24
+ },
25
+ )
25
26
  }
26
27
 
27
28
  exports.hook_capabilities = function (next, connection) {
28
- if (!connection.tls.enabled) return next();
29
+ if (!connection.tls.enabled) return next()
29
30
 
30
- const methods = [ 'PLAIN', 'LOGIN' ];
31
- if (this.cfg.main.sysadmin) methods.push('CRAM-MD5');
31
+ const methods = ['PLAIN', 'LOGIN']
32
+ if (this.cfg.main.sysadmin) methods.push('CRAM-MD5')
32
33
 
33
- connection.capabilities.push(`AUTH ${methods.join(' ')}`);
34
- connection.notes.allowed_auth_methods = methods;
34
+ connection.capabilities.push(`AUTH ${methods.join(' ')}`)
35
+ connection.notes.allowed_auth_methods = methods
35
36
 
36
- next();
37
+ next()
37
38
  }
38
39
 
39
40
  exports.check_plain_passwd = function (connection, user, passwd, cb) {
41
+ let chunk_count = 0
42
+ let auth_success = false
40
43
 
41
- let chunk_count = 0;
42
- let auth_success = false;
44
+ const socket = this.get_vpopmaild_socket(user)
45
+ socket.setEncoding('utf8')
43
46
 
44
- const socket = this.get_vpopmaild_socket(user);
45
- socket.setEncoding('utf8');
46
-
47
- socket.on('data', chunk => {
48
- chunk_count++;
47
+ socket.on('data', (chunk) => {
48
+ chunk_count++
49
49
  if (chunk_count === 1) {
50
50
  if (/^\+OK/.test(chunk)) {
51
- socket.write(`slogin ${user} ${passwd}\n\r`);
52
- return;
51
+ socket.write(`slogin ${user} ${passwd}\n\r`)
52
+ return
53
53
  }
54
- socket.end();
54
+ socket.end()
55
55
  }
56
56
  if (chunk_count === 2) {
57
- if (/^\+OK/.test(chunk)) { // slogin reply
58
- auth_success = true;
59
- socket.write("quit\n\r");
57
+ if (/^\+OK/.test(chunk)) {
58
+ // slogin reply
59
+ auth_success = true
60
+ socket.write('quit\n\r')
60
61
  }
61
- socket.end(); // disconnect
62
+ socket.end() // disconnect
62
63
  }
63
64
  })
64
65
 
65
66
  socket.on('end', () => {
66
- connection.loginfo(this, `AUTH user="${user}" success=${auth_success}`);
67
- cb(auth_success);
67
+ connection.loginfo(this, `AUTH user="${user}" success=${auth_success}`)
68
+ cb(auth_success)
68
69
  })
69
70
  }
70
71
 
71
72
  exports.get_sock_opts = function (user) {
72
-
73
73
  this.sock_opts = {
74
74
  port: 89,
75
75
  host: '127.0.0.1',
76
76
  sysadmin: undefined,
77
- };
77
+ }
78
78
 
79
- const domain = (user.split('@'))[1];
80
- let sect = this.cfg.main;
81
- if (domain && this.cfg[domain]) sect = this.cfg[domain];
79
+ const domain = user.split('@')[1]
80
+ let sect = this.cfg.main
81
+ if (domain && this.cfg[domain]) sect = this.cfg[domain]
82
82
 
83
- if (sect.port) this.sock_opts.port = sect.port;
84
- if (sect.host) this.sock_opts.host = sect.host;
85
- if (sect.sysadmin) this.sock_opts.sysadmin = sect.sysadmin;
83
+ if (sect.port) this.sock_opts.port = sect.port
84
+ if (sect.host) this.sock_opts.host = sect.host
85
+ if (sect.sysadmin) this.sock_opts.sysadmin = sect.sysadmin
86
86
 
87
- this.logdebug(`sock: ${this.sock_opts.host}:${this.sock_opts.port}`);
88
- return this.sock_opts;
87
+ this.logdebug(`sock: ${this.sock_opts.host}:${this.sock_opts.port}`)
88
+ return this.sock_opts
89
89
  }
90
90
 
91
91
  exports.get_vpopmaild_socket = function (user) {
92
- this.get_sock_opts(user);
92
+ this.get_sock_opts(user)
93
93
 
94
- const socket = new net.Socket();
95
- socket.connect(this.sock_opts.port, this.sock_opts.host);
96
- socket.setTimeout(300 * 1000);
97
- socket.setEncoding('utf8');
94
+ const socket = new net.Socket()
95
+ socket.connect(this.sock_opts.port, this.sock_opts.host)
96
+ socket.setTimeout(300 * 1000)
97
+ socket.setEncoding('utf8')
98
98
 
99
99
  socket.on('timeout', () => {
100
- this.logerror("vpopmaild connection timed out");
101
- socket.end();
100
+ this.logerror('vpopmaild connection timed out')
101
+ socket.end()
102
102
  })
103
- socket.on('error', err => {
104
- this.logerror(`vpopmaild connection failed: ${err}`);
105
- socket.end();
103
+ socket.on('error', (err) => {
104
+ this.logerror(`vpopmaild connection failed: ${err}`)
105
+ socket.end()
106
106
  })
107
107
  socket.on('connect', () => {
108
- this.logdebug('vpopmail connected');
108
+ this.logdebug('vpopmail connected')
109
109
  })
110
- return socket;
110
+ return socket
111
111
  }
112
112
 
113
113
  exports.get_plain_passwd = function (user, connection, cb) {
114
-
115
- const socket = this.get_vpopmaild_socket(user);
114
+ const socket = this.get_vpopmaild_socket(user)
116
115
  if (!this.sock_opts.sysadmin) {
117
- this.logerror("missing sysadmin credentials");
118
- return cb(null);
116
+ this.logerror('missing sysadmin credentials')
117
+ return cb(null)
119
118
  }
120
119
 
121
- const sys = this.sock_opts.sysadmin.split(':');
122
- let plain_pass = null;
123
- let chunk_count = 0;
120
+ const sys = this.sock_opts.sysadmin.split(':')
121
+ let plain_pass = null
122
+ let chunk_count = 0
124
123
 
125
- socket.on('data', chunk => {
126
- chunk_count++;
127
- this.logdebug(`${chunk_count}\t${chunk}`);
124
+ socket.on('data', (chunk) => {
125
+ chunk_count++
126
+ this.logdebug(`${chunk_count}\t${chunk}`)
128
127
  if (chunk_count === 1) {
129
128
  if (/^\+OK/.test(chunk)) {
130
- socket.write(`slogin ${sys[0]} ${sys[1]}\n\r`);
131
- return;
129
+ socket.write(`slogin ${sys[0]} ${sys[1]}\n\r`)
130
+ return
132
131
  }
133
- this.logerror("no ok to start");
134
- socket.end(); // disconnect
132
+ this.logerror('no ok to start')
133
+ socket.end() // disconnect
135
134
  }
136
135
  // slogin reply
137
136
  if (chunk_count === 2) {
138
137
  if (/^\+OK/.test(chunk)) {
139
- this.logdebug('login success, getting user info');
140
- socket.write(`user_info ${user}\n\r`);
141
- return;
138
+ this.logdebug('login success, getting user info')
139
+ socket.write(`user_info ${user}\n\r`)
140
+ return
142
141
  }
143
- this.logerror("syadmin login failed");
144
- socket.end(); // disconnect
142
+ this.logerror('syadmin login failed')
143
+ socket.end() // disconnect
145
144
  }
146
145
  if (chunk_count > 2) {
147
146
  if (/^-ERR/.test(chunk)) {
148
- this.lognotice(`get_plain failed: ${chunk}`);
149
- socket.end(); // disconnect
150
- return;
147
+ this.lognotice(`get_plain failed: ${chunk}`)
148
+ socket.end() // disconnect
149
+ return
151
150
  }
152
151
  if (!/clear_text_password/.test(chunk)) {
153
- return; // pass might be in the next chunk
152
+ return // pass might be in the next chunk
154
153
  }
155
- const pass = chunk.match(/clear_text_password\s(\S+)\s/);
156
- plain_pass = pass[1];
157
- socket.write("quit\n\r");
154
+ const pass = chunk.match(/clear_text_password\s(\S+)\s/)
155
+ plain_pass = pass[1]
156
+ socket.write('quit\n\r')
158
157
  }
159
- });
158
+ })
160
159
  socket.on('end', () => {
161
- cb(plain_pass ? plain_pass.toString() : plain_pass);
162
- });
160
+ cb(plain_pass ? plain_pass.toString() : plain_pass)
161
+ })
163
162
  }
@@ -1,8 +1,8 @@
1
1
  // Auth against a flat file
2
2
 
3
3
  exports.register = function () {
4
- this.inherits('auth/auth_base');
5
- this.load_flat_ini();
4
+ this.inherits('auth/auth_base')
5
+ this.load_flat_ini()
6
6
 
7
7
  if (this.cfg.core.constrain_sender) {
8
8
  this.register_hook('mail', 'constrain_sender')
@@ -10,34 +10,35 @@ exports.register = function () {
10
10
  }
11
11
 
12
12
  exports.load_flat_ini = function () {
13
- this.cfg = this.config.get('auth_flat_file.ini', {
14
- booleans: [
15
- '+core.constrain_sender',
16
- ]
17
- },
18
- () => {
19
- this.load_flat_ini();
20
- });
13
+ this.cfg = this.config.get(
14
+ 'auth_flat_file.ini',
15
+ {
16
+ booleans: ['+core.constrain_sender'],
17
+ },
18
+ () => {
19
+ this.load_flat_ini()
20
+ },
21
+ )
21
22
 
22
23
  if (this.cfg.users === undefined) this.cfg.users = {}
23
24
  }
24
25
 
25
26
  exports.hook_capabilities = function (next, connection) {
26
27
  if (!connection.remote.is_private && !connection.tls.enabled) {
27
- connection.logdebug(this, "Auth disabled for insecure public connection");
28
- return next();
28
+ connection.logdebug(this, 'Auth disabled for insecure public connection')
29
+ return next()
29
30
  }
30
31
 
31
32
  const methods = this.cfg.core?.methods ? this.cfg.core.methods.split(',') : null
32
33
  if (methods && methods.length > 0) {
33
- connection.capabilities.push(`AUTH ${methods.join(' ')}`);
34
- connection.notes.allowed_auth_methods = methods;
34
+ connection.capabilities.push(`AUTH ${methods.join(' ')}`)
35
+ connection.notes.allowed_auth_methods = methods
35
36
  }
36
- next();
37
+ next()
37
38
  }
38
39
 
39
40
  exports.get_plain_passwd = function (user, connection, cb) {
40
- if (this.cfg.users[user]) return cb(this.cfg.users[user].toString());
41
+ if (this.cfg.users[user]) return cb(this.cfg.users[user].toString())
41
42
 
42
- cb();
43
+ cb()
43
44
  }