Haraka 3.0.3 → 3.0.5

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 (239) hide show
  1. package/.eslintrc.yaml +4 -9
  2. package/CONTRIBUTORS.md +11 -0
  3. package/Changes.md +1397 -1213
  4. package/Plugins.md +117 -105
  5. package/README.md +4 -13
  6. package/bin/haraka +198 -298
  7. package/config/auth_flat_file.ini +1 -0
  8. package/config/dhparams.pem +8 -0
  9. package/config/mail_from.is_resolvable.ini +4 -2
  10. package/config/me +1 -0
  11. package/config/outbound.ini +0 -2
  12. package/config/plugins +35 -36
  13. package/config/smtp.ini +1 -1
  14. package/config/smtp.json +17 -0
  15. package/config/tls.ini +2 -0
  16. package/config/tls_cert.pem +23 -0
  17. package/config/tls_key.pem +28 -0
  18. package/connection.js +46 -73
  19. package/contrib/bsd-rc.d/haraka +3 -1
  20. package/contrib/plugin2npm.sh +6 -36
  21. package/docs/CoreConfig.md +2 -2
  22. package/docs/Logging.md +7 -21
  23. package/docs/Outbound.md +104 -201
  24. package/docs/Plugins.md +2 -2
  25. package/docs/Transaction.md +59 -82
  26. package/docs/plugins/queue/smtp_proxy.md +5 -10
  27. package/docs/plugins/tls.md +37 -9
  28. package/endpoint.js +16 -13
  29. package/haraka.js +10 -14
  30. package/host_pool.js +5 -5
  31. package/http/html/index.html +6 -5
  32. package/line_socket.js +3 -4
  33. package/logger.js +44 -28
  34. package/outbound/client_pool.js +27 -23
  35. package/outbound/config.js +4 -6
  36. package/outbound/fsync_writestream.js +1 -1
  37. package/outbound/hmail.js +178 -218
  38. package/outbound/index.js +86 -99
  39. package/outbound/qfile.js +1 -1
  40. package/outbound/queue.js +51 -44
  41. package/outbound/timer_queue.js +3 -2
  42. package/outbound/tls.js +19 -7
  43. package/package.json +60 -51
  44. package/plugins/.eslintrc.yaml +0 -6
  45. package/plugins/auth/auth_base.js +4 -2
  46. package/plugins/auth/auth_proxy.js +14 -12
  47. package/plugins/auth/auth_vpopmaild.js +1 -1
  48. package/plugins/block_me.js +1 -1
  49. package/plugins/data.signatures.js +2 -4
  50. package/plugins/early_talker.js +2 -1
  51. package/plugins/mail_from.is_resolvable.js +65 -135
  52. package/plugins/queue/deliver.js +4 -5
  53. package/plugins/queue/lmtp.js +11 -12
  54. package/plugins/queue/qmail-queue.js +2 -2
  55. package/plugins/queue/quarantine.js +2 -2
  56. package/plugins/queue/rabbitmq.js +16 -17
  57. package/plugins/queue/smtp_forward.js +3 -3
  58. package/plugins/queue/smtp_proxy.js +10 -1
  59. package/plugins/queue/test.js +2 -2
  60. package/plugins/rcpt_to.host_list_base.js +5 -5
  61. package/plugins/rcpt_to.in_host_list.js +2 -2
  62. package/plugins/relay.js +6 -7
  63. package/plugins/reseed_rng.js +1 -1
  64. package/plugins/status.js +37 -33
  65. package/plugins/tls.js +2 -2
  66. package/plugins/xclient.js +3 -2
  67. package/plugins.js +50 -54
  68. package/run_tests +3 -30
  69. package/server.js +190 -190
  70. package/smtp_client.js +30 -23
  71. package/{tests → test}/config/plugins +0 -2
  72. package/{tests → test}/config/smtp.ini +3 -1
  73. package/test/config/tls/example.com/_.example.com.key +28 -0
  74. package/test/config/tls/example.com/example.com.crt +25 -0
  75. package/{tests/loud → test}/config/tls.ini +4 -2
  76. package/test/connection.js +302 -0
  77. package/test/endpoint.js +94 -0
  78. package/{tests → test}/fixtures/line_socket.js +1 -1
  79. package/{tests → test}/fixtures/util_hmailitem.js +19 -25
  80. package/{tests → test}/host_pool.js +42 -57
  81. package/test/logger.js +258 -0
  82. package/test/outbound/hmail.js +141 -0
  83. package/test/outbound/index.js +220 -0
  84. package/test/outbound/qfile.js +126 -0
  85. package/test/outbound_bounce_net_errors.js +142 -0
  86. package/{tests → test}/outbound_bounce_rfc3464.js +110 -122
  87. package/test/plugins/auth/auth_base.js +484 -0
  88. package/test/plugins/auth/auth_vpopmaild.js +83 -0
  89. package/test/plugins/early_talker.js +104 -0
  90. package/test/plugins/mail_from.is_resolvable.js +35 -0
  91. package/test/plugins/queue/smtp_forward.js +206 -0
  92. package/test/plugins/rcpt_to.host_list_base.js +122 -0
  93. package/test/plugins/rcpt_to.in_host_list.js +193 -0
  94. package/test/plugins/relay.js +303 -0
  95. package/test/plugins/status.js +130 -0
  96. package/test/plugins/tls.js +70 -0
  97. package/test/plugins.js +228 -0
  98. package/test/rfc1869.js +73 -0
  99. package/test/server.js +491 -0
  100. package/test/smtp_client.js +299 -0
  101. package/test/tls_socket.js +277 -0
  102. package/test/transaction.js +270 -0
  103. package/tls_socket.js +202 -252
  104. package/transaction.js +8 -23
  105. package/CONTRIBUTING.md +0 -1
  106. package/bin/dkimverify +0 -40
  107. package/config/access.domains +0 -13
  108. package/config/attachment.ctype.regex +0 -2
  109. package/config/attachment.filename.regex +0 -1
  110. package/config/avg.ini +0 -5
  111. package/config/bounce.ini +0 -15
  112. package/config/data.headers.ini +0 -61
  113. package/config/dkim/dkim_key_gen.sh +0 -78
  114. package/config/dkim_sign.ini +0 -4
  115. package/config/dkim_verify.ini +0 -7
  116. package/config/dnsbl.ini +0 -23
  117. package/config/greylist.ini +0 -43
  118. package/config/helo.checks.ini +0 -52
  119. package/config/messagesniffer.ini +0 -18
  120. package/config/spamassassin.ini +0 -56
  121. package/dkim.js +0 -614
  122. package/docs/plugins/avg.md +0 -35
  123. package/docs/plugins/bounce.md +0 -69
  124. package/docs/plugins/clamd.md +0 -147
  125. package/docs/plugins/esets.md +0 -8
  126. package/docs/plugins/greylist.md +0 -90
  127. package/docs/plugins/helo.checks.md +0 -135
  128. package/docs/plugins/messagesniffer.md +0 -163
  129. package/docs/plugins/spamassassin.md +0 -180
  130. package/outbound/mx_lookup.js +0 -70
  131. package/plugins/auth/auth_ldap.js +0 -3
  132. package/plugins/avg.js +0 -162
  133. package/plugins/backscatterer.js +0 -25
  134. package/plugins/bounce.js +0 -381
  135. package/plugins/clamd.js +0 -382
  136. package/plugins/data.uribl.js +0 -4
  137. package/plugins/dkim_sign.js +0 -395
  138. package/plugins/dkim_verify.js +0 -62
  139. package/plugins/dns_list_base.js +0 -221
  140. package/plugins/dnsbl.js +0 -146
  141. package/plugins/dnswl.js +0 -58
  142. package/plugins/esets.js +0 -71
  143. package/plugins/graph.js +0 -5
  144. package/plugins/greylist.js +0 -645
  145. package/plugins/helo.checks.js +0 -533
  146. package/plugins/messagesniffer.js +0 -381
  147. package/plugins/rcpt_to.ldap.js +0 -3
  148. package/plugins/rcpt_to.max_count.js +0 -24
  149. package/plugins/spamassassin.js +0 -384
  150. package/tests/config/dkim/example.com/dns +0 -29
  151. package/tests/config/dkim/example.com/private +0 -6
  152. package/tests/config/dkim/example.com/public +0 -4
  153. package/tests/config/dkim/example.com/selector +0 -1
  154. package/tests/config/dkim.private.key +0 -6
  155. package/tests/config/dkim_sign.ini +0 -4
  156. package/tests/config/helo.checks.ini +0 -52
  157. package/tests/connection.js +0 -327
  158. package/tests/endpoint.js +0 -128
  159. package/tests/fixtures/vm_harness.js +0 -59
  160. package/tests/logger.js +0 -327
  161. package/tests/outbound/hmail.js +0 -112
  162. package/tests/outbound/index.js +0 -324
  163. package/tests/outbound/qfile.js +0 -67
  164. package/tests/outbound_bounce_net_errors.js +0 -173
  165. package/tests/plugins/auth/auth_base.js +0 -463
  166. package/tests/plugins/auth/auth_vpopmaild.js +0 -91
  167. package/tests/plugins/bounce.js +0 -307
  168. package/tests/plugins/clamd.js +0 -224
  169. package/tests/plugins/deprecated/relay_acl.js +0 -140
  170. package/tests/plugins/deprecated/relay_all.js +0 -59
  171. package/tests/plugins/dkim_sign.js +0 -315
  172. package/tests/plugins/dkim_signer.js +0 -108
  173. package/tests/plugins/dns_list_base.js +0 -259
  174. package/tests/plugins/dnsbl.js +0 -101
  175. package/tests/plugins/early_talker.js +0 -115
  176. package/tests/plugins/greylist.js +0 -58
  177. package/tests/plugins/helo.checks.js +0 -525
  178. package/tests/plugins/mail_from.is_resolvable.js +0 -116
  179. package/tests/plugins/queue/smtp_forward.js +0 -221
  180. package/tests/plugins/rcpt_to.host_list_base.js +0 -132
  181. package/tests/plugins/rcpt_to.in_host_list.js +0 -218
  182. package/tests/plugins/relay.js +0 -339
  183. package/tests/plugins/spamassassin.js +0 -171
  184. package/tests/plugins/status.js +0 -138
  185. package/tests/plugins/tls.js +0 -84
  186. package/tests/plugins.js +0 -247
  187. package/tests/rfc1869.js +0 -61
  188. package/tests/server.js +0 -510
  189. package/tests/smtp_client/auth.js +0 -105
  190. package/tests/smtp_client/basic.js +0 -101
  191. package/tests/smtp_client.js +0 -80
  192. package/tests/tls_socket.js +0 -333
  193. package/tests/transaction.js +0 -284
  194. /package/docs/{plugins → deprecated}/dkim_sign.md +0 -0
  195. /package/docs/{plugins → deprecated}/dkim_verify.md +0 -0
  196. /package/docs/{plugins → deprecated}/dnsbl.md +0 -0
  197. /package/docs/{plugins → deprecated}/dnswl.md +0 -0
  198. /package/{tests → test}/.eslintrc.yaml +0 -0
  199. /package/{tests → test}/config/auth_flat_file.ini +0 -0
  200. /package/{tests → test}/config/dhparams.pem +0 -0
  201. /package/{tests → test}/config/host_list +0 -0
  202. /package/{tests → test}/config/outbound_tls_cert.pem +0 -0
  203. /package/{tests → test}/config/outbound_tls_key.pem +0 -0
  204. /package/{tests → test}/config/smtp_forward.ini +0 -0
  205. /package/{tests → test}/config/tls/ec.pem +0 -0
  206. /package/{tests → test}/config/tls/haraka.local.pem +0 -0
  207. /package/{tests → test}/config/tls/mismatched.pem +0 -0
  208. /package/{tests → test}/config/tls_cert.pem +0 -0
  209. /package/{tests → test}/config/tls_key.pem +0 -0
  210. /package/{tests → test}/fixtures/todo_qfile.txt +0 -0
  211. /package/{tests → test}/installation/config/test-plugin-flat +0 -0
  212. /package/{tests → test}/installation/config/test-plugin.ini +0 -0
  213. /package/{tests → test}/installation/config/tls.ini +0 -0
  214. /package/{tests → test}/installation/node_modules/load_first/index.js +0 -0
  215. /package/{tests → test}/installation/node_modules/load_first/package.json +0 -0
  216. /package/{tests → test}/installation/node_modules/test-plugin/config/test-plugin-flat +0 -0
  217. /package/{tests → test}/installation/node_modules/test-plugin/config/test-plugin.ini +0 -0
  218. /package/{tests → test}/installation/node_modules/test-plugin/package.json +0 -0
  219. /package/{tests → test}/installation/node_modules/test-plugin/test-plugin.js +0 -0
  220. /package/{tests → test}/installation/plugins/base_plugin.js +0 -0
  221. /package/{tests → test}/installation/plugins/folder_plugin/index.js +0 -0
  222. /package/{tests → test}/installation/plugins/folder_plugin/package.json +0 -0
  223. /package/{tests → test}/installation/plugins/inherits.js +0 -0
  224. /package/{tests → test}/installation/plugins/load_first.js +0 -0
  225. /package/{tests → test}/installation/plugins/plugin.js +0 -0
  226. /package/{tests → test}/installation/plugins/tls.js +0 -0
  227. /package/{tests → test}/loud/config/dhparams.pem +0 -0
  228. /package/{tests → test}/loud/config/tls/goobered.pem +0 -0
  229. /package/{tests → test/loud}/config/tls.ini +0 -0
  230. /package/{tests → test}/mail_specimen/base64-root-part.txt +0 -0
  231. /package/{tests → test}/mail_specimen/varied-fold-lengths-preserve-data.txt +0 -0
  232. /package/{tests → test}/queue/1507509981169_1507509981169_0_61403_e0Y0Ym_1_fixed +0 -0
  233. /package/{tests → test}/queue/1507509981169_1507509981169_0_61403_e0Y0Ym_1_haraka +0 -0
  234. /package/{tests → test}/queue/1508269674999_1508269674999_0_34002_socVUF_1_haraka +0 -0
  235. /package/{tests → test}/queue/1508455115683_1508455115683_0_90253_9Q4o4V_1_haraka +0 -0
  236. /package/{tests → test}/queue/multibyte +0 -0
  237. /package/{tests → test}/queue/plain +0 -0
  238. /package/{tests → test}/queue/zero-length +0 -0
  239. /package/{tests → test}/test-queue/delete-me +0 -0
@@ -0,0 +1,270 @@
1
+ const assert = require('node:assert')
2
+ const fs = require('node:fs');
3
+ const path = require('node:path');
4
+
5
+ const config = require('haraka-config')
6
+ const transaction = require('../transaction');
7
+
8
+ const _set_up = (done) => {
9
+ this.transaction = transaction.createTransaction(undefined, config.get('smtp.ini'));
10
+ done()
11
+ }
12
+
13
+ describe('transaction', () => {
14
+ beforeEach(_set_up)
15
+
16
+ it('add_body_filter', (done) => {
17
+
18
+ this.transaction.add_body_filter('text/plain', (ct, enc, buf) => {
19
+ // The functionality of these filter functions is tested in
20
+ // haraka-email-message. This just assures the plumbing is in place.
21
+
22
+ assert.ok(ct.indexOf('text/plain') === 0, "correct body part");
23
+ assert.ok(/utf-?8/i.test(enc), "correct encoding");
24
+ assert.equal(buf.toString().trim(), "Text part", "correct body contents");
25
+ });
26
+
27
+ [
28
+ "Content-Type: multipart/alternative; boundary=abcd\n",
29
+ "\n",
30
+ "--abcd\n",
31
+ "Content-Type: text/plain\n",
32
+ "\n",
33
+ "Text part\n",
34
+ "--abcd\n",
35
+ "Content-Type: text/html\n",
36
+ "\n",
37
+ "<p>HTML part</p>\n",
38
+ "--abcd--\n",
39
+ ].forEach(line => {
40
+ this.transaction.add_data(line);
41
+ });
42
+ this.transaction.end_data(() => {
43
+ done();
44
+ });
45
+ })
46
+
47
+ it('regression: attachment_hooks before set_banner/add_body_filter', (done) => {
48
+
49
+ this.transaction.attachment_hooks(() => {});
50
+ this.transaction.set_banner('banner');
51
+ this.transaction.add_body_filter('', () => {
52
+ assert.ok(true, "body filter called");
53
+ });
54
+ [
55
+ "Content-Type: text/plain\n",
56
+ "\n",
57
+ "Some text\n",
58
+ ].forEach(line => {
59
+ this.transaction.add_data(line);
60
+ });
61
+
62
+ this.transaction.end_data(() => {
63
+ this.transaction.message_stream.get_data(body => {
64
+ assert.ok(/banner$/.test(body.toString().trim()), "banner applied");
65
+ done();
66
+ })
67
+ })
68
+ })
69
+
70
+ it('correct output encoding when content in non-utf8 #2176', (done) => {
71
+
72
+ // Czech panagram "Příliš žluťoučký kůň úpěl ďábelské ódy." in ISO-8859-2 encoding
73
+ const message = [0x50, 0xF8, 0xED, 0x6C, 0x69, 0xB9, 0x20, 0xBE, 0x6C, 0x75, 0xBB, 0x6F, 0x76, 0xE8, 0x6B, 0xFD, 0x20, 0x6B, 0xF9, 0xF2, 0xFA, 0xEC, 0x6C, 0x20, 0xEF, 0xE2, 0x62, 0x65, 0x6C, 0x73, 0x6b, 0xE9, 0x20, 0xF3, 0x64, 0x79, 0x2E];
74
+ const payload = [
75
+ Buffer.from("Content-Type: text/plain; charset=iso-8859-2; format=flowed\n"),
76
+ "\n",
77
+ Buffer.from([...message, 0x0A]), // Add \n
78
+ ];
79
+
80
+
81
+ this.transaction.parse_body = true;
82
+ this.transaction.attachment_hooks(function () {});
83
+
84
+ for (const line of payload) {
85
+ this.transaction.add_data(line);
86
+ }
87
+ this.transaction.end_data(() => {
88
+ this.transaction.message_stream.get_data(function (body) {
89
+ assert.ok(body.includes(Buffer.from(message)), "message not damaged");
90
+ done();
91
+ });
92
+ });
93
+ })
94
+
95
+ it('no munging of bytes if not parsing body', (done) => {
96
+
97
+ // Czech panagram "Příliš žluťoučký kůň úpěl ďábelské ódy.\n" in ISO-8859-2 encoding
98
+ const message = Buffer.from([0x50, 0xF8, 0xED, 0x6C, 0x69, 0xB9, 0x20, 0xBE, 0x6C, 0x75, 0xBB, 0x6F, 0x76, 0xE8, 0x6B, 0xFD, 0x20, 0x6B, 0xF9, 0xF2, 0xFA, 0xEC, 0x6C, 0x20, 0xEF, 0xE2, 0x62, 0x65, 0x6C, 0x73, 0x6b, 0xE9, 0x20, 0xF3, 0x64, 0x79, 0x2E, 0x0A]);
99
+ const payload = [
100
+ "Content-Type: text/plain; charset=iso-8859-2; format=flowed\n",
101
+ "\n",
102
+ message
103
+ ];
104
+
105
+ payload.forEach(line => {
106
+ this.transaction.add_data(line);
107
+ });
108
+ this.transaction.end_data(() => {
109
+ this.transaction.message_stream.get_data(body => {
110
+ assert.ok(body.includes(message), "message not damaged");
111
+ done();
112
+ });
113
+ });
114
+ })
115
+
116
+ it('bannering with nested mime structure', (done) => {
117
+
118
+ this.transaction.set_banner('TEXT_BANNER', 'HTML_BANNER');
119
+ [
120
+ 'Content-Type: multipart/mixed; boundary="TOP_LEVEL"',
121
+ '',
122
+ '--TOP_LEVEL',
123
+ 'Content-Type: multipart/alternative; boundary="INNER_LEVEL"',
124
+ '',
125
+ '--INNER_LEVEL',
126
+ 'Content-Type: text/plain; charset=us-ascii',
127
+ '',
128
+ 'Hello, this is a text part',
129
+ '--INNER_LEVEL',
130
+ 'Content-Type: text/html; charset=us-ascii',
131
+ '',
132
+ '<p>This is an html part</p>',
133
+ '--INNER_LEVEL--',
134
+ '--TOP_LEVEL--',
135
+ ].forEach(line => {
136
+ this.transaction.add_data(`${line}\r\n`);
137
+ });
138
+ this.transaction.end_data(() => {
139
+ this.transaction.message_stream.get_data(body => {
140
+ assert.ok(/Hello, this is a text part/.test(body.toString()),
141
+ "text content comes through in final message");
142
+ assert.ok(/This is an html part/.test(body.toString()),
143
+ "html content comes through in final message");
144
+ assert.ok(/TEXT_BANNER/.test(body.toString()),
145
+ "text banner comes through in final message");
146
+ assert.ok(/HTML_BANNER/.test(body.toString()),
147
+ "html banner comes through in final message");
148
+ done();
149
+ });
150
+ });
151
+ })
152
+
153
+ describe('base64_handling', () => {
154
+ beforeEach(_set_up)
155
+
156
+ it('varied-base64-fold-lengths-preserve-data', (done) => {
157
+
158
+ const parsed_attachments = {};
159
+ this.transaction.parse_body = true;
160
+ //accumulate attachment buffers.
161
+ this.transaction.attachment_hooks((ct, filename, body, stream) => {
162
+ let attachment = Buffer.alloc(0);
163
+ stream.on('data', data => {
164
+ attachment = Buffer.concat([attachment, data]);
165
+ });
166
+ stream.on('end', () => {
167
+ parsed_attachments[filename] = attachment;
168
+ });
169
+ });
170
+
171
+ const specimen_path = path.join(__dirname, 'mail_specimen', 'varied-fold-lengths-preserve-data.txt');
172
+ write_file_data_to_transaction(this.transaction, specimen_path);
173
+
174
+ assert.equal(this.transaction.body.children.length, 6);
175
+
176
+ let first_attachment = null;
177
+ for (const i in parsed_attachments) {
178
+ const current_attachment = parsed_attachments[i];
179
+ first_attachment = first_attachment || current_attachment;
180
+ // All buffers from data that was encoded with varied line lengths should
181
+ // still have the same final data.
182
+ assert.equal(true, first_attachment.equals(current_attachment),
183
+ `The buffer data for '${i}' doesn't appear to be equal to the other attachments, and is likely corrupted.`);
184
+ }
185
+ done();
186
+ })
187
+
188
+ it('base64-root-html-decodes-correct-number-of-bytes', (done) => {
189
+
190
+ this.transaction.parse_body = true;
191
+ const specimen_path = path.join(__dirname, 'mail_specimen', 'base64-root-part.txt');
192
+ write_file_data_to_transaction(this.transaction, specimen_path);
193
+
194
+ assert.equal(this.transaction.body.bodytext.length, 425);
195
+ done();
196
+ })
197
+ })
198
+
199
+ // Test is to ensure boundary marker just after the headers, is in-tact
200
+ // Issue: "User1990" <--abcd
201
+ // Expected: --abcd
202
+ describe('boundarymarkercorrupt_test', () => {
203
+ beforeEach(_set_up)
204
+
205
+ // populate the same email data in transaction (self.transaction.add_data()) and
206
+ // in raw buffer, then compare
207
+ it('fix mime boundary corruption issue', (done) => {
208
+ const self = this;
209
+ let buffer = '';
210
+ self.transaction.add_data("Content-Type: multipart/alternative; boundary=abcd\r\n");
211
+ buffer += "Content-Type: multipart/alternative; boundary=abcd\r\n";
212
+ self.transaction.add_data('To: "User1_firstname_middlename_lastname" <user1_firstname_middlename_lastname@test.com>,\r\n');
213
+ buffer += 'To: "User1_firstname_middlename_lastname" <user1_firstname_middlename_lastname@test.com>,\r\n';
214
+ // make sure we add headers so that it exceeds 64k bytes to expose this issue
215
+ for (let i=0;i<725;i++){
216
+ self.transaction.add_data(` "User${i}_firstname_middlename_lastname" <user${i}_firstname_middlename_lastname@test.com>,\r\n`);
217
+ buffer += ` "User${i}_firstname_middlename_lastname" <user${i}_firstname_middlename_lastname@test.com>,\r\n`
218
+ }
219
+ self.transaction.add_data(' "Final User_firstname_middlename_lastname" <final_user_firstname_middlename_lastname@test.com>\r\n');
220
+ buffer += ' "Final User_firstname_middlename_lastname" <final_user_firstname_middlename_lastname@test.com>\r\n';
221
+ self.transaction.add_data('Message-ID: <Boundary_Marker_Test>\r\n');
222
+ buffer += 'Message-ID: <Boundary_Marker_Test>\r\n';
223
+ self.transaction.add_data('MIME-Version: 1.0\r\n');
224
+ buffer += 'MIME-Version: 1.0\r\n';
225
+ self.transaction.add_data('Date: Wed, 1 Jun 2022 16:44:39 +0530 (IST)\r\n');
226
+ buffer += 'Date: Wed, 1 Jun 2022 16:44:39 +0530 (IST)\r\n';
227
+ self.transaction.add_data('\r\n');
228
+ buffer += '\r\n';
229
+ self.transaction.add_data("--abcd\r\n");
230
+ buffer += "--abcd\r\n";
231
+
232
+ [
233
+ "Content-Type: text/plain\r\n",
234
+ "\r\n",
235
+ "Text part\r\n",
236
+ "--abcd\r\n",
237
+ "Content-Type: text/html\r\n",
238
+ "\r\n",
239
+ "<p>HTML part</p>\r\n",
240
+ "--abcd--\r\n",
241
+ ].forEach(line => {
242
+ self.transaction.add_data(line);
243
+ buffer += line;
244
+ });
245
+
246
+ this.transaction.end_data(function () {
247
+ self.transaction.message_stream.get_data(function (body) {
248
+ assert.ok(body.includes(buffer), "message is damaged");
249
+ done();
250
+ })
251
+ })
252
+ })
253
+ })
254
+ })
255
+
256
+ function write_file_data_to_transaction (test_transaction, filename) {
257
+ const specimen = fs.readFileSync(filename, 'utf8');
258
+ const matcher = /[^\n]*([\n]|$)/g;
259
+
260
+ let line;
261
+ do {
262
+ line = matcher.exec(specimen);
263
+ if (line[0] == '') {
264
+ break;
265
+ }
266
+ test_transaction.add_data(line[0]);
267
+ } while (line[0] != '');
268
+
269
+ test_transaction.end_data();
270
+ }