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
@@ -3,84 +3,84 @@
3
3
  // in the mail_from.blocklist file. You need to be running the
4
4
  // mail_from.blocklist plugin for this to work fully.
5
5
 
6
- const fs = require('node:fs');
7
- const utils = require('haraka-utils');
6
+ const fs = require('node:fs')
7
+ const utils = require('haraka-utils')
8
8
 
9
9
  exports.hook_data = (next, connection) => {
10
10
  // enable mail body parsing
11
- connection.transaction.parse_body = true;
12
- next();
11
+ connection.transaction.parse_body = true
12
+ next()
13
13
  }
14
14
 
15
15
  exports.hook_data_post = function (next, connection) {
16
- if (!connection?.relaying || !connection?.transaction) return next();
16
+ if (!connection?.relaying || !connection?.transaction) return next()
17
17
 
18
- const recip = (this.config.get('block_me.recipient') || '').toLowerCase();
19
- const senders = this.config.get('block_me.senders', 'list');
18
+ const recip = (this.config.get('block_me.recipient') || '').toLowerCase()
19
+ const senders = this.config.get('block_me.senders', 'list')
20
20
 
21
21
  // Make sure only 1 recipient
22
22
  if (connection.transaction.rcpt_to.length != 1) {
23
- return next();
23
+ return next()
24
24
  }
25
25
 
26
26
  // Check recipient is the right one
27
27
  if (connection.transaction.rcpt_to[0].address().toLowerCase() != recip) {
28
- return next();
28
+ return next()
29
29
  }
30
30
 
31
31
  // Check sender is in list
32
- const sender = connection.transaction.mail_from.address();
32
+ const sender = connection.transaction.mail_from.address()
33
33
  if (!utils.in_array(sender, senders)) {
34
- return next(DENY, `You are not allowed to block mail, ${sender}`);
34
+ return next(DENY, `You are not allowed to block mail, ${sender}`)
35
35
  }
36
36
 
37
37
  // Now extract the "From" from the body...
38
- const to_block = extract_from_line(connection.transaction.body);
38
+ const to_block = extract_from_line(connection.transaction.body)
39
39
  if (!to_block) {
40
- connection.logerror(this, "No sender found in email");
41
- return next();
40
+ connection.logerror(this, 'No sender found in email')
41
+ return next()
42
42
  }
43
43
 
44
- connection.loginfo(this, `Blocking new sender: ${to_block}`);
44
+ connection.loginfo(this, `Blocking new sender: ${to_block}`)
45
45
 
46
- connection.transaction.notes.block_me = 1;
46
+ connection.transaction.notes.block_me = 1
47
47
 
48
48
  // add to mail_from.blocklist
49
49
  fs.open('./config/mail_from.blocklist', 'a', (err, fd) => {
50
50
  if (err) {
51
- connection.logerror(this, `Unable to append to mail_from.blocklist: ${err}`);
52
- return;
51
+ connection.logerror(this, `Unable to append to mail_from.blocklist: ${err}`)
52
+ return
53
53
  }
54
54
  fs.write(fd, `${to_block}\n`, null, 'UTF-8', (err2, written) => {
55
- fs.close(fd);
56
- });
57
- });
55
+ fs.close(fd)
56
+ })
57
+ })
58
58
 
59
- next();
59
+ next()
60
60
  }
61
61
 
62
62
  exports.hook_queue = (next, connection) => {
63
63
  if (connection.transaction.notes.block_me) {
64
64
  // pretend we queued this mail
65
- return next(OK);
65
+ return next(OK)
66
66
  }
67
67
 
68
- next();
68
+ next()
69
69
  }
70
70
 
71
71
  // Example: From: Site Tucano Gold <contato@tucanogold.com.br>
72
- function extract_from_line (body) {
73
- const matches = body.bodytext.match(/\bFrom:[^<\n]*<([^>\n]*)>/);
72
+ function extract_from_line(body) {
73
+ const matches = body.bodytext.match(/\bFrom:[^<\n]*<([^>\n]*)>/)
74
74
  if (matches) {
75
- return matches[1];
75
+ return matches[1]
76
76
  }
77
77
 
78
- for (let i=0,l=body.children.length; i < l; i++) {
79
- const from = extract_from_line(body.children[i]);
78
+ for (let i = 0, l = body.children.length; i < l; i++) {
79
+ const from = extract_from_line(body.children[i])
80
80
  if (from) {
81
- return from;
81
+ return from
82
82
  }
83
83
  }
84
84
 
85
- return null;
85
+ return null
86
86
  }
@@ -1,30 +1,30 @@
1
- 'use strict';
1
+ 'use strict'
2
2
  // Simple string signatures
3
3
 
4
4
  exports.hook_data = (next, connection) => {
5
5
  // enable mail body parsing
6
- if (connection?.transaction) connection.transaction.parse_body = true;
7
- next();
6
+ if (connection?.transaction) connection.transaction.parse_body = true
7
+ next()
8
8
  }
9
9
 
10
10
  exports.hook_data_post = function (next, connection) {
11
- if (!connection?.transaction) return next();
11
+ if (!connection?.transaction) return next()
12
12
 
13
- const sigs = this.config.get('data.signatures', 'list');
13
+ const sigs = this.config.get('data.signatures', 'list')
14
14
 
15
15
  if (check_sigs(sigs, connection.transaction.body)) {
16
- return next(DENY, "Mail matches a known spam signature");
16
+ return next(DENY, 'Mail matches a known spam signature')
17
17
  }
18
- next();
18
+ next()
19
19
  }
20
20
 
21
- function check_sigs (sigs, body) {
22
- for (let i=0,l=sigs.length; i < l; i++) {
23
- if (body.bodytext.includes(sigs[i])) return 1;
21
+ function check_sigs(sigs, body) {
22
+ for (let i = 0, l = sigs.length; i < l; i++) {
23
+ if (body.bodytext.includes(sigs[i])) return 1
24
24
  }
25
25
 
26
- for (let i=0,l=body.children.length; i < l; i++) {
27
- if (check_sigs(sigs, body.children[i])) return 1;
26
+ for (let i = 0, l = body.children.length; i < l; i++) {
27
+ if (check_sigs(sigs, body.children[i])) return 1
28
28
  }
29
- return 0;
29
+ return 0
30
30
  }
@@ -1,61 +1,65 @@
1
1
  /*
2
- ** delay_deny
3
- **
4
- ** This plugin delays all pre-DATA 'deny' results until the recipients are sent
5
- ** and all post-DATA commands until all hook_data_post plugins have run.
6
- ** This allows relays and authenticated users to bypass pre-DATA rejections.
7
- */
2
+ ** delay_deny
3
+ **
4
+ ** This plugin delays all pre-DATA 'deny' results until the recipients are sent
5
+ ** and all post-DATA commands until all hook_data_post plugins have run.
6
+ ** This allows relays and authenticated users to bypass pre-DATA rejections.
7
+ */
8
8
 
9
9
  exports.hook_deny = function (next, connection, params) {
10
10
  /* params
11
- ** [0] = plugin return value (DENY or DENYSOFT)
12
- ** [1] = plugin return message
13
- */
11
+ ** [0] = plugin return value (DENY or DENYSOFT)
12
+ ** [1] = plugin return message
13
+ */
14
14
 
15
- const pi_name = params[2];
16
- const pi_function = params[3];
15
+ const pi_name = params[2]
16
+ const pi_function = params[3]
17
17
  // var pi_params = params[4];
18
- const pi_hook = params[5];
18
+ const pi_hook = params[5]
19
19
 
20
- const { transaction } = connection;
20
+ const { transaction } = connection
21
21
 
22
22
  // Don't delay ourselves...
23
- if (pi_name == 'delay_deny') return next();
23
+ if (pi_name == 'delay_deny') return next()
24
24
 
25
25
  // Load config
26
- const cfg = this.config.get('delay_deny.ini');
27
- let skip;
28
- let included;
26
+ const cfg = this.config.get('delay_deny.ini')
27
+ let skip
28
+ let included
29
29
  if (cfg.main.included_plugins) {
30
- included = cfg.main.included_plugins.split(/[;, ]+/);
31
- }
32
- else if (cfg.main.excluded_plugins) {
33
- skip = cfg.main.excluded_plugins.split(/[;, ]+/);
30
+ included = cfg.main.included_plugins.split(/[;, ]+/)
31
+ } else if (cfg.main.excluded_plugins) {
32
+ skip = cfg.main.excluded_plugins.split(/[;, ]+/)
34
33
  }
35
34
 
36
35
  // 'included' mode: only delay deny plugins in the included list
37
36
  if (included?.length) {
38
- if (!included.includes(pi_name) &&
37
+ if (
38
+ !included.includes(pi_name) &&
39
39
  !included.includes(`${pi_name}:${pi_hook}`) &&
40
- !included.includes(`${pi_name}:${pi_hook}:${pi_function}`)) {
41
- return next();
40
+ !included.includes(`${pi_name}:${pi_hook}:${pi_function}`)
41
+ ) {
42
+ return next()
42
43
  }
43
- }
44
- else if (skip?.length) { // 'excluded' mode: delay deny everything except in skip list
44
+ } else if (skip?.length) {
45
+ // 'excluded' mode: delay deny everything except in skip list
45
46
  // Skip by <plugin name>
46
47
  if (skip.includes(pi_name)) {
47
- connection.logdebug(this, `not delaying excluded plugin: ${pi_name}`);
48
- return next();
48
+ connection.logdebug(this, `not delaying excluded plugin: ${pi_name}`)
49
+ return next()
49
50
  }
50
51
  // Skip by <plugin name>:<hook>
51
52
  if (skip.includes(`${pi_name}:${pi_hook}`)) {
52
- connection.logdebug(this, `not delaying excluded hook: ${pi_hook} in plugin: ${pi_name}`);
53
- return next();
53
+ connection.logdebug(this, `not delaying excluded hook: ${pi_hook} in plugin: ${pi_name}`)
54
+ return next()
54
55
  }
55
56
  // Skip by <plugin name>:<hook>:<function name>
56
57
  if (skip.includes(`${pi_name}:${pi_hook}:${pi_function}`)) {
57
- connection.logdebug(this, `not delaying excluded function: ${pi_function} on hook: ${pi_hook} in plugin: ${pi_name}`);
58
- return next();
58
+ connection.logdebug(
59
+ this,
60
+ `not delaying excluded function: ${pi_function} on hook: ${pi_hook} in plugin: ${pi_name}`,
61
+ )
62
+ return next()
59
63
  }
60
64
  }
61
65
 
@@ -66,84 +70,84 @@ exports.hook_deny = function (next, connection, params) {
66
70
  case 'ehlo':
67
71
  case 'helo':
68
72
  if (!connection.notes.delay_deny_pre) {
69
- connection.notes.delay_deny_pre = [];
73
+ connection.notes.delay_deny_pre = []
70
74
  }
71
- connection.notes.delay_deny_pre.push(params);
75
+ connection.notes.delay_deny_pre.push(params)
72
76
  if (!connection.notes.delay_deny_pre_fail) {
73
- connection.notes.delay_deny_pre_fail = {};
77
+ connection.notes.delay_deny_pre_fail = {}
74
78
  }
75
- connection.notes.delay_deny_pre_fail[pi_name] = 1;
76
- return next(OK);
79
+ connection.notes.delay_deny_pre_fail[pi_name] = 1
80
+ return next(OK)
77
81
  // Pre-DATA transaction delays
78
82
  case 'mail':
79
83
  case 'rcpt':
80
84
  case 'rcpt_ok':
81
85
  if (!transaction.notes.delay_deny_pre) {
82
- transaction.notes.delay_deny_pre = [];
86
+ transaction.notes.delay_deny_pre = []
83
87
  }
84
- transaction.notes.delay_deny_pre.push(params);
88
+ transaction.notes.delay_deny_pre.push(params)
85
89
  if (!transaction.notes.delay_deny_pre_fail) {
86
- transaction.notes.delay_deny_pre_fail = {};
90
+ transaction.notes.delay_deny_pre_fail = {}
87
91
  }
88
- transaction.notes.delay_deny_pre_fail[pi_name] = 1;
89
- return next(OK);
92
+ transaction.notes.delay_deny_pre_fail[pi_name] = 1
93
+ return next(OK)
90
94
  // Post-DATA delays
91
95
  case 'data':
92
96
  case 'data_post':
93
- // fall through
97
+ // fall through
94
98
  default:
95
99
  // No delays
96
- next();
100
+ next()
97
101
  }
98
102
  }
99
103
 
100
104
  exports.hook_rcpt_ok = function (next, connection, rcpt) {
101
- const transaction = connection?.transaction;
102
- if (!transaction) return next();
105
+ const transaction = connection?.transaction
106
+ if (!transaction) return next()
103
107
 
104
108
  // Bypass all pre-DATA deny for AUTH/RELAY
105
109
  if (connection.relaying) {
106
- connection.loginfo(this, 'bypassing all pre-DATA deny: AUTH/RELAY');
107
- return next();
110
+ connection.loginfo(this, 'bypassing all pre-DATA deny: AUTH/RELAY')
111
+ return next()
108
112
  }
109
113
 
110
114
  // Apply any delayed rejections
111
115
  // Check connection level pre-DATA rejections first
112
116
  if (connection.notes?.delay_deny_pre) {
113
117
  for (const params of connection.notes.delay_deny_pre) {
114
- return next(params[0], params[1]);
118
+ return next(params[0], params[1])
115
119
  }
116
120
  }
117
121
 
118
122
  // Then check transaction level pre-DATA
119
123
  if (transaction.notes?.delay_deny_pre) {
120
- for (let i=0; i<transaction.notes.delay_deny_pre.length; i++) {
121
- const params = transaction.notes.delay_deny_pre[i];
124
+ for (let i = 0; i < transaction.notes.delay_deny_pre.length; i++) {
125
+ const params = transaction.notes.delay_deny_pre[i]
122
126
 
123
127
  // Remove rejection from the array if it was on the rcpt hooks
124
128
  if (params[5] === 'rcpt' || params[5] === 'rcpt_ok') {
125
- transaction.notes.delay_deny_pre.splice(i, 1);
129
+ transaction.notes.delay_deny_pre.splice(i, 1)
126
130
  }
127
131
 
128
- return next(params[0], params[1]);
132
+ return next(params[0], params[1])
129
133
  }
130
134
  }
131
- next();
135
+ next()
132
136
  }
133
137
 
134
138
  exports.hook_data = (next, connection) => {
135
- const transaction = connection?.transaction;
136
- if (!transaction) return next();
139
+ const transaction = connection?.transaction
140
+ if (!transaction) return next()
137
141
 
138
142
  // Add a header showing all pre-DATA rejections
139
- const fails = [];
143
+ const fails = []
140
144
  if (connection.notes?.delay_deny_pre_fail) {
141
- fails.push.apply(Object.keys(connection.notes.delay_deny_pre_fail));
145
+ fails.push.apply(Object.keys(connection.notes.delay_deny_pre_fail))
142
146
  }
143
147
  if (transaction.notes?.delay_deny_pre_fail) {
144
- fails.push.apply(Object.keys(transaction.notes.delay_deny_pre_fail));
148
+ fails.push.apply(Object.keys(transaction.notes.delay_deny_pre_fail))
145
149
  }
146
- if (fails.length) transaction.add_header('X-Haraka-Fail-Pre', fails.join(' '));
150
+ if (fails.length) transaction.add_header('X-Haraka-Fail-Pre', fails.join(' '))
147
151
 
148
- next();
152
+ next()
149
153
  }
@@ -1,59 +1,59 @@
1
1
  // Prevent a user from sending their AUTH credentials
2
2
  // This is a simple, primitive form of anti-phishing.
3
3
 
4
- function escapeRegExp (str) {
5
- return str.replace(/[-[\]/{}()*+?.\\^$|]/g, "\\$&");
4
+ function escapeRegExp(str) {
5
+ return str.replace(/[-[\]/{}()*+?.\\^$|]/g, '\\$&')
6
6
  }
7
7
 
8
8
  exports.hook_data = (next, connection) => {
9
9
  const { notes, transaction } = connection ?? {}
10
10
 
11
11
  if (transaction && notes?.auth_user && notes.auth_passwd) {
12
- transaction.parse_body = true;
12
+ transaction.parse_body = true
13
13
  }
14
- next();
14
+ next()
15
15
  }
16
16
 
17
17
  exports.hook_data_post = (next, connection) => {
18
18
  if (!(connection.notes.auth_user && connection.notes.auth_passwd)) {
19
- return next();
19
+ return next()
20
20
  }
21
21
 
22
- let user = connection.notes.auth_user;
23
- let domain;
22
+ let user = connection.notes.auth_user
23
+ let domain
24
24
  const idx = user.indexOf('@')
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.substr(idx)
29
+ user = user.substr(0, idx)
30
30
  }
31
- const passwd = connection.notes.auth_passwd;
32
- const bound_regexp = "(?:\\b|\\B)";
33
- const passwd_regexp = new RegExp(bound_regexp + escapeRegExp(passwd) + bound_regexp, 'm');
34
- const user_regexp = new RegExp(bound_regexp +
35
- escapeRegExp(user) +
36
- (domain ? `(?:${escapeRegExp(domain)})?` : '') +
37
- bound_regexp, 'im');
31
+ const passwd = connection.notes.auth_passwd
32
+ const bound_regexp = '(?:\\b|\\B)'
33
+ const passwd_regexp = new RegExp(bound_regexp + escapeRegExp(passwd) + bound_regexp, 'm')
34
+ const user_regexp = new RegExp(
35
+ bound_regexp + escapeRegExp(user) + (domain ? `(?:${escapeRegExp(domain)})?` : '') + bound_regexp,
36
+ 'im',
37
+ )
38
38
 
39
39
  if (look_for_credentials(user_regexp, passwd_regexp, connection?.transaction?.body)) {
40
- return next(DENY, "Credential leak detected: never give out your username/password to anyone!");
40
+ return next(DENY, 'Credential leak detected: never give out your username/password to anyone!')
41
41
  }
42
42
 
43
- next();
43
+ next()
44
44
  }
45
45
 
46
- function look_for_credentials (user_regexp, passwd_regexp, body) {
46
+ function look_for_credentials(user_regexp, passwd_regexp, body) {
47
47
  if (user_regexp.test(body.bodytext) && passwd_regexp.test(body.bodytext)) {
48
- return true;
48
+ return true
49
49
  }
50
50
 
51
51
  // Check all child parts
52
- for (let i=0,l=body.children.length; i < l; i++) {
52
+ for (let i = 0, l = body.children.length; i < l; i++) {
53
53
  if (look_for_credentials(user_regexp, passwd_regexp, body.children[i])) {
54
- return true;
54
+ return true
55
55
  }
56
56
  }
57
57
 
58
- return false;
58
+ return false
59
59
  }