Haraka 3.1.2 → 3.1.4

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 (66) hide show
  1. package/.prettierignore +2 -0
  2. package/CONTRIBUTORS.md +24 -2
  3. package/Changes.md +48 -0
  4. package/Plugins.md +81 -64
  5. package/README.md +1 -1
  6. package/bin/haraka +9 -7
  7. package/config/connection.ini +10 -0
  8. package/config/smtp.ini +0 -9
  9. package/connection.js +15 -19
  10. package/docs/CoreConfig.md +2 -3
  11. package/docs/Plugins.md +1 -1
  12. package/docs/plugins/aliases.md +0 -2
  13. package/docs/plugins/queue/qmail-queue.md +0 -1
  14. package/docs/tutorials/Migrating_from_v1_to_v2.md +1 -1
  15. package/logger.js +2 -2
  16. package/outbound/client_pool.js +1 -1
  17. package/outbound/hmail.js +76 -83
  18. package/outbound/index.js +36 -34
  19. package/outbound/queue.js +231 -176
  20. package/package.json +29 -31
  21. package/plugins/prevent_credential_leaks.js +2 -2
  22. package/plugins/process_title.js +1 -1
  23. package/plugins/queue/smtp_forward.js +1 -1
  24. package/plugins/status.js +8 -5
  25. package/plugins/tls.js +1 -1
  26. package/plugins.js +19 -14
  27. package/rfc1869.js +10 -10
  28. package/run_tests +20 -2
  29. package/server.js +15 -10
  30. package/smtp_client.js +2 -9
  31. package/test/config/tls/haraka.local.pem +47 -47
  32. package/test/connection.js +286 -147
  33. package/test/fixtures/line_socket.js +1 -0
  34. package/test/fixtures/util_hmailitem.js +1 -1
  35. package/test/outbound/bounce_net_errors.js +176 -0
  36. package/test/outbound/bounce_rfc3464.js +303 -0
  37. package/test/outbound/hmail.js +140 -104
  38. package/test/outbound/index.js +61 -101
  39. package/test/outbound/qfile.js +25 -25
  40. package/test/outbound/queue.js +233 -0
  41. package/test/plugins/queue/smtp_forward.js +1 -1
  42. package/test/plugins/record_envelope_addresses.js +93 -0
  43. package/test/plugins/tls.js +2 -2
  44. package/test/plugins/xclient.js +137 -0
  45. package/test/rfc1869.js +43 -0
  46. package/test/smtp_client.js +6 -6
  47. package/test/transaction.js +486 -201
  48. package/tls_socket.js +3 -3
  49. package/transaction.js +33 -10
  50. package/config/me +0 -1
  51. package/config/rabbitmq.ini +0 -10
  52. package/config/rabbitmq_amqplib.ini +0 -19
  53. package/config/tls_cert.pem +0 -23
  54. package/config/tls_key.pem +0 -28
  55. package/docs/plugins/queue/rabbitmq.md +0 -34
  56. package/docs/plugins/queue/rabbitmq_amqplib.md +0 -51
  57. package/plugins/queue/rabbitmq.js +0 -141
  58. package/plugins/queue/rabbitmq_amqplib.js +0 -96
  59. package/test/config/tls/ec.pem +0 -23
  60. package/test/config/tls/mismatched.pem +0 -49
  61. package/test/outbound_bounce_net_errors.js +0 -157
  62. package/test/outbound_bounce_rfc3464.js +0 -366
  63. package/test/queue/multibyte +0 -0
  64. package/test/queue/plain +0 -0
  65. package/test/test-queue/delete-me +0 -0
  66. package/test/tls_socket.js +0 -273
package/package.json CHANGED
@@ -9,7 +9,7 @@
9
9
  "server",
10
10
  "email"
11
11
  ],
12
- "version": "3.1.2",
12
+ "version": "3.1.4",
13
13
  "homepage": "http://haraka.github.io",
14
14
  "repository": {
15
15
  "type": "git",
@@ -20,49 +20,47 @@
20
20
  "node": ">=20"
21
21
  },
22
22
  "dependencies": {
23
- "address-rfc2821": "^2.1.3",
23
+ "address-rfc2821": "^2.1.5",
24
24
  "address-rfc2822": "^2.2.3",
25
- "async": "^3.2.6",
26
25
  "daemon": "~1.1.0",
27
- "haraka-config": "^1.4.2",
26
+ "haraka-config": "^1.5.0",
28
27
  "haraka-constants": "^1.0.7",
29
28
  "haraka-dsn": "^1.1.0",
30
- "haraka-email-message": "^1.2.6",
31
- "haraka-message-stream": "^1.3.2",
29
+ "haraka-email-message": "^1.3.1",
30
+ "haraka-message-stream": "^2.0.0",
32
31
  "haraka-net-utils": "^1.7.2",
33
32
  "haraka-notes": "^1.1.1",
34
33
  "haraka-plugin-redis": "^2.0.11",
35
- "haraka-results": "^2.2.6",
36
- "haraka-tld": "^1.2.4",
34
+ "haraka-results": "^2.3.0",
35
+ "haraka-tld": "^1.3.1",
37
36
  "haraka-utils": "^1.1.4",
38
37
  "ipaddr.js": "~2.3.0",
39
- "node-gyp": "^12.1.0",
38
+ "node-gyp": "^12.2.0",
40
39
  "nopt": "^9.0.0",
41
40
  "npid": "~0.4.0",
42
- "redis": "~5.10.0",
43
- "semver": "^7.7.3",
41
+ "redis": "~5.11.0",
42
+ "semver": "^7.7.4",
44
43
  "sockaddr": "^1.0.1",
45
44
  "sprintf-js": "~1.1.3"
46
45
  },
47
46
  "optionalDependencies": {
48
47
  "haraka-plugin-access": "^1.1.10",
49
48
  "haraka-plugin-aliases": "^1.0.3",
50
- "haraka-plugin-asn": "^2.0.5",
51
- "haraka-plugin-attachment": "^1.1.5",
49
+ "haraka-plugin-asn": "^2.0.6",
50
+ "haraka-plugin-attachment": "^1.2.0",
52
51
  "haraka-plugin-avg": "^1.1.0",
53
- "haraka-plugin-bounce": "^2.1.1",
52
+ "haraka-plugin-bounce": "^2.1.2",
54
53
  "haraka-plugin-clamd": "^1.0.2",
55
54
  "haraka-plugin-dcc": "^1.0.3",
56
55
  "haraka-plugin-dkim": "^1.0.11",
57
56
  "haraka-plugin-dns-list": "^1.2.4",
58
57
  "haraka-plugin-early_talker": "^1.0.2",
59
- "haraka-plugin-elasticsearch": "^8.1.5",
58
+ "haraka-plugin-elasticsearch": "^8.1.6",
60
59
  "haraka-plugin-esets": "^1.0.1",
61
60
  "haraka-plugin-fcrdns": "^1.1.2",
62
- "haraka-plugin-geoip": "^1.1.1",
63
- "haraka-plugin-graph": "^1.0.5",
64
- "haraka-plugin-greylist": "^1.0.1",
65
- "haraka-plugin-headers": "^1.0.6",
61
+ "haraka-plugin-geoip": "^1.1.2",
62
+ "haraka-plugin-greylist": "^1.1.0",
63
+ "haraka-plugin-headers": "^1.1.0",
66
64
  "haraka-plugin-helo.checks": "^1.1.0",
67
65
  "haraka-plugin-karma": "^2.1.8",
68
66
  "haraka-plugin-known-senders": "^1.1.3",
@@ -70,23 +68,23 @@
70
68
  "haraka-plugin-mail_from.is_resolvable": "^1.1.0",
71
69
  "haraka-plugin-messagesniffer": "^1.0.1",
72
70
  "haraka-plugin-p0f": "^1.0.11",
73
- "haraka-plugin-qmail-deliverable": "^1.2.5",
71
+ "haraka-plugin-qmail-deliverable": "^1.3.2",
74
72
  "haraka-plugin-recipient-routes": "^1.3.1",
75
73
  "haraka-plugin-relay": "^1.0.1",
76
74
  "haraka-plugin-rspamd": "^1.4.2",
77
75
  "haraka-plugin-spamassassin": "^1.0.3",
78
- "haraka-plugin-spf": "^1.2.10",
76
+ "haraka-plugin-spf": "^1.2.11",
79
77
  "haraka-plugin-syslog": "^1.0.7",
80
78
  "haraka-plugin-uribl": "^1.0.10",
81
- "haraka-plugin-watch": "^2.0.8",
79
+ "haraka-plugin-watch": "^2.0.9",
82
80
  "@techteamer/ocsp": "^1.0.1"
83
81
  },
84
82
  "devDependencies": {
85
- "@haraka/eslint-config": "^2.0.3",
86
- "haraka-test-fixtures": "^1.3.10",
83
+ "@haraka/eslint-config": "^2.0.4",
84
+ "haraka-test-fixtures": "^1.4.1",
87
85
  "mocha": "^11.7.5",
88
86
  "mock-require": "^3.0.3",
89
- "nodemailer": "^7.0.12"
87
+ "nodemailer": "^8.0.4"
90
88
  },
91
89
  "bugs": {
92
90
  "mail": "haraka.mail@gmail.com",
@@ -97,19 +95,19 @@
97
95
  "haraka_grep": "./bin/haraka_grep"
98
96
  },
99
97
  "scripts": {
100
- "format:NYET": "npm run prettier:fix && npm run lint:fix",
98
+ "format": "npm run prettier:fix && npm run lint:fix",
101
99
  "lint": "npx eslint *.js outbound plugins plugins/*/*.js test test/*/*.js test/*/*/*.js bin/haraka",
102
100
  "lint:fix": "npx eslint --fix *.js outbound plugins plugins/*/*.js test test/*/*.js test/*/*/*.js bin/haraka",
103
101
  "prettier": "npx prettier . --check",
104
102
  "prettier:fix": "npx prettier . --write --log-level=warn",
105
- "test": "npx mocha --exit --timeout=4000 test test/outbound test/plugins/auth test/plugins/queue test/plugins",
106
- "versions": "npx dependency-version-checker check",
107
- "versions:fix": "npx dependency-version-checker update",
108
- "format": "npm run prettier:fix && npm run lint:fix"
103
+ "test": "sh ./run_tests",
104
+ "versions": "npx npm-dep-mgr check",
105
+ "versions:fix": "npx npm-dep-mgr update",
106
+ "test:coverage": "npx c8 --reporter=text --reporter=text-summary npm test"
109
107
  },
110
108
  "prettier": {
111
109
  "singleQuote": true,
112
110
  "printWidth": 120,
113
111
  "semi": false
114
112
  }
115
- }
113
+ }
@@ -25,8 +25,8 @@ exports.hook_data_post = (next, connection) => {
25
25
  if (idx) {
26
26
  // If the username is qualified (e.g. user@domain.com)
27
27
  // then we make the @domain.com part optional in the regexp.
28
- domain = user.substr(idx)
29
- user = user.substr(0, idx)
28
+ domain = user.substring(idx)
29
+ user = user.substring(0, idx)
30
30
  }
31
31
  const passwd = connection.notes.auth_passwd
32
32
  const bound_regexp = '(?:\\b|\\B)'
@@ -1,6 +1,6 @@
1
1
  // process_title
2
2
 
3
- const outbound = require('./outbound')
3
+ const outbound = require('../outbound')
4
4
 
5
5
  function setupInterval(title, server) {
6
6
  // Set up a timer to update title
@@ -6,7 +6,7 @@
6
6
 
7
7
  const url = require('node:url')
8
8
 
9
- const smtp_client_mod = require('./smtp_client')
9
+ const smtp_client_mod = require('../../smtp_client')
10
10
 
11
11
  exports.register = function () {
12
12
  this.load_errs = []
package/plugins/status.js CHANGED
@@ -92,8 +92,9 @@ exports.pool_list = (cb) => {
92
92
  cb(null, result)
93
93
  }
94
94
 
95
- exports.queue_list = function (cb) {
96
- this.outbound.list_queue((err, qlist = []) => {
95
+ exports.queue_list = async function (cb) {
96
+ try {
97
+ const qlist = await this.outbound.list_queue()
97
98
  const result = []
98
99
 
99
100
  for (const todo of qlist) {
@@ -107,8 +108,10 @@ exports.queue_list = function (cb) {
107
108
  })
108
109
  }
109
110
 
110
- cb(err, result)
111
- })
111
+ cb(null, result)
112
+ } catch (err) {
113
+ cb(err)
114
+ }
112
115
  }
113
116
 
114
117
  exports.queue_stats = function (cb) {
@@ -116,7 +119,7 @@ exports.queue_stats = function (cb) {
116
119
  }
117
120
 
118
121
  exports.queue_inspect = function (cb) {
119
- const delivery_queue_items = this.outbound.delivery_queue._tasks.toArray()
122
+ const delivery_queue_items = this.outbound.delivery_queue.tasks
120
123
  const fail_queue_items = this.outbound.temp_fail_queue.queue
121
124
 
122
125
  cb(null, {
package/plugins/tls.js CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  /* global server */
6
6
 
7
- const tls_socket = require('./tls_socket')
7
+ const tls_socket = require('../tls_socket')
8
8
 
9
9
  // exported so tests can override config dir
10
10
  exports.net_utils = require('haraka-net-utils')
package/plugins.js CHANGED
@@ -33,10 +33,6 @@ class Plugin {
33
33
  return require(`./${name}`)
34
34
  }
35
35
 
36
- core_require(name) {
37
- return this.haraka_require(name)
38
- }
39
-
40
36
  _get_plugin_path() {
41
37
  /* From https://github.com/haraka/Haraka/pull/1278#issuecomment-168856528
42
38
  In Development mode, or install via a plain "git clone":
@@ -56,13 +52,13 @@ class Plugin {
56
52
  */
57
53
 
58
54
  this.hasPackageJson = false
59
- const name = this.name.startsWith('haraka-plugin-') ? this.name.substr(14) : this.name
55
+ const name = this.name.startsWith('haraka-plugin-') ? this.name.slice(14) : this.name
60
56
  if (this.name !== name) this.name = name
61
57
 
62
58
  let paths = []
63
59
  if (process.env.HARAKA) {
64
60
  // Installed mode - started via bin/haraka
65
- paths = paths.concat(plugin_search_paths(process.env.HARAKA, name))
61
+ paths = [...paths, ...plugin_search_paths(process.env.HARAKA, name)]
66
62
 
67
63
  // permit local "folder" plugins (/$name/package.json) (see #1649)
68
64
  paths.push(
@@ -72,7 +68,7 @@ class Plugin {
72
68
  }
73
69
 
74
70
  // development mode
75
- paths = paths.concat(plugin_search_paths(__dirname, name))
71
+ paths = [...paths, ...plugin_search_paths(__dirname, name)]
76
72
  for (const pp of paths) {
77
73
  if (this.plugin_path) continue
78
74
  try {
@@ -91,11 +87,13 @@ class Plugin {
91
87
  // haraka/config folder for overrides
92
88
  return exports.config.module_config(path.dirname(this.plugin_path), process.env.HARAKA || __dirname)
93
89
  }
90
+
94
91
  if (process.env.HARAKA) {
95
92
  // Plain .js file, installed mode - look in core folder for defaults,
96
93
  // install dir for overrides
97
94
  return exports.config.module_config(__dirname, process.env.HARAKA)
98
95
  }
96
+
99
97
  if (process.env.HARAKA_TEST_DIR) {
100
98
  return exports.config.module_config(process.env.HARAKA_TEST_DIR)
101
99
  }
@@ -158,17 +156,19 @@ class Plugin {
158
156
  return require(module)
159
157
  }
160
158
 
161
- if (fs.existsSync(path.join(__dirname, `${module}.js`)) || fs.existsSync(path.join(__dirname, module))) {
162
- return require(module)
159
+ for (const ext of [`${module}.js`, module]) {
160
+ if (fs.existsSync(path.join(__dirname, ext))) {
161
+ return require(module)
162
+ }
163
163
  }
164
164
 
165
165
  return require(path.join(path.dirname(this.plugin_path), module))
166
166
  }
167
167
  }
168
168
 
169
- _get_code(pp) {
169
+ _get_code(pi_path) {
170
170
  if (this.hasPackageJson) {
171
- let packageDir = path.dirname(pp)
171
+ let packageDir = path.dirname(pi_path)
172
172
  if (/^win(32|64)/.test(process.platform)) {
173
173
  // escape the c:\path\back\slashes else they disappear
174
174
  packageDir = packageDir.replace(/\\/g, '\\\\')
@@ -177,7 +177,7 @@ class Plugin {
177
177
  }
178
178
 
179
179
  try {
180
- return `"use strict";${fs.readFileSync(pp)}`
180
+ return `"use strict";${fs.readFileSync(pi_path)}`
181
181
  } catch (err) {
182
182
  if (exports.config.get('smtp.ini').main.ignore_bad_plugins) {
183
183
  plugins.logcrit(`Loading ${this.name} failed: ${err}`)
@@ -241,8 +241,13 @@ process.on('message', (msg) => {
241
241
 
242
242
  function plugin_search_paths(prefix, name) {
243
243
  return [
244
+ // Haraka/plugins/*.js
244
245
  path.resolve(prefix, 'plugins', `${name}.js`),
246
+
247
+ // Haraka/node_modules/haraka-plugin-*/package.json
245
248
  path.resolve(prefix, 'node_modules', `haraka-plugin-${name}`, 'package.json'),
249
+
250
+ // global node_modules/haraka-plugin-*/package.json
246
251
  path.resolve(prefix, '..', `haraka-plugin-${name}`, 'package.json'),
247
252
  ]
248
253
  }
@@ -281,7 +286,7 @@ plugins.load_plugins = (override) => {
281
286
  }
282
287
 
283
288
  for (let plugin of plugin_list) {
284
- if (plugin.startsWith('haraka-plugin-')) plugin = plugin.substr(14)
289
+ if (plugin.startsWith('haraka-plugin-')) plugin = plugin.substring(14)
285
290
  if (plugins.deprecated[plugin]) {
286
291
  plugins.lognotice(
287
292
  `${plugin} has been replaced by '${plugins.deprecated[plugin]}'. Please update config/plugins`,
@@ -467,7 +472,7 @@ plugins.run_next_hook = (hook, object, params) => {
467
472
  }
468
473
 
469
474
  const respond_method = `${hook}_respond`
470
- if (item && is_deny_retval(retval) && hook.substr(0, 5) !== 'init_') {
475
+ if (item && is_deny_retval(retval) && hook.substring(0, 5) !== 'init_') {
471
476
  object.deny_respond = get_denyfn(object, hook, params, retval, msg, respond_method)
472
477
  plugins.run_hooks('deny', object, [retval, msg, item[0].name, item[1], params, hook])
473
478
  } else {
package/rfc1869.js CHANGED
@@ -33,7 +33,7 @@ exports.parse = (type, line, strict) => {
33
33
 
34
34
  while (1) {
35
35
  const old_length = line.length
36
- line = line.replace(chew_regexp, function repl(str, p1) {
36
+ line = line.replace(chew_regexp, (str, p1) => {
37
37
  params.push(p1)
38
38
  return ''
39
39
  })
@@ -73,17 +73,17 @@ exports.parse = (type, line, strict) => {
73
73
  throw new Error('Syntax error in parameters')
74
74
  }
75
75
  } else {
76
- // console.log(`Looking at ${line}``);
76
+ // console.log(`Looking at ${line}`);
77
77
  if (line.match(/@.*\s/)) {
78
78
  throw new Error('Syntax error in parameters')
79
- } else {
80
- if (line.match(/\s/)) {
81
- throw new Error('Syntax error in parameters')
82
- } else if (line.match(/@/)) {
83
- if (!line.match(/^<.*>$/)) line = `<${line}>`
84
- } else if (!line.match(/^<(postmaster|abuse)>$/i)) {
85
- throw new Error(`Syntax error in address: ${line}`)
86
- }
79
+ }
80
+ if (line.match(/\s/)) {
81
+ throw new Error('Syntax error in parameters')
82
+ }
83
+ if (line.match(/@/)) {
84
+ if (!line.match(/^<.*>$/)) line = `<${line}>`
85
+ } else if (!line.match(/^<(postmaster|abuse)>$/i)) {
86
+ throw new Error(`Syntax error in address: ${line}`)
87
87
  }
88
88
  }
89
89
 
package/run_tests CHANGED
@@ -1,5 +1,23 @@
1
1
  #!/bin/sh
2
2
 
3
- TESTS=${1:-"test test/outbound test/plugins/auth test/plugins/queue test/plugins"}
3
+ # Files using node:test
4
+ NODE_TEST_FILES="test/transaction.js test/connection.js test/outbound/*.js"
4
5
 
5
- npx mocha --exit $TESTS
6
+ # Mocha scans test/ but skips transaction.js, connection.js, and outbound/
7
+ MOCHA_IGNORE="--ignore=test/transaction.js --ignore=test/connection.js"
8
+ MOCHA_TESTS="test test/plugins/auth test/plugins/queue test/plugins"
9
+
10
+ if [ -n "$1" ]; then
11
+ case "$1" in
12
+ test/transaction.js | test/connection.js | test/outbound/*)
13
+ node --test "$1"
14
+ ;;
15
+ *)
16
+ npx mocha --exit --timeout=4000 "$1"
17
+ ;;
18
+ esac
19
+ else
20
+ # default, run 'em all
21
+ node --test --test-concurrency=1 $NODE_TEST_FILES && \
22
+ npx mocha --exit --timeout=4000 $MOCHA_IGNORE $MOCHA_TESTS
23
+ fi
package/server.js CHANGED
@@ -92,9 +92,9 @@ Server.daemonize = function () {
92
92
  }
93
93
  }
94
94
 
95
- Server.flushQueue = (domain) => {
95
+ Server.flushQueue = async (domain) => {
96
96
  if (!Server.cluster) {
97
- outbound.flush_queue(domain)
97
+ await outbound.flush_queue(domain)
98
98
  return
99
99
  }
100
100
 
@@ -506,7 +506,7 @@ Server.setup_http_listeners = async () => {
506
506
  app.use(Server.handle404)
507
507
  }
508
508
 
509
- Server.init_master_respond = (retval, msg) => {
509
+ Server.init_master_respond = async (retval, msg) => {
510
510
  if (!(retval === constants.ok || retval === constants.cont)) {
511
511
  Server.logerror(`init_master returned error${msg ? `: ${msg}` : ''}`)
512
512
  return logger.dump_and_exit(1)
@@ -517,18 +517,20 @@ Server.init_master_respond = (retval, msg) => {
517
517
 
518
518
  // Load the queue if we're just one process
519
519
  if (!(cluster && c.nodes)) {
520
- outbound.load_queue()
520
+ try {
521
+ await outbound.init_queue()
522
+ } catch (err) {
523
+ Server.logcrit('Loading queue failed. Shutting down.')
524
+ return logger.dump_and_exit(1)
525
+ }
521
526
  Server.setup_http_listeners()
522
527
  return
523
528
  }
524
529
 
525
530
  // Running under cluster, fork children here, so that
526
531
  // cluster events can be registered in init_master hooks.
527
- outbound.scan_queue_pids((err, pids) => {
528
- if (err) {
529
- Server.logcrit('Scanning queue failed. Shutting down.')
530
- return logger.dump_and_exit(1)
531
- }
532
+ try {
533
+ const pids = await outbound.scan_queue_pids()
532
534
  Server.daemonize()
533
535
  // Fork workers
534
536
  const workers = c.nodes === 'cpus' ? os.cpus().length : c.nodes
@@ -552,7 +554,10 @@ Server.init_master_respond = (retval, msg) => {
552
554
  Server.lognotice(`worker ${worker.id} listening on ${endpoint(address)}`)
553
555
  })
554
556
  cluster.on('exit', cluster_exit_listener)
555
- })
557
+ } catch (err) {
558
+ Server.logcrit('Scanning queue failed. Shutting down.')
559
+ logger.dump_and_exit(1)
560
+ }
556
561
  }
557
562
 
558
563
  function cluster_exit_listener(worker, code, signal) {
package/smtp_client.js CHANGED
@@ -192,13 +192,8 @@ class SMTPClient extends events.EventEmitter {
192
192
  client.socket.on('end', closed('ended'))
193
193
  }
194
194
 
195
- load_tls_config(opts) {
196
- const tls_options = { servername: this.host }
197
- if (opts) {
198
- Object.assign(tls_options, opts)
199
- }
200
-
201
- this.tls_options = tls_options
195
+ load_tls_config(opts = {}) {
196
+ this.tls_options = { servername: this.host, ...opts }
202
197
  }
203
198
 
204
199
  send_command(command, data) {
@@ -212,10 +207,8 @@ class SMTPClient extends events.EventEmitter {
212
207
  start_data(data) {
213
208
  this.response = []
214
209
  this.command = 'dot'
215
- // SUNSET: dot_stuffing was renamed to dot_stuffed, remove it after 2026-01
216
210
  data.pipe(this.socket, {
217
211
  dot_stuffed: false,
218
- dot_stuffing: true,
219
212
  ending_dot: true,
220
213
  end: false,
221
214
  })
@@ -1,51 +1,51 @@
1
1
  -----BEGIN PRIVATE KEY-----
2
- MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDcg5h5TVO1gECK
3
- yNCXbpJduNqJvhE6hyVb9q0WRR8zKHE7DnOog9JqOcrz4mv3TmszDZ2511mGxo/v
4
- j2dAYakU7HxEuSqKX1CsjbDP3xa7IvVCaKQbcMImq7dzmenXkCdPivuglZmooZen
5
- c18QZ6YkrunDeh/OcP8WAA+9yYXp82lmKPzKNkJETfGVXff0loXWR5SSjGXYvjqm
6
- XK6IXqPcuNriUTmylLx2149O6RWJPaZ2YYxTOHTeV5OMeEHjLpAOShCfZi4VYvAe
7
- GZSFq5UdMv5QD1k6BueS1Ruf6ChCLjfqkMcCAw8DOY8oxvzovgM/sgBcx3L00/pe
8
- QeSegG+3AgMBAAECggEAW9qJEcYvH0SMHgNmOB375ARTK9s7S/jti/Aly0gBpgqr
9
- l+D+NmyqokruikZ/mKVWrA546+eTSDu/yxcd+Eh16NxVKz9CRB9N+IKQ6xXPXyZB
10
- qWbzLOb8SKVwpjuvl3ZZmZ2YER0fw4mEJWE+cRPrtg4SG7XsN88DwoNGC1U9beSL
11
- vZ3lDuOMHNBNGx5k608i5HCV8Ty3Sz8ksvL9fPFwUpKAvRuG3lYgS+GxSrijH+KO
12
- vIwXAu3E+7MIPXdbsg14HBRRHEfyQlRGV8rj3e8neDLFarB8fXDVqIsko6/D5qZZ
13
- D/jXYW7pcafOGT0PTbHxUMrUxahhAjKKfPt3Y7JVcQKBgQDzIhmN7SbQvu2dl54X
14
- XezrgKteDVd4q7VYVpiAjNEZA+kNdBcXC6k2T5WMNPesNwyFIoDLDFWUg4FMG/Mc
15
- KA1eArBocGQ0gQvLlnlUxBy519e/AAj7jTspLi7gAwLqfTo0TGdTH/Hfq+1uCXys
16
- dd3BKYnDKc4aDPTQCEkRzfPHDwKBgQDoLw7MZecGnNNrqArqsOaOO1uUKFysW6pi
17
- 2ZU7KKj1x6vKGIW88YmzNBPCj4LU8XlXbR1isaSs5TaWgc6N0aAEXwA6TN/8PXhq
18
- 6IXarR1WJIq2DEDtdBrj2AiaPoF8Y6hsebsQs+EpyLx8MCGLaucYJvqyK87ep000
19
- mXQuyfgM2QKBgHCLy2qAaeRdTV8S7TKB3wcQ88LAyEnqqjJvO37eMHi076+zmnCn
20
- jDfA1UgmyLNmdBw44YeceQ0bZsHVek8BV1a6RfDCfhAz4ELor9eGRInemVcn7ACN
21
- 2uHwJ/C4VCQ5vbSx3W6ELhHM40Z5i8XFddZRpRy7gFVcxAJ8o15jiMIPAoGAHiq3
22
- DoGS8b4AjjVILdQMMKCvtmFEITTLv4orpIMU6NInlNt4zOLJFFqI0reYtRgmvuAz
23
- eDZCgiBJ5mY5Mx3wX4EEY47Hb1uBQMqzUYU6kY2v5BVVfkSelcnk3D2Qz1uXb3il
24
- gHcOo0IskyohwZ6DJhUyb2HXwAAWvOXPPaEKNIkCgYAqWhzYCAoxZ6f7i2I3J1JO
25
- 5OaMi4+9YR3ivTDcKVYp1ZOzANe0gsQlal/gf2fTjG35b9FyK3Lo5rp0QLKxv2vh
26
- 6dR+sk+58jJhk8H1kPNIVzvA4SAd51YoE0x7edi7+5vDMwlz57yz5rwMQvN1wUOO
27
- 5Ev9F9qrVJZFF4Ei+fRW9Q==
2
+ MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDCdI9wQHH4zJzr
3
+ Kjd4/a4AV8uPnvZwOHC/mhFnAS2V4+oPLgBZYG/yiktsmTcsYl3Cgf3n8X1eMsRl
4
+ i91kdC1+2txMsn/Y6DDAxW+qbYWIvWWPQlCr+eweGAYf3HkWAd3nAiKB1qfnUvL5
5
+ y0werjQFV9cAeK9xqtC7HqaTOYtNnAmipIGLK7y4RQfnzf20Qqu9yv3uC2Gaj3Vk
6
+ EhGFRaIvKxVmnvCmRYa8UM3HKtF4q+ApkoeslJjqK68vSXtDQFZ6qHatotWeYVzt
7
+ luX66f925pKBTU6AVJJQxrCWjQ/KLLLW7qbytaMjagz4IBpRNpb3Wfc7c7/51nDm
8
+ TyECGKMnAgMBAAECggEAFbpmiLl6wr1CT3ixKCDYf4tP4KV3jgSQfKhfh233RQdp
9
+ kPan7VS8TZKsaN8Z7iizp1dVIsS2KH9tuJcPTvk4WDNmaF+Nr5QKVo/5MUb5o9Td
10
+ 80sKrpzHiHlQveCp2w6sV/LCHlX4/v0iz0yrHcaDY5F0IcZafE4E8tOy80J70VkL
11
+ NmWb9bP5CKFs7bAknGzXSGonhOVH1Yf7WTE7OYGi5XfBoLWLozTzL19YKez6Je4m
12
+ KHlSzVSmXqmYgZ/48U+RIRp0m31zswAdvmkg6qGNr8F4kXcySDzhQjdeojIj8sho
13
+ MVy9dl+qjSxIBGDjmZz/MfySyEfJABJVf6anx3JE4QKBgQDuQi3x3w/utdtmfI4l
14
+ 9n1SsgB3uu/eNl/5LuWyQBKoKO1iyR86LfGo9nqbsiFtg72IfuCy1QSklm5ZVFqL
15
+ vyRb77YH1fbah0BM4JCj2JhKgJMPJTWJ3woC5tJu67nKO3W6yB9TjMOFFl1y41tl
16
+ NJuvoVUNZO1dYMtDJynLJ0GI8QKBgQDQ72EMozJTvS3VDGemXDimkyJyYGKyqV/f
17
+ KzCfW66lLUREPEYN6NaG49jwR/dQfPqBPtTQqLy/HA1ZYNeQR5QdeklQiRVWs0tn
18
+ /Nfbb1DkSPZWebX2o+hPVPUH5XVVZXOR89v8oKvajVE37hKhYK7fHxKgC8gY1zkP
19
+ H6kUD0atlwKBgG9RhF3ptmv1k9jCgTfDfrJQcF+Ae+n6xcSK4M7zmMPwu1jYVzq7
20
+ lJk47/gmte+RCdDoVtu3I0Ay+MPL4bJBUB+UVBw9H+TiJGzGz01+OUk14X/GBsmv
21
+ 5+GLLu6cPGX8efkW32wN7JwV4vt2tpEGj2bzneVwLmbefpmVhrVgVgJBAoGAD/WZ
22
+ BiwZFghnTdTKvgxhT2gBw5bVMyx45EUaS7HnHzrb8hJgj4Nvj5Ir6f61R3Kkd+bi
23
+ vqWE9VwhMOiSzrSI/c9vdjViaeL8KY9ItbxFA4sHNgfJ/HL8tcKZjObcFY/QSh/E
24
+ eAGV3vXYdFs9FRKbiPOIqqz7tdoKw7r5YUzhazUCgYBYWwvYgeccNBPeamROwt73
25
+ C1hWbjcrHhMRrB84vcM0j6EHIk689HJu7VobwJooQOALvyh7VSlD1b5V2DstsBiX
26
+ cD2uKAwdLlRJuThTxgq81qW4h8KnDpdFYrwFsevaA+r4c7ihy/2oeASY6SMqUC89
27
+ jAJOkfhhCdoj6D85HLIMNw==
28
28
  -----END PRIVATE KEY-----
29
29
  -----BEGIN CERTIFICATE-----
30
- MIIDzzCCAregAwIBAgIJAOa6xwibkwczMA0GCSqGSIb3DQEBCwUAMH4xCzAJBgNV
31
- BAYTAlVTMRMwEQYDVQQIDApXYXNoaW5ndG9uMRAwDgYDVQQHDAdTZWF0dGxlMQ8w
32
- DQYDVQQKDAZIYXJha2ExFTATBgNVBAMMDGhhcmFrYS5sb2NhbDEgMB4GCSqGSIb3
33
- DQEJARYRbWF0dEBoYXJha2EubG9jYWwwHhcNMTcwMzA0MjMyODQ5WhcNMjMwMzAz
34
- MjMyODQ5WjB+MQswCQYDVQQGEwJVUzETMBEGA1UECAwKV2FzaGluZ3RvbjEQMA4G
35
- A1UEBwwHU2VhdHRsZTEPMA0GA1UECgwGSGFyYWthMRUwEwYDVQQDDAxoYXJha2Eu
36
- bG9jYWwxIDAeBgkqhkiG9w0BCQEWEW1hdHRAaGFyYWthLmxvY2FsMIIBIjANBgkq
37
- hkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3IOYeU1TtYBAisjQl26SXbjaib4ROocl
38
- W/atFkUfMyhxOw5zqIPSajnK8+Jr905rMw2duddZhsaP749nQGGpFOx8RLkqil9Q
39
- rI2wz98WuyL1QmikG3DCJqu3c5np15AnT4r7oJWZqKGXp3NfEGemJK7pw3ofznD/
40
- FgAPvcmF6fNpZij8yjZCRE3xlV339JaF1keUkoxl2L46plyuiF6j3Lja4lE5spS8
41
- dtePTukViT2mdmGMUzh03leTjHhB4y6QDkoQn2YuFWLwHhmUhauVHTL+UA9ZOgbn
42
- ktUbn+goQi436pDHAgMPAzmPKMb86L4DP7IAXMdy9NP6XkHknoBvtwIDAQABo1Aw
43
- TjAdBgNVHQ4EFgQUsfam5K8yKVyyJG7NQfKXjpr6gYEwHwYDVR0jBBgwFoAUsfam
44
- 5K8yKVyyJG7NQfKXjpr6gYEwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC
45
- AQEAL7vMH/sYj/rDzo+pYn8qK9eZBpTPQLsuiotNYqoH/tOJzaOBI2cMSrbGM3zG
46
- aegTqKOduO6vpXun7MT4tGilOxt+1eve6RbsjKMeTkZr+A44rRRUZ4LHZe38oaGk
47
- A8jB6YHiiefH1mgfSN1igcT7SkOxv8WM4jsCyOCy3wG8b4V8wvDytOtJOJo041hX
48
- njmypWHaZ1IDYu1ybnb/Macnno0NMkEMx0uIlG/c3+KvJwpz2WHrKrKA5l5oGp/n
49
- +F3pt6NhSJCDG0cktax07LIvxMpAoOaJ6cYSfwB/v0HiYh2733bEXEiQ2jxO5vXo
50
- NS2fKRYBqs2ATDVHpzknBC1KcA==
30
+ MIID3TCCAsWgAwIBAgIUaYxDRJxsA5vqHEHzLkRzYlYJhGwwDQYJKoZIhvcNAQEL
31
+ BQAwfjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCldhc2hpbmd0b24xEDAOBgNVBAcM
32
+ B1NlYXR0bGUxDzANBgNVBAoMBkhhcmFrYTEVMBMGA1UEAwwMaGFyYWthLmxvY2Fs
33
+ MSAwHgYJKoZIhvcNAQkBFhFtYXR0QGhhcmFrYS5sb2NhbDAeFw0yNjAzMjUwNDI1
34
+ MzJaFw0yOTAzMjQwNDI1MzJaMH4xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApXYXNo
35
+ aW5ndG9uMRAwDgYDVQQHDAdTZWF0dGxlMQ8wDQYDVQQKDAZIYXJha2ExFTATBgNV
36
+ BAMMDGhhcmFrYS5sb2NhbDEgMB4GCSqGSIb3DQEJARYRbWF0dEBoYXJha2EubG9j
37
+ YWwwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCdI9wQHH4zJzrKjd4
38
+ /a4AV8uPnvZwOHC/mhFnAS2V4+oPLgBZYG/yiktsmTcsYl3Cgf3n8X1eMsRli91k
39
+ dC1+2txMsn/Y6DDAxW+qbYWIvWWPQlCr+eweGAYf3HkWAd3nAiKB1qfnUvL5y0we
40
+ rjQFV9cAeK9xqtC7HqaTOYtNnAmipIGLK7y4RQfnzf20Qqu9yv3uC2Gaj3VkEhGF
41
+ RaIvKxVmnvCmRYa8UM3HKtF4q+ApkoeslJjqK68vSXtDQFZ6qHatotWeYVztluX6
42
+ 6f925pKBTU6AVJJQxrCWjQ/KLLLW7qbytaMjagz4IBpRNpb3Wfc7c7/51nDmTyEC
43
+ GKMnAgMBAAGjUzBRMB0GA1UdDgQWBBSzcvDenCZgIgox2IXTubXgLv/6xTAfBgNV
44
+ HSMEGDAWgBSzcvDenCZgIgox2IXTubXgLv/6xTAPBgNVHRMBAf8EBTADAQH/MA0G
45
+ CSqGSIb3DQEBCwUAA4IBAQAQK28lJKzpDm7LZHPPxGczn4jaBYtSYZ2aM1SP+fRv
46
+ TMyl6QEm4atyQCETWngVEHw9zM2uVH9lUvqxRQVLxQL0Hdi05l+PGc5c/UNGsOa6
47
+ 4LJSP8f0OPvvWiMc1coWAxM9UCtAByTiMWyqbdhm9huZ8XWCBWjZ6HJswMxrFFs8
48
+ WE0Zrdh+lutDilL9af6FF0vI1PW7dyo8a5tKZ13tYI3C4feyQoao0xZZZSvw+v50
49
+ Pq/HLEre2zfxy11QbKVTco8ipwxRVsF3XfKKco6Vh3APp03v3QhlRovbxJsV2ZE0
50
+ F8a2QrvoPLEBqyDPFyRc5+EgJFJcNBzrbBYbGLGA7sJ+
51
51
  -----END CERTIFICATE-----