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
package/tls_socket.js CHANGED
@@ -1,166 +1,165 @@
1
- 'use strict';
1
+ 'use strict'
2
2
 
3
- const cluster = require('node:cluster');
4
- const net = require('node:net');
5
- const path = require('node:path');
6
- const { spawn } = require('node:child_process');
7
- const stream = require('node:stream');
8
- const tls = require('node:tls');
9
- const util = require('node:util');
3
+ const cluster = require('node:cluster')
4
+ const net = require('node:net')
5
+ const path = require('node:path')
6
+ const { spawn } = require('node:child_process')
7
+ const stream = require('node:stream')
8
+ const tls = require('node:tls')
9
+ const util = require('node:util')
10
10
 
11
11
  // npm packages
12
- exports.config = require('haraka-config'); // exported for tests
12
+ exports.config = require('haraka-config') // exported for tests
13
13
  const Notes = require('haraka-notes')
14
14
 
15
- const log = require('./logger');
15
+ const log = require('./logger')
16
16
 
17
- const certsByHost = new Notes();
18
- const ctxByHost = {};
19
- let ocsp;
20
- let ocspCache;
17
+ const certsByHost = new Notes()
18
+ const ctxByHost = {}
19
+ let ocsp
20
+ let ocspCache
21
21
 
22
22
  // provides a common socket for attaching
23
23
  // and detaching from either main socket, or crypto socket
24
24
  class pluggableStream extends stream.Stream {
25
- constructor (socket) {
26
- super();
27
- this.readable = this.writable = true;
28
- this._timeout = 0;
29
- this._keepalive = false;
30
- this._writeState = true;
31
- this._pending = [];
32
- this._pendingCallbacks = [];
33
- if (socket) this.attach(socket);
34
- }
35
-
36
- pause () {
25
+ constructor(socket) {
26
+ super()
27
+ this.readable = this.writable = true
28
+ this._timeout = 0
29
+ this._keepalive = false
30
+ this._writeState = true
31
+ this._pending = []
32
+ this._pendingCallbacks = []
33
+ if (socket) this.attach(socket)
34
+ }
35
+
36
+ pause() {
37
37
  if (this.targetsocket.pause) {
38
- this.targetsocket.pause();
39
- this.readable = false;
38
+ this.targetsocket.pause()
39
+ this.readable = false
40
40
  }
41
41
  }
42
42
 
43
- resume () {
43
+ resume() {
44
44
  if (this.targetsocket.resume) {
45
- this.readable = true;
46
- this.targetsocket.resume();
45
+ this.readable = true
46
+ this.targetsocket.resume()
47
47
  }
48
48
  }
49
49
 
50
- attach (socket) {
51
- this.targetsocket = socket;
52
- this.targetsocket.on('data', data => {
53
- this.emit('data', data);
54
- });
50
+ attach(socket) {
51
+ this.targetsocket = socket
52
+ this.targetsocket.on('data', (data) => {
53
+ this.emit('data', data)
54
+ })
55
55
  this.targetsocket.on('connect', (a, b) => {
56
- this.emit('connect', a, b);
57
- });
56
+ this.emit('connect', a, b)
57
+ })
58
58
  this.targetsocket.on('secureConnect', (a, b) => {
59
- this.emit('secureConnect', a, b);
60
- this.emit('secure', a, b);
61
- });
59
+ this.emit('secureConnect', a, b)
60
+ this.emit('secure', a, b)
61
+ })
62
62
  this.targetsocket.on('secure', (a, b) => {
63
- this.emit('secure', a, b);
64
- });
63
+ this.emit('secure', a, b)
64
+ })
65
65
  this.targetsocket.on('end', () => {
66
- this.writable = this.targetsocket.writable;
67
- this.emit('end');
68
- });
69
- this.targetsocket.on('close', had_error => {
70
- this.writable = this.targetsocket.writable;
71
- this.emit('close', had_error);
72
- });
66
+ this.writable = this.targetsocket.writable
67
+ this.emit('end')
68
+ })
69
+ this.targetsocket.on('close', (had_error) => {
70
+ this.writable = this.targetsocket.writable
71
+ this.emit('close', had_error)
72
+ })
73
73
  this.targetsocket.on('drain', () => {
74
- this.emit('drain');
75
- });
76
- this.targetsocket.once('error', exception => {
77
- this.writable = this.targetsocket.writable;
78
- exception.source = 'tls';
79
- this.emit('error', exception);
80
- });
74
+ this.emit('drain')
75
+ })
76
+ this.targetsocket.once('error', (exception) => {
77
+ this.writable = this.targetsocket.writable
78
+ exception.source = 'tls'
79
+ this.emit('error', exception)
80
+ })
81
81
  this.targetsocket.on('timeout', () => {
82
- this.emit('timeout');
83
- });
82
+ this.emit('timeout')
83
+ })
84
84
  if (this.targetsocket.remotePort) {
85
- this.remotePort = this.targetsocket.remotePort;
85
+ this.remotePort = this.targetsocket.remotePort
86
86
  }
87
87
  if (this.targetsocket.remoteAddress) {
88
- this.remoteAddress = this.targetsocket.remoteAddress;
88
+ this.remoteAddress = this.targetsocket.remoteAddress
89
89
  }
90
90
  if (this.targetsocket.localPort) {
91
- this.localPort = this.targetsocket.localPort;
91
+ this.localPort = this.targetsocket.localPort
92
92
  }
93
93
  if (this.targetsocket.localAddress) {
94
- this.localAddress = this.targetsocket.localAddress;
94
+ this.localAddress = this.targetsocket.localAddress
95
95
  }
96
96
  }
97
97
 
98
- clean (data) {
98
+ clean(data) {
99
99
  if (this.targetsocket?.removeAllListeners) {
100
100
  for (const name of ['data', 'secure', 'secureConnect', 'end', 'close', 'error', 'drain']) {
101
- this.targetsocket.removeAllListeners(name);
101
+ this.targetsocket.removeAllListeners(name)
102
102
  }
103
103
  }
104
- this.targetsocket = {};
105
- this.targetsocket.write = () => {};
104
+ this.targetsocket = {}
105
+ this.targetsocket.write = () => {}
106
106
  }
107
107
 
108
- write (data, encoding, callback) {
108
+ write(data, encoding, callback) {
109
109
  if (this.targetsocket.write) {
110
- return this.targetsocket.write(data, encoding, callback);
110
+ return this.targetsocket.write(data, encoding, callback)
111
111
  }
112
- return false;
112
+ return false
113
113
  }
114
114
 
115
- end (data, encoding) {
115
+ end(data, encoding) {
116
116
  if (this.targetsocket.end) {
117
- return this.targetsocket.end(data, encoding);
117
+ return this.targetsocket.end(data, encoding)
118
118
  }
119
119
  }
120
120
 
121
- destroySoon () {
121
+ destroySoon() {
122
122
  if (this.targetsocket.destroySoon) {
123
- return this.targetsocket.destroySoon();
123
+ return this.targetsocket.destroySoon()
124
124
  }
125
125
  }
126
126
 
127
- destroy () {
127
+ destroy() {
128
128
  if (this.targetsocket.destroy) {
129
- return this.targetsocket.destroy();
129
+ return this.targetsocket.destroy()
130
130
  }
131
131
  }
132
132
 
133
- setKeepAlive (bool) {
134
- this._keepalive = bool;
135
- return this.targetsocket.setKeepAlive(bool);
133
+ setKeepAlive(bool) {
134
+ this._keepalive = bool
135
+ return this.targetsocket.setKeepAlive(bool)
136
136
  }
137
137
 
138
- setNoDelay (/* true||false */) {
139
- }
138
+ setNoDelay(/* true||false */) {}
140
139
 
141
- unref () {
142
- return this.targetsocket.unref();
140
+ unref() {
141
+ return this.targetsocket.unref()
143
142
  }
144
143
 
145
- setTimeout (timeout) {
146
- this._timeout = timeout;
147
- return this.targetsocket.setTimeout(timeout);
144
+ setTimeout(timeout) {
145
+ this._timeout = timeout
146
+ return this.targetsocket.setTimeout(timeout)
148
147
  }
149
148
 
150
- isEncrypted () {
151
- return this.targetsocket.encrypted;
149
+ isEncrypted() {
150
+ return this.targetsocket.encrypted
152
151
  }
153
152
 
154
- isSecure () {
155
- return this.targetsocket.encrypted && this.targetsocket.authorized;
153
+ isSecure() {
154
+ return this.targetsocket.encrypted && this.targetsocket.authorized
156
155
  }
157
156
  }
158
157
 
159
158
  exports.parse_x509 = async (string) => {
160
- const res = {};
159
+ const res = {}
161
160
  if (!string) return res
162
161
 
163
- const keyRe = new RegExp('([-]+BEGIN (?:\\w+ )?PRIVATE KEY[-]+[^-]*[-]+END (?:\\w+ )?PRIVATE KEY[-]+)', 'gm')
162
+ const keyRe = new RegExp('([-]+BEGIN (?:\\w+ )?PRIVATE KEY[-]+[^-]*[-]+END (?:\\w+ )?PRIVATE KEY[-]+)', 'gm')
164
163
  res.keys = string.match(keyRe)
165
164
 
166
165
  const certRe = new RegExp('([-]+BEGIN CERTIFICATE[-]+[^-]*[-]+END CERTIFICATE[-]+)', 'gm')
@@ -179,8 +178,8 @@ exports.parse_x509 = async (string) => {
179
178
 
180
179
  res.expire = new Date(raw.match(/notAfter=(.* [A-Z]{3})/)[1])
181
180
 
182
- const match = /CN\s*=\s*([^/\s,]+)/.exec(raw);
183
- if (match && match[1]) res.names = [ match[1] ]
181
+ const match = /CN\s*=\s*([^/\s,]+)/.exec(raw)
182
+ if (match && match[1]) res.names = [match[1]]
184
183
 
185
184
  for (let name of Array.from(raw.matchAll(/DNS:([^\s,]+)/gm), (m) => m[0])) {
186
185
  name = name.replace('DNS:', '')
@@ -188,189 +187,202 @@ exports.parse_x509 = async (string) => {
188
187
  }
189
188
  }
190
189
 
191
- return res;
190
+ return res
192
191
  }
193
192
 
194
193
  exports.load_tls_ini = (opts) => {
195
-
196
- log.info(`loading tls.ini`); // from ${this.config.root_path}`);
197
-
198
- const cfg = exports.config.get('tls.ini', {
199
- booleans: [
200
- '-redis.disable_for_failed_hosts',
201
-
202
- // wildcards match in any section and are not initialized
203
- '*.requestCert',
204
- '*.rejectUnauthorized',
205
- '*.honorCipherOrder' ,
206
- '*.enableOCSPStapling',
207
- '*.requestOCSP',
208
-
209
- // explicitely declared booleans are initialized
210
- '+main.requestCert',
211
- '-main.rejectUnauthorized',
212
- '+main.honorCipherOrder',
213
- '-main.requestOCSP',
214
- '-main.mutual_tls',
215
- ]
216
- }, () => {
217
- this.load_tls_ini();
218
- });
219
-
220
- if (cfg.no_tls_hosts === undefined) cfg.no_tls_hosts = {};
221
- if (cfg.mutual_auth_hosts === undefined) cfg.mutual_auth_hosts = {};
222
- if (cfg.mutual_auth_hosts_exclude === undefined) cfg.mutual_auth_hosts_exclude = {};
194
+ log.info(`loading tls.ini`) // from ${this.config.root_path}`);
195
+
196
+ const cfg = exports.config.get(
197
+ 'tls.ini',
198
+ {
199
+ booleans: [
200
+ '-redis.disable_for_failed_hosts',
201
+
202
+ // wildcards match in any section and are not initialized
203
+ '*.requestCert',
204
+ '*.rejectUnauthorized',
205
+ '*.honorCipherOrder',
206
+ '*.enableOCSPStapling',
207
+ '*.requestOCSP',
208
+
209
+ // explicitely declared booleans are initialized
210
+ '+main.requestCert',
211
+ '-main.rejectUnauthorized',
212
+ '+main.honorCipherOrder',
213
+ '-main.requestOCSP',
214
+ '-main.mutual_tls',
215
+ ],
216
+ },
217
+ () => {
218
+ this.load_tls_ini()
219
+ },
220
+ )
221
+
222
+ if (cfg.no_tls_hosts === undefined) cfg.no_tls_hosts = {}
223
+ if (cfg.mutual_auth_hosts === undefined) cfg.mutual_auth_hosts = {}
224
+ if (cfg.mutual_auth_hosts_exclude === undefined) cfg.mutual_auth_hosts_exclude = {}
223
225
 
224
226
  if (cfg.main.enableOCSPStapling !== undefined) {
225
- log.error('deprecated setting enableOCSPStapling in tls.ini');
226
- cfg.main.requestOCSP = cfg.main.enableOCSPStapling;
227
+ log.error('deprecated setting enableOCSPStapling in tls.ini')
228
+ cfg.main.requestOCSP = cfg.main.enableOCSPStapling
227
229
  }
228
230
 
229
231
  if (ocsp === undefined && cfg.main.requestOCSP) {
230
232
  try {
231
- ocsp = require('ocsp');
232
- log.debug('ocsp loaded');
233
- ocspCache = new ocsp.Cache();
234
- }
235
- catch (ignore) {
236
- log.notice("OCSP Stapling not available.");
233
+ ocsp = require('ocsp')
234
+ log.debug('ocsp loaded')
235
+ ocspCache = new ocsp.Cache()
236
+ } catch (ignore) {
237
+ log.notice('OCSP Stapling not available.')
237
238
  }
238
239
  }
239
240
 
240
241
  if (cfg.main.requireAuthorized === undefined) {
241
- cfg.main.requireAuthorized = [];
242
- }
243
- else if (!Array.isArray(cfg.main.requireAuthorized)) {
244
- cfg.main.requireAuthorized = [cfg.main.requireAuthorized];
242
+ cfg.main.requireAuthorized = []
243
+ } else if (!Array.isArray(cfg.main.requireAuthorized)) {
244
+ cfg.main.requireAuthorized = [cfg.main.requireAuthorized]
245
245
  }
246
246
 
247
- if (!Array.isArray(cfg.main.no_starttls_ports)) cfg.main.no_starttls_ports = [];
247
+ if (!Array.isArray(cfg.main.no_starttls_ports)) cfg.main.no_starttls_ports = []
248
248
 
249
- this.cfg = cfg;
249
+ this.cfg = cfg
250
250
 
251
251
  if (!opts || opts.role === 'server') {
252
- this.applySocketOpts('*');
253
- this.load_default_opts();
252
+ this.applySocketOpts('*')
253
+ this.load_default_opts()
254
254
  }
255
255
 
256
- return cfg;
256
+ return cfg
257
257
  }
258
258
 
259
- exports.applySocketOpts = name => {
260
-
259
+ exports.applySocketOpts = (name) => {
261
260
  // https://nodejs.org/api/tls.html#tls_new_tls_tlssocket_socket_options
262
261
  const TLSSocketOptions = [
263
262
  // 'server' // manually added
264
- 'isServer', 'requestCert', 'rejectUnauthorized',
265
- 'NPNProtocols', 'ALPNProtocols', 'session',
266
- 'requestOCSP', 'secureContext', 'SNICallback'
267
- ];
263
+ 'isServer',
264
+ 'requestCert',
265
+ 'rejectUnauthorized',
266
+ 'NPNProtocols',
267
+ 'ALPNProtocols',
268
+ 'session',
269
+ 'requestOCSP',
270
+ 'secureContext',
271
+ 'SNICallback',
272
+ ]
268
273
 
269
274
  // https://nodejs.org/api/tls.html#tls_tls_createsecurecontext_options
270
275
  const createSecureContextOptions = [
271
- 'key', 'cert', 'dhparam',
272
- 'pfx', 'passphrase', 'ca', 'crl', 'ciphers', 'minVersion', 'honorCipherOrder',
273
- 'ecdhCurve', 'secureProtocol', 'secureOptions', 'sessionIdContext'
274
- ];
275
-
276
- for (const opt of [ ...TLSSocketOptions, ...createSecureContextOptions ]) {
277
-
276
+ 'key',
277
+ 'cert',
278
+ 'dhparam',
279
+ 'pfx',
280
+ 'passphrase',
281
+ 'ca',
282
+ 'crl',
283
+ 'ciphers',
284
+ 'minVersion',
285
+ 'honorCipherOrder',
286
+ 'ecdhCurve',
287
+ 'secureProtocol',
288
+ 'secureOptions',
289
+ 'sessionIdContext',
290
+ ]
291
+
292
+ for (const opt of [...TLSSocketOptions, ...createSecureContextOptions]) {
278
293
  if (this.cfg[name] && this.cfg[name][opt] !== undefined) {
279
294
  // if the setting exists in tls.ini [name]
280
295
  certsByHost.set([name, opt], this.cfg[name][opt])
281
- }
282
- else if (this.cfg.main[opt] !== undefined) {
296
+ } else if (this.cfg.main[opt] !== undefined) {
283
297
  // save settings in tls.ini [main] to each CN
284
298
  certsByHost.set([name, opt], this.cfg.main[opt])
285
- }
286
- else {
299
+ } else {
287
300
  // defaults
288
301
  switch (opt) {
289
302
  case 'sessionIdContext':
290
303
  certsByHost.set([name, opt], 'haraka')
291
- break;
304
+ break
292
305
  case 'isServer':
293
306
  certsByHost.set([name, opt], true)
294
- break;
307
+ break
295
308
  case 'key':
296
309
  certsByHost.set([name, opt], 'tls_key.pem')
297
- break;
310
+ break
298
311
  case 'cert':
299
312
  certsByHost.set([name, opt], 'tls_cert.pem')
300
- break;
313
+ break
301
314
  case 'dhparam':
302
315
  certsByHost.set([name, opt], 'dhparams.pem')
303
- break;
316
+ break
304
317
  case 'SNICallback':
305
318
  certsByHost.set([name, opt], exports.SNICallback)
306
- break;
319
+ break
307
320
  }
308
321
  }
309
322
  }
310
323
  }
311
324
 
312
325
  exports.load_default_opts = () => {
313
-
314
- const cfg = certsByHost['*'];
326
+ const cfg = certsByHost['*']
315
327
 
316
328
  if (cfg.dhparam && typeof cfg.dhparam === 'string') {
317
- log.debug(`loading dhparams from ${cfg.dhparam}`);
329
+ log.debug(`loading dhparams from ${cfg.dhparam}`)
318
330
  certsByHost.set('*.dhparam', this.config.get(cfg.dhparam, 'binary'))
319
331
  }
320
332
 
321
333
  if (cfg.ca && typeof cfg.ca === 'string') {
322
- log.info(`loading CA certs from ${cfg.ca}`);
334
+ log.info(`loading CA certs from ${cfg.ca}`)
323
335
  certsByHost.set('*.ca', this.config.get(cfg.ca, 'binary'))
324
336
  }
325
337
 
326
338
  // make non-array key/cert option into Arrays with one entry
327
- if (!(Array.isArray(cfg.key ))) cfg.key = [cfg.key];
328
- if (!(Array.isArray(cfg.cert))) cfg.cert = [cfg.cert];
339
+ if (!Array.isArray(cfg.key)) cfg.key = [cfg.key]
340
+ if (!Array.isArray(cfg.cert)) cfg.cert = [cfg.cert]
329
341
 
330
342
  if (cfg.key.length != cfg.cert.length) {
331
- log.error(`number of keys (${cfg.key.length}) not equal to certs (${cfg.cert.length}).`);
343
+ log.error(`number of keys (${cfg.key.length}) not equal to certs (${cfg.cert.length}).`)
332
344
  }
333
345
 
334
346
  // if key file has already been loaded, it'll be a Buffer.
335
347
  if (typeof cfg.key[0] === 'string') {
336
348
  // turn key/cert file names into actual key/cert binary data
337
- const asArray = cfg.key.map(keyFileName => {
338
- if (!keyFileName) return;
339
- const key = this.config.get(keyFileName, 'binary');
349
+ const asArray = cfg.key.map((keyFileName) => {
350
+ if (!keyFileName) return
351
+ const key = this.config.get(keyFileName, 'binary')
340
352
  if (!key) {
341
- log.error(`tls key ${path.join(this.config.root_path, keyFileName)} could not be loaded.`);
353
+ log.error(`tls key ${path.join(this.config.root_path, keyFileName)} could not be loaded.`)
342
354
  }
343
- return key;
355
+ return key
344
356
  })
345
357
  certsByHost.set('*.key', asArray)
346
358
  }
347
359
 
348
360
  if (typeof cfg.cert[0] === 'string') {
349
- const asArray = cfg.cert.map(certFileName => {
350
- if (!certFileName) return;
351
- const cert = this.config.get(certFileName, 'binary');
361
+ const asArray = cfg.cert.map((certFileName) => {
362
+ if (!certFileName) return
363
+ const cert = this.config.get(certFileName, 'binary')
352
364
  if (!cert) {
353
- log.error(`tls cert ${path.join(this.config.root_path, certFileName)} could not be loaded.`);
365
+ log.error(`tls cert ${path.join(this.config.root_path, certFileName)} could not be loaded.`)
354
366
  }
355
- return cert;
367
+ return cert
356
368
  })
357
369
  certsByHost.set('*.cert', asArray)
358
370
  }
359
371
 
360
372
  if (cfg.cert[0] && cfg.key[0]) {
361
- this.tls_valid = true;
373
+ this.tls_valid = true
362
374
 
363
375
  // now that all opts are applied, generate TLS context
364
376
  this.ensureDhparams(() => {
365
- ctxByHost['*'] = tls.createSecureContext(cfg);
377
+ ctxByHost['*'] = tls.createSecureContext(cfg)
366
378
  })
367
379
  }
368
380
  }
369
381
 
370
382
  exports.SNICallback = function (servername, sniDone) {
371
- log.debug(`SNI servername: ${servername}`);
383
+ log.debug(`SNI servername: ${servername}`)
372
384
 
373
- sniDone(null, ctxByHost[servername] || ctxByHost['*']);
385
+ sniDone(null, ctxByHost[servername] || ctxByHost['*'])
374
386
  }
375
387
 
376
388
  exports.get_certs_dir = async (tlsDir) => {
@@ -383,26 +395,24 @@ exports.get_certs_dir = async (tlsDir) => {
383
395
  const files = await this.config.getDir(tlsDir, dirOpts)
384
396
  for (const file of files) {
385
397
  try {
386
- r[file.path] = await exports.parse_x509(file.data.toString());
387
- }
388
- catch (err) {
398
+ r[file.path] = await exports.parse_x509(file.data.toString())
399
+ } catch (err) {
389
400
  log.debug(err.message)
390
401
  }
391
402
  }
392
403
 
393
- log.debug(`found ${Object.keys(r).length} files in config/tls`);
404
+ log.debug(`found ${Object.keys(r).length} files in config/tls`)
394
405
  if (Object.keys(r).length === 0) return
395
406
 
396
407
  const s = {} // certs by name (CN)
397
408
 
398
409
  for (const fp in r) {
399
-
400
410
  if (r[fp].expire && r[fp].expire < new Date()) {
401
411
  log.error(`${fp} expired on ${r[fp].expire}`)
402
412
  }
403
413
 
404
414
  // a file with a key and no cert, get name from file
405
- if (!r[fp].names) r[fp].names = [ path.parse(fp).name ]
415
+ if (!r[fp].names) r[fp].names = [path.parse(fp).name]
406
416
 
407
417
  for (let name of r[fp].names) {
408
418
  if (name[0] === '_') name = name.replace('_', '*') // windows
@@ -424,38 +434,37 @@ exports.get_certs_dir = async (tlsDir) => {
424
434
  this.applySocketOpts(cn) // from tls.ini
425
435
  certsByHost.set([cn, 'cert'], Buffer.from(s[cn].cert))
426
436
  certsByHost.set([cn, 'key'], Buffer.from(s[cn].key))
427
- certsByHost.set([cn, 'dhparam'], certsByHost['*'].dhparam, true);
437
+ certsByHost.set([cn, 'dhparam'], certsByHost['*'].dhparam, true)
428
438
 
429
439
  // all opts are applied, generate TLS context
430
440
  try {
431
- ctxByHost[cn] = tls.createSecureContext(certsByHost.get([cn]));
432
- }
433
- catch (err) {
441
+ ctxByHost[cn] = tls.createSecureContext(certsByHost.get([cn]))
442
+ } catch (err) {
434
443
  log.error(`CN '${cn}' loading got: ${err.message}`)
435
444
  delete ctxByHost[cn]
436
445
  delete certsByHost[cn]
437
446
  }
438
447
  }
439
448
 
440
- log.info(`found ${Object.keys(s).length} TLS certs in config/tls`);
449
+ log.info(`found ${Object.keys(s).length} TLS certs in config/tls`)
441
450
 
442
451
  return certsByHost // used only by tests
443
452
  }
444
453
 
445
- function openssl (crt, ...params) {
454
+ function openssl(crt, ...params) {
446
455
  return new Promise((resolve) => {
447
456
  let crtTxt = ''
448
457
 
449
- const o = spawn('openssl', [...params], { timeout: 1000 });
450
- o.stdout.on('data', data => {
458
+ const o = spawn('openssl', [...params], { timeout: 1000 })
459
+ o.stdout.on('data', (data) => {
451
460
  crtTxt += data
452
461
  })
453
462
 
454
- o.stderr.on('data', data => {
463
+ o.stderr.on('data', (data) => {
455
464
  log.debug(`err: ${data.toString().trim()}`)
456
465
  })
457
466
 
458
- o.on('close', code => {
467
+ o.on('close', (code) => {
459
468
  if (code !== 0) {
460
469
  if (code) console.error(code)
461
470
  }
@@ -468,14 +477,12 @@ function openssl (crt, ...params) {
468
477
  }
469
478
 
470
479
  exports.getSocketOpts = async (name) => {
471
-
472
480
  // startup time, load the config/tls dir
473
- if (!certsByHost['*']) this.load_tls_ini();
481
+ if (!certsByHost['*']) this.load_tls_ini()
474
482
 
475
483
  try {
476
484
  await this.get_certs_dir('tls')
477
- }
478
- catch (err) {
485
+ } catch (err) {
479
486
  if (err.code !== 'ENOENT') {
480
487
  console.error(err.messsage)
481
488
  log.error(err)
@@ -485,243 +492,234 @@ exports.getSocketOpts = async (name) => {
485
492
  return certsByHost[name] || certsByHost['*']
486
493
  }
487
494
 
488
- function pipe (cleartext, socket) {
489
- cleartext.socket = socket;
495
+ function pipe(cleartext, socket) {
496
+ cleartext.socket = socket
490
497
 
491
- function onError (e) {
492
- }
498
+ function onError(e) {}
493
499
 
494
- function onClose () {
495
- socket.removeListener('error', onError);
496
- socket.removeListener('close', onClose);
500
+ function onClose() {
501
+ socket.removeListener('error', onError)
502
+ socket.removeListener('close', onClose)
497
503
  }
498
504
 
499
- socket.on('error', onError);
500
- socket.on('close', onClose);
505
+ socket.on('error', onError)
506
+ socket.on('close', onClose)
501
507
  }
502
508
 
503
- exports.ensureDhparams = done => {
504
-
509
+ exports.ensureDhparams = (done) => {
505
510
  // empty/missing dhparams file
506
511
  if (certsByHost['*'].dhparam) {
507
- return done(null, certsByHost['*'].dhparam);
512
+ return done(null, certsByHost['*'].dhparam)
508
513
  }
509
514
 
510
- if (cluster.isWorker) return; // only once, on the master process
515
+ if (cluster.isWorker) return // only once, on the master process
511
516
 
512
- const filePath = this.cfg.main.dhparam || 'dhparams.pem';
513
- const fpResolved = path.resolve(exports.config.root_path, filePath);
517
+ const filePath = this.cfg.main.dhparam || 'dhparams.pem'
518
+ const fpResolved = path.resolve(exports.config.root_path, filePath)
514
519
 
515
- log.info(`Generating a 2048 bit dhparams file at ${fpResolved}`);
520
+ log.info(`Generating a 2048 bit dhparams file at ${fpResolved}`)
516
521
 
517
- const o = spawn('openssl', ['dhparam', '-out', `${fpResolved}`, '2048']);
518
- o.stdout.on('data', data => {
522
+ const o = spawn('openssl', ['dhparam', '-out', `${fpResolved}`, '2048'])
523
+ o.stdout.on('data', (data) => {
519
524
  // normally empty output
520
- log.debug(data);
525
+ log.debug(data)
521
526
  })
522
527
 
523
- o.stderr.on('data', data => {
528
+ o.stderr.on('data', (data) => {
524
529
  // this is the status gibberish `openssl dhparam` spews as it works
525
530
  })
526
531
 
527
- o.on('close', code => {
532
+ o.on('close', (code) => {
528
533
  if (code !== 0) {
529
- return done(`Error code: ${code}`);
534
+ return done(`Error code: ${code}`)
530
535
  }
531
536
 
532
- log.info(`Saved to ${fpResolved}`);
533
- const content = this.config.get(filePath, 'binary');
537
+ log.info(`Saved to ${fpResolved}`)
538
+ const content = this.config.get(filePath, 'binary')
534
539
 
535
540
  certsByHost.set('*.dhparam', content)
536
- done(null, certsByHost['*'].dhparam);
537
- });
541
+ done(null, certsByHost['*'].dhparam)
542
+ })
538
543
  }
539
544
 
540
- exports.addOCSP = server => {
545
+ exports.addOCSP = (server) => {
541
546
  if (!ocsp) {
542
- log.debug(`addOCSP: 'ocsp' not available`);
543
- return;
547
+ log.debug(`addOCSP: 'ocsp' not available`)
548
+ return
544
549
  }
545
550
 
546
551
  if (server.listenerCount('OCSPRequest') > 0) {
547
- log.debug('OCSPRequest already listening');
548
- return;
552
+ log.debug('OCSPRequest already listening')
553
+ return
549
554
  }
550
555
 
551
- log.debug('adding OCSPRequest listener');
556
+ log.debug('adding OCSPRequest listener')
552
557
  server.on('OCSPRequest', (cert, issuer, ocr_cb) => {
553
- log.debug(`OCSPRequest: ${cert}`);
558
+ log.debug(`OCSPRequest: ${cert}`)
554
559
  ocsp.getOCSPURI(cert, async (err, uri) => {
555
- log.debug(`OCSP Request, URI: ${uri}, err=${err}`);
556
- if (err) return ocr_cb(err);
557
- if (uri === null) return ocr_cb(); // not working OCSP server
560
+ log.debug(`OCSP Request, URI: ${uri}, err=${err}`)
561
+ if (err) return ocr_cb(err)
562
+ if (uri === null) return ocr_cb() // not working OCSP server
558
563
 
559
- const req = ocsp.request.generate(cert, issuer);
564
+ const req = ocsp.request.generate(cert, issuer)
560
565
  const cached = await ocspCache.probe(req.id)
561
566
 
562
567
  if (cached) {
563
- log.debug(`OCSP cache: ${util.inspect(cached)}`);
564
- return ocr_cb(null, cached.response);
568
+ log.debug(`OCSP cache: ${util.inspect(cached)}`)
569
+ return ocr_cb(null, cached.response)
565
570
  }
566
571
 
567
572
  const options = {
568
573
  url: uri,
569
- ocsp: req.data
570
- };
574
+ ocsp: req.data,
575
+ }
571
576
 
572
- log.debug(`OCSP req:${util.inspect(req)}`);
573
- ocspCache.request(req.id, options, ocr_cb);
577
+ log.debug(`OCSP req:${util.inspect(req)}`)
578
+ ocspCache.request(req.id, options, ocr_cb)
574
579
  })
575
580
  })
576
581
  }
577
582
 
578
583
  exports.shutdown = () => {
579
- if (ocsp) cleanOcspCache();
584
+ if (ocsp) cleanOcspCache()
580
585
  }
581
586
 
582
- function cleanOcspCache () {
583
- log.debug(`Cleaning ocspCache. How many keys? ${Object.keys(ocspCache.cache).length}`);
587
+ function cleanOcspCache() {
588
+ log.debug(`Cleaning ocspCache. How many keys? ${Object.keys(ocspCache.cache).length}`)
584
589
  Object.keys(ocspCache.cache).forEach((key) => {
585
- clearTimeout(ocspCache.cache[key].timer);
586
- });
590
+ clearTimeout(ocspCache.cache[key].timer)
591
+ })
587
592
  }
588
593
 
589
- exports.certsByHost = certsByHost;
590
- exports.ocsp = ocsp;
594
+ exports.certsByHost = certsByHost
595
+ exports.ocsp = ocsp
591
596
 
592
597
  exports.get_rejectUnauthorized = (rejectUnauthorized, port, port_list) => {
593
598
  // console.log(`rejectUnauthorized: ${rejectUnauthorized}, port ${port}, list: ${port_list}`)
594
599
 
595
- if (rejectUnauthorized) return true;
600
+ if (rejectUnauthorized) return true
596
601
 
597
- return !!(port_list.includes(port));
602
+ return !!port_list.includes(port)
598
603
  }
599
604
 
600
- function createServer (cb) {
601
- const server = net.createServer(cryptoSocket => {
602
-
603
- const socket = new pluggableStream(cryptoSocket);
605
+ function createServer(cb) {
606
+ const server = net.createServer((cryptoSocket) => {
607
+ const socket = new pluggableStream(cryptoSocket)
604
608
 
605
- exports.addOCSP(server);
609
+ exports.addOCSP(server)
606
610
 
607
- socket.upgrade = cb2 => {
608
- log.debug('Upgrading to TLS');
611
+ socket.upgrade = (cb2) => {
612
+ log.debug('Upgrading to TLS')
609
613
 
610
- socket.clean();
614
+ socket.clean()
611
615
 
612
- cryptoSocket.removeAllListeners('data');
616
+ cryptoSocket.removeAllListeners('data')
613
617
 
614
- const options = Object.assign({}, certsByHost['*']);
615
- options.server = server; // TLSSocket needs server for SNI to work
618
+ const options = Object.assign({}, certsByHost['*'])
619
+ options.server = server // TLSSocket needs server for SNI to work
616
620
 
617
- options.rejectUnauthorized = exports.get_rejectUnauthorized(options.rejectUnauthorized, cryptoSocket.localPort, exports.cfg.main.requireAuthorized);
621
+ options.rejectUnauthorized = exports.get_rejectUnauthorized(
622
+ options.rejectUnauthorized,
623
+ cryptoSocket.localPort,
624
+ exports.cfg.main.requireAuthorized,
625
+ )
618
626
 
619
- const cleartext = new tls.TLSSocket(cryptoSocket, options);
627
+ const cleartext = new tls.TLSSocket(cryptoSocket, options)
620
628
 
621
- pipe(cleartext, cryptoSocket);
629
+ pipe(cleartext, cryptoSocket)
622
630
 
623
631
  cleartext
624
- .on('error', exception => {
625
- exception.source = 'tls';
626
- socket.emit('error', exception);
632
+ .on('error', (exception) => {
633
+ exception.source = 'tls'
634
+ socket.emit('error', exception)
627
635
  })
628
636
  .on('secure', () => {
629
- log.debug('TLS secured.');
630
- socket.emit('secure');
631
- const cipher = cleartext.getCipher();
632
- cipher.version = cleartext.getProtocol();
633
- if (cb2) cb2(
634
- cleartext.authorized,
635
- cleartext.authorizationError,
636
- cleartext.getPeerCertificate(),
637
- cipher
638
- );
637
+ log.debug('TLS secured.')
638
+ socket.emit('secure')
639
+ const cipher = cleartext.getCipher()
640
+ cipher.version = cleartext.getProtocol()
641
+ if (cb2)
642
+ cb2(cleartext.authorized, cleartext.authorizationError, cleartext.getPeerCertificate(), cipher)
639
643
  })
640
644
 
641
- socket.cleartext = cleartext;
645
+ socket.cleartext = cleartext
642
646
 
643
647
  if (socket._timeout) {
644
- cleartext.setTimeout(socket._timeout);
648
+ cleartext.setTimeout(socket._timeout)
645
649
  }
646
650
 
647
- cleartext.setKeepAlive(socket._keepalive);
651
+ cleartext.setKeepAlive(socket._keepalive)
648
652
 
649
- socket.attach(socket.cleartext);
650
- };
653
+ socket.attach(socket.cleartext)
654
+ }
651
655
 
652
- cb(socket);
653
- });
656
+ cb(socket)
657
+ })
654
658
 
655
- return server;
659
+ return server
656
660
  }
657
661
 
658
- function getCertFor (host) {
659
- if (host && certsByHost[host]) return certsByHost[host];
660
- return certsByHost['*']; // the default TLS cert
662
+ function getCertFor(host) {
663
+ if (host && certsByHost[host]) return certsByHost[host]
664
+ return certsByHost['*'] // the default TLS cert
661
665
  }
662
666
 
663
- function connect (conn_options = {}) {
664
- // called by outbound/client_pool, smtp_client, plugins/spamassassin,avg,clamd
667
+ function connect(conn_options = {}) {
668
+ // called by outbound/client_pool, smtp_client, plugins/spamassassin,avg,clamd,
669
+ // plugins/auth/auth_proxy
665
670
 
666
- const cryptoSocket = net.connect(conn_options);
667
- const socket = new pluggableStream(cryptoSocket);
671
+ const cryptoSocket = net.connect(conn_options)
672
+ const socket = new pluggableStream(cryptoSocket)
668
673
 
669
674
  socket.upgrade = (options, cb2) => {
670
- socket.clean();
671
- cryptoSocket.removeAllListeners('data');
675
+ socket.clean()
676
+ cryptoSocket.removeAllListeners('data')
672
677
 
673
678
  if (exports.tls_valid) {
674
679
  const host = conn_options.host
675
- if (exports.cfg === undefined) exports.load_tls_ini();
680
+ if (exports.cfg === undefined) exports.load_tls_ini()
676
681
  if (exports.cfg.mutual_auth_hosts[host]) {
677
- options = Object.assign(options, getCertFor(exports.cfg.mutual_auth_hosts[host]));
678
- }
679
- else if (exports.cfg.mutual_auth_hosts_exclude[host]) {
682
+ options = Object.assign(options, getCertFor(exports.cfg.mutual_auth_hosts[host]))
683
+ } else if (exports.cfg.mutual_auth_hosts_exclude[host]) {
680
684
  // send no client cert
681
- }
682
- else if (exports.cfg.main.mutual_tls) {
683
- options = Object.assign(options, getCertFor(host));
685
+ } else if (exports.cfg.main.mutual_tls) {
686
+ options = Object.assign(options, getCertFor(host))
684
687
  }
685
688
  }
686
- options.socket = cryptoSocket;
689
+ options.socket = cryptoSocket
687
690
 
688
- const cleartext = new tls.connect(options);
691
+ const cleartext = new tls.connect(options)
689
692
 
690
- pipe(cleartext, cryptoSocket);
693
+ pipe(cleartext, cryptoSocket)
691
694
 
692
- cleartext.on('error', err => {
693
- if (err.reason) log.error(`client TLS error: ${err}`);
695
+ cleartext.on('error', (err) => {
696
+ if (err.reason) log.error(`client TLS error: ${err}`)
694
697
  })
695
698
 
696
699
  cleartext.once('secureConnect', () => {
697
- log.debug('client TLS secured.');
698
- const cipher = cleartext.getCipher();
699
- cipher.version = cleartext.getProtocol();
700
- if (cb2) cb2(
701
- cleartext.authorized,
702
- cleartext.authorizationError,
703
- cleartext.getPeerCertificate(),
704
- cipher
705
- );
706
- });
707
-
708
- socket.cleartext = cleartext;
700
+ log.debug('client TLS secured.')
701
+ const cipher = cleartext.getCipher()
702
+ cipher.version = cleartext.getProtocol()
703
+ if (cb2) cb2(cleartext.authorized, cleartext.authorizationError, cleartext.getPeerCertificate(), cipher)
704
+ })
705
+
706
+ socket.cleartext = cleartext
709
707
 
710
708
  if (socket._timeout) {
711
- cleartext.setTimeout(socket._timeout);
709
+ cleartext.setTimeout(socket._timeout)
712
710
  }
713
711
 
714
- cleartext.setKeepAlive(socket._keepalive);
712
+ cleartext.setKeepAlive(socket._keepalive)
715
713
 
716
- socket.attach(socket.cleartext);
714
+ socket.attach(socket.cleartext)
717
715
 
718
- log.debug('client TLS upgrade in progress, awaiting secured.');
716
+ log.debug('client TLS upgrade in progress, awaiting secured.')
719
717
  }
720
718
 
721
- return socket;
719
+ return socket
722
720
  }
723
721
 
724
- exports.connect = connect;
725
- exports.createConnection = connect;
726
- exports.Server = createServer;
727
- exports.createServer = createServer;
722
+ exports.connect = connect
723
+ exports.createConnection = connect
724
+ exports.Server = createServer
725
+ exports.createServer = createServer