@mavogel/awscdk-rootmail 0.1.4 → 0.1.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 (179) hide show
  1. package/.jsii +2 -2
  2. package/lib/rootmail.js +1 -1
  3. package/lib/ses-receive.js +1 -1
  4. package/node_modules/@aws-sdk/checksums/package.json +2 -2
  5. package/node_modules/@aws-sdk/client-cloudwatch-logs/dist-cjs/index.js +1 -1
  6. package/node_modules/@aws-sdk/client-cloudwatch-logs/package.json +3 -3
  7. package/node_modules/@aws-sdk/client-route-53/dist-cjs/index.js +1 -1
  8. package/node_modules/@aws-sdk/client-route-53/package.json +3 -3
  9. package/node_modules/@aws-sdk/client-s3/dist-cjs/index.js +38 -15
  10. package/node_modules/@aws-sdk/client-s3/dist-es/models/enums.js +7 -0
  11. package/node_modules/@aws-sdk/client-s3/dist-es/schemas/schemas_0.js +28 -14
  12. package/node_modules/@aws-sdk/client-s3/dist-types/commands/CopyObjectCommand.d.ts +3 -0
  13. package/node_modules/@aws-sdk/client-s3/dist-types/commands/CreateMultipartUploadCommand.d.ts +3 -0
  14. package/node_modules/@aws-sdk/client-s3/dist-types/commands/GetBucketInventoryConfigurationCommand.d.ts +1 -1
  15. package/node_modules/@aws-sdk/client-s3/dist-types/commands/GetBucketNotificationConfigurationCommand.d.ts +3 -3
  16. package/node_modules/@aws-sdk/client-s3/dist-types/commands/GetObjectCommand.d.ts +3 -0
  17. package/node_modules/@aws-sdk/client-s3/dist-types/commands/GetObjectLockConfigurationCommand.d.ts +4 -0
  18. package/node_modules/@aws-sdk/client-s3/dist-types/commands/GetObjectRetentionCommand.d.ts +5 -0
  19. package/node_modules/@aws-sdk/client-s3/dist-types/commands/HeadObjectCommand.d.ts +3 -0
  20. package/node_modules/@aws-sdk/client-s3/dist-types/commands/ListBucketInventoryConfigurationsCommand.d.ts +1 -1
  21. package/node_modules/@aws-sdk/client-s3/dist-types/commands/PutBucketInventoryConfigurationCommand.d.ts +1 -1
  22. package/node_modules/@aws-sdk/client-s3/dist-types/commands/PutBucketNotificationConfigurationCommand.d.ts +3 -3
  23. package/node_modules/@aws-sdk/client-s3/dist-types/commands/PutObjectCommand.d.ts +3 -0
  24. package/node_modules/@aws-sdk/client-s3/dist-types/commands/PutObjectLockConfigurationCommand.d.ts +4 -0
  25. package/node_modules/@aws-sdk/client-s3/dist-types/commands/PutObjectRetentionCommand.d.ts +5 -0
  26. package/node_modules/@aws-sdk/client-s3/dist-types/commands/PutPublicAccessBlockCommand.d.ts +1 -1
  27. package/node_modules/@aws-sdk/client-s3/dist-types/models/enums.d.ts +15 -0
  28. package/node_modules/@aws-sdk/client-s3/dist-types/models/models_0.d.ts +186 -49
  29. package/node_modules/@aws-sdk/client-s3/dist-types/models/models_1.d.ts +43 -1
  30. package/node_modules/@aws-sdk/client-s3/dist-types/schemas/schemas_0.d.ts +1 -0
  31. package/node_modules/@aws-sdk/client-s3/dist-types/ts3.4/commands/PutPublicAccessBlockCommand.d.ts +1 -1
  32. package/node_modules/@aws-sdk/client-s3/dist-types/ts3.4/models/enums.d.ts +8 -0
  33. package/node_modules/@aws-sdk/client-s3/dist-types/ts3.4/models/models_0.d.ts +23 -7
  34. package/node_modules/@aws-sdk/client-s3/dist-types/ts3.4/models/models_1.d.ts +14 -1
  35. package/node_modules/@aws-sdk/client-s3/dist-types/ts3.4/schemas/schemas_0.d.ts +1 -0
  36. package/node_modules/@aws-sdk/client-s3/package.json +6 -6
  37. package/node_modules/@aws-sdk/client-ses/dist-cjs/index.js +1 -1
  38. package/node_modules/@aws-sdk/client-ses/package.json +3 -3
  39. package/node_modules/@aws-sdk/client-ssm/dist-cjs/index.js +1 -1
  40. package/node_modules/@aws-sdk/client-ssm/package.json +3 -3
  41. package/node_modules/@aws-sdk/core/dist-cjs/submodules/util/index.js +5 -0
  42. package/node_modules/@aws-sdk/core/dist-es/submodules/util/hasOwn.js +3 -0
  43. package/node_modules/@aws-sdk/core/dist-es/submodules/util/index.js +1 -0
  44. package/node_modules/@aws-sdk/core/dist-types/submodules/util/hasOwn.d.ts +4 -0
  45. package/node_modules/@aws-sdk/core/dist-types/submodules/util/index.d.ts +1 -0
  46. package/node_modules/@aws-sdk/core/dist-types/ts3.4/submodules/util/hasOwn.d.ts +1 -0
  47. package/node_modules/@aws-sdk/core/dist-types/ts3.4/submodules/util/index.d.ts +1 -0
  48. package/node_modules/@aws-sdk/core/package.json +1 -1
  49. package/node_modules/@aws-sdk/credential-provider-env/package.json +2 -2
  50. package/node_modules/@aws-sdk/credential-provider-http/package.json +2 -2
  51. package/node_modules/@aws-sdk/credential-provider-ini/package.json +9 -9
  52. package/node_modules/@aws-sdk/credential-provider-login/package.json +3 -3
  53. package/node_modules/@aws-sdk/credential-provider-node/package.json +7 -7
  54. package/node_modules/@aws-sdk/credential-provider-process/package.json +2 -2
  55. package/node_modules/@aws-sdk/credential-provider-sso/package.json +4 -4
  56. package/node_modules/@aws-sdk/credential-provider-web-identity/package.json +3 -3
  57. package/node_modules/@aws-sdk/middleware-sdk-s3/package.json +2 -2
  58. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/cognito-identity/index.js +1 -1
  59. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/signin/index.js +1 -1
  60. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sso/index.js +1 -1
  61. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sso-oidc/index.js +1 -1
  62. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sts/index.js +1 -1
  63. package/node_modules/@aws-sdk/nested-clients/package.json +2 -2
  64. package/node_modules/@aws-sdk/token-providers/package.json +3 -3
  65. package/node_modules/mailparser/.release-please-manifest.json +1 -1
  66. package/node_modules/mailparser/CHANGELOG.md +28 -0
  67. package/node_modules/mailparser/package.json +2 -2
  68. package/node_modules/nodemailer/CHANGELOG.md +74 -0
  69. package/node_modules/nodemailer/dist/cjs/addressparser/index.d.ts +1 -3
  70. package/node_modules/nodemailer/dist/cjs/addressparser/index.js +176 -13
  71. package/node_modules/nodemailer/dist/cjs/base64/index.d.ts +2 -6
  72. package/node_modules/nodemailer/dist/cjs/base64/index.js +2 -0
  73. package/node_modules/nodemailer/dist/cjs/dkim/index.d.ts +4 -4
  74. package/node_modules/nodemailer/dist/cjs/dkim/message-parser.d.ts +1 -3
  75. package/node_modules/nodemailer/dist/cjs/dkim/message-parser.js +2 -0
  76. package/node_modules/nodemailer/dist/cjs/dkim/relaxed-body.d.ts +3 -22
  77. package/node_modules/nodemailer/dist/cjs/dkim/relaxed-body.js +5 -0
  78. package/node_modules/nodemailer/dist/cjs/dkim/sign.d.ts +5 -5
  79. package/node_modules/nodemailer/dist/cjs/errors.d.ts +8 -8
  80. package/node_modules/nodemailer/dist/cjs/fetch/cookies.d.ts +12 -10
  81. package/node_modules/nodemailer/dist/cjs/fetch/cookies.js +28 -14
  82. package/node_modules/nodemailer/dist/cjs/fetch/index.d.ts +15 -15
  83. package/node_modules/nodemailer/dist/cjs/json-transport/index.d.ts +2 -2
  84. package/node_modules/nodemailer/dist/cjs/mail-composer/index.d.ts +49 -104
  85. package/node_modules/nodemailer/dist/cjs/mail-composer/index.js +11 -2
  86. package/node_modules/nodemailer/dist/cjs/mailer/index.d.ts +21 -28
  87. package/node_modules/nodemailer/dist/cjs/mailer/index.js +19 -5
  88. package/node_modules/nodemailer/dist/cjs/mailer/mail-message.d.ts +8 -12
  89. package/node_modules/nodemailer/dist/cjs/mailer/mail-message.js +2 -0
  90. package/node_modules/nodemailer/dist/cjs/mime-funcs/index.d.ts +1 -1
  91. package/node_modules/nodemailer/dist/cjs/mime-funcs/index.js +4 -1
  92. package/node_modules/nodemailer/dist/cjs/mime-node/index.d.ts +37 -191
  93. package/node_modules/nodemailer/dist/cjs/mime-node/index.js +82 -12
  94. package/node_modules/nodemailer/dist/cjs/mime-node/last-newline.d.ts +1 -3
  95. package/node_modules/nodemailer/dist/cjs/mime-node/last-newline.js +2 -0
  96. package/node_modules/nodemailer/dist/cjs/mime-node/le-unix.d.ts +1 -5
  97. package/node_modules/nodemailer/dist/cjs/mime-node/le-unix.js +1 -0
  98. package/node_modules/nodemailer/dist/cjs/mime-node/le-windows.d.ts +1 -5
  99. package/node_modules/nodemailer/dist/cjs/mime-node/le-windows.js +1 -0
  100. package/node_modules/nodemailer/dist/cjs/nodemailer.d.ts +2 -2
  101. package/node_modules/nodemailer/dist/cjs/package-info.d.ts +1 -1
  102. package/node_modules/nodemailer/dist/cjs/package-info.js +1 -1
  103. package/node_modules/nodemailer/dist/cjs/qp/index.d.ts +2 -5
  104. package/node_modules/nodemailer/dist/cjs/qp/index.js +2 -0
  105. package/node_modules/nodemailer/dist/cjs/sendmail-transport/index.d.ts +4 -6
  106. package/node_modules/nodemailer/dist/cjs/ses-transport/index.d.ts +2 -2
  107. package/node_modules/nodemailer/dist/cjs/ses-transport/index.js +5 -1
  108. package/node_modules/nodemailer/dist/cjs/shared/index.d.ts +31 -37
  109. package/node_modules/nodemailer/dist/cjs/shared/index.js +19 -7
  110. package/node_modules/nodemailer/dist/cjs/smtp-connection/data-stream.d.ts +1 -9
  111. package/node_modules/nodemailer/dist/cjs/smtp-connection/data-stream.js +2 -0
  112. package/node_modules/nodemailer/dist/cjs/smtp-connection/http-proxy-client.d.ts +1 -1
  113. package/node_modules/nodemailer/dist/cjs/smtp-connection/index.d.ts +62 -403
  114. package/node_modules/nodemailer/dist/cjs/smtp-connection/index.js +37 -1
  115. package/node_modules/nodemailer/dist/cjs/smtp-pool/index.d.ts +8 -46
  116. package/node_modules/nodemailer/dist/cjs/smtp-pool/index.js +13 -2
  117. package/node_modules/nodemailer/dist/cjs/smtp-pool/pool-resource.d.ts +2 -4
  118. package/node_modules/nodemailer/dist/cjs/smtp-transport/index.d.ts +16 -16
  119. package/node_modules/nodemailer/dist/cjs/stream-transport/index.d.ts +3 -3
  120. package/node_modules/nodemailer/dist/cjs/well-known/index.d.ts +9 -9
  121. package/node_modules/nodemailer/dist/cjs/well-known/services.js +2 -0
  122. package/node_modules/nodemailer/dist/cjs/xoauth2/index.d.ts +18 -18
  123. package/node_modules/nodemailer/dist/esm/addressparser/index.d.ts +1 -3
  124. package/node_modules/nodemailer/dist/esm/addressparser/index.js +176 -13
  125. package/node_modules/nodemailer/dist/esm/base64/index.d.ts +2 -6
  126. package/node_modules/nodemailer/dist/esm/base64/index.js +2 -0
  127. package/node_modules/nodemailer/dist/esm/dkim/index.d.ts +4 -4
  128. package/node_modules/nodemailer/dist/esm/dkim/message-parser.d.ts +1 -3
  129. package/node_modules/nodemailer/dist/esm/dkim/message-parser.js +2 -0
  130. package/node_modules/nodemailer/dist/esm/dkim/relaxed-body.d.ts +3 -22
  131. package/node_modules/nodemailer/dist/esm/dkim/relaxed-body.js +5 -0
  132. package/node_modules/nodemailer/dist/esm/dkim/sign.d.ts +5 -5
  133. package/node_modules/nodemailer/dist/esm/errors.d.ts +8 -8
  134. package/node_modules/nodemailer/dist/esm/fetch/cookies.d.ts +12 -10
  135. package/node_modules/nodemailer/dist/esm/fetch/cookies.js +25 -14
  136. package/node_modules/nodemailer/dist/esm/fetch/index.d.ts +15 -15
  137. package/node_modules/nodemailer/dist/esm/json-transport/index.d.ts +2 -2
  138. package/node_modules/nodemailer/dist/esm/mail-composer/index.d.ts +49 -104
  139. package/node_modules/nodemailer/dist/esm/mail-composer/index.js +11 -2
  140. package/node_modules/nodemailer/dist/esm/mailer/index.d.ts +21 -28
  141. package/node_modules/nodemailer/dist/esm/mailer/index.js +19 -5
  142. package/node_modules/nodemailer/dist/esm/mailer/mail-message.d.ts +8 -12
  143. package/node_modules/nodemailer/dist/esm/mailer/mail-message.js +2 -0
  144. package/node_modules/nodemailer/dist/esm/mime-funcs/index.d.ts +1 -1
  145. package/node_modules/nodemailer/dist/esm/mime-funcs/index.js +4 -1
  146. package/node_modules/nodemailer/dist/esm/mime-node/index.d.ts +37 -191
  147. package/node_modules/nodemailer/dist/esm/mime-node/index.js +82 -12
  148. package/node_modules/nodemailer/dist/esm/mime-node/last-newline.d.ts +1 -3
  149. package/node_modules/nodemailer/dist/esm/mime-node/last-newline.js +2 -0
  150. package/node_modules/nodemailer/dist/esm/mime-node/le-unix.d.ts +1 -5
  151. package/node_modules/nodemailer/dist/esm/mime-node/le-unix.js +1 -0
  152. package/node_modules/nodemailer/dist/esm/mime-node/le-windows.d.ts +1 -5
  153. package/node_modules/nodemailer/dist/esm/mime-node/le-windows.js +1 -0
  154. package/node_modules/nodemailer/dist/esm/nodemailer.d.ts +2 -2
  155. package/node_modules/nodemailer/dist/esm/package-info.d.ts +1 -1
  156. package/node_modules/nodemailer/dist/esm/package-info.js +1 -1
  157. package/node_modules/nodemailer/dist/esm/qp/index.d.ts +2 -5
  158. package/node_modules/nodemailer/dist/esm/qp/index.js +2 -0
  159. package/node_modules/nodemailer/dist/esm/sendmail-transport/index.d.ts +4 -6
  160. package/node_modules/nodemailer/dist/esm/ses-transport/index.d.ts +2 -2
  161. package/node_modules/nodemailer/dist/esm/ses-transport/index.js +5 -1
  162. package/node_modules/nodemailer/dist/esm/shared/index.d.ts +31 -37
  163. package/node_modules/nodemailer/dist/esm/shared/index.js +19 -7
  164. package/node_modules/nodemailer/dist/esm/smtp-connection/data-stream.d.ts +1 -9
  165. package/node_modules/nodemailer/dist/esm/smtp-connection/data-stream.js +2 -0
  166. package/node_modules/nodemailer/dist/esm/smtp-connection/http-proxy-client.d.ts +1 -1
  167. package/node_modules/nodemailer/dist/esm/smtp-connection/index.d.ts +62 -403
  168. package/node_modules/nodemailer/dist/esm/smtp-connection/index.js +37 -1
  169. package/node_modules/nodemailer/dist/esm/smtp-pool/index.d.ts +8 -46
  170. package/node_modules/nodemailer/dist/esm/smtp-pool/index.js +13 -2
  171. package/node_modules/nodemailer/dist/esm/smtp-pool/pool-resource.d.ts +2 -4
  172. package/node_modules/nodemailer/dist/esm/smtp-transport/index.d.ts +16 -16
  173. package/node_modules/nodemailer/dist/esm/stream-transport/index.d.ts +3 -3
  174. package/node_modules/nodemailer/dist/esm/well-known/index.d.ts +9 -9
  175. package/node_modules/nodemailer/dist/esm/well-known/services.js +2 -0
  176. package/node_modules/nodemailer/dist/esm/xoauth2/index.d.ts +18 -18
  177. package/node_modules/nodemailer/dist/well-known/services.json +2 -2
  178. package/node_modules/nodemailer/package.json +6 -6
  179. package/package.json +1 -1
@@ -50,6 +50,134 @@ const ADDR_SPEC = /^[^@\s]+@[^@\s]+$/;
50
50
  * further '@' that a domain should not have but malformed headers carry anyway.
51
51
  */
52
52
  const LOOSE_ADDR_SPEC = /^[^@\s]+@\S+$/;
53
+ /**
54
+ * An addr-spec sitting inside free text, together with the whitespace around it. Sticky
55
+ * on purpose: it is run at the one offset _looseAddressStart picks rather than being let
56
+ * loose to search, see there.
57
+ */
58
+ const LOOSE_TEXT_ADDR = /\s*\b[^@\s]+@[^\s]+\b\s*/y;
59
+ /**
60
+ * The characters JS `\s` matches, which the scan below has to agree with to land on the
61
+ * same match the pattern would.
62
+ */
63
+ function _isSpaceCode(code) {
64
+ return (code === 0x20 ||
65
+ (code >= 0x09 && code <= 0x0d) ||
66
+ code === 0xa0 ||
67
+ code === 0x1680 ||
68
+ (code >= 0x2000 && code <= 0x200a) ||
69
+ code === 0x2028 ||
70
+ code === 0x2029 ||
71
+ code === 0x202f ||
72
+ code === 0x205f ||
73
+ code === 0x3000 ||
74
+ code === 0xfeff);
75
+ }
76
+ /**
77
+ * The characters JS `\w` matches without the unicode flag, the set the `\b` in
78
+ * LOOSE_TEXT_ADDR is read against. charCodeAt off either end of the string gives NaN,
79
+ * which compares false throughout, so out of range reads as the non-word the pattern
80
+ * treats them as.
81
+ */
82
+ function _isWordCode(code) {
83
+ return (code >= 0x30 && code <= 0x39) || (code >= 0x41 && code <= 0x5a) || (code >= 0x61 && code <= 0x7a) || code === 0x5f;
84
+ }
85
+ /**
86
+ * Whether `\b` holds at an offset
87
+ */
88
+ function _isBoundary(text, at) {
89
+ return _isWordCode(text.charCodeAt(at - 1)) !== _isWordCode(text.charCodeAt(at));
90
+ }
91
+ /**
92
+ * Offset of the first '@' in `text` between `from` and `to`, or -1 when the range holds none.
93
+ *
94
+ * indexOf would scan on to the end of the value, and the value here is a whole header. The
95
+ * walk below steps one whitespace delimited run at a time and only ever uses a '@' that sits
96
+ * inside the run it is on, so an unbounded probe rescans everything behind that run once per
97
+ * run and grows with the square of the header: 400KB of free text carrying no '@' took a
98
+ * quarter of a second. GHSA-v53p-9fqp-m79j took the pattern search out of this walk and left
99
+ * the probe unbounded behind it.
100
+ *
101
+ * @param text Text to look in
102
+ * @param from Offset to start at
103
+ * @param to Offset to stop before
104
+ * @return Offset of the '@', or -1
105
+ */
106
+ function _indexOfAt(text, from, to) {
107
+ for (let i = from; i < to; i++) {
108
+ if (text.charCodeAt(i) === 0x40) {
109
+ return i;
110
+ }
111
+ }
112
+ return -1;
113
+ }
114
+ /**
115
+ * Finds the offset LOOSE_TEXT_ADDR matches at, or -1 when it does not match at all.
116
+ *
117
+ * Letting the pattern search for itself is quadratic: '[^@\s]+' is retried from every
118
+ * offset and rescans the run to the next '@' each time, so 140KB of header holding no
119
+ * usable '@' blocks the event loop for about ten seconds (GHSA-v53p-9fqp-m79j). The search is also unnecessary.
120
+ * '[^@\s]+' crosses neither whitespace nor a '@', so a match can only begin at the head of
121
+ * a whitespace delimited run or just past a '@' inside one, and '[^\s]+\b' gives characters
122
+ * back until it lands on a boundary, so the only end it can take in that run is the last
123
+ * boundary in it. Both are found in one pass, and the pattern is then run at that single
124
+ * offset.
125
+ *
126
+ * @param text Free text to look in
127
+ * @return Offset to match at, or -1
128
+ */
129
+ function _looseAddressStart(text) {
130
+ const len = text.length;
131
+ let pos = 0;
132
+ while (pos < len) {
133
+ while (pos < len && _isSpaceCode(text.charCodeAt(pos))) {
134
+ pos++;
135
+ }
136
+ if (pos >= len) {
137
+ break;
138
+ }
139
+ const runStart = pos;
140
+ let runEnd = pos;
141
+ while (runEnd < len && !_isSpaceCode(text.charCodeAt(runEnd))) {
142
+ runEnd++;
143
+ }
144
+ let at = _indexOfAt(text, runStart, runEnd);
145
+ if (at >= 0) {
146
+ let lastBoundary = -1;
147
+ for (let k = runEnd; k > runStart; k--) {
148
+ if (_isBoundary(text, k)) {
149
+ lastBoundary = k;
150
+ break;
151
+ }
152
+ }
153
+ let atomStart = runStart;
154
+ while (lastBoundary >= 0 && at >= 0) {
155
+ // '[^@\s]+' has to cover a character before the '@' and '[^\s]+' one after it,
156
+ // and the boundary that ends the match has to sit past both
157
+ if (at > atomStart && runEnd > at + 1 && lastBoundary > at + 1) {
158
+ for (let start = atomStart; start < at; start++) {
159
+ if (_isBoundary(text, start)) {
160
+ if (start > runStart) {
161
+ return start;
162
+ }
163
+ // the leading '\s*' is greedy, so a match that begins at the run
164
+ // takes the whitespace in front of it along
165
+ let padded = runStart;
166
+ while (padded > 0 && _isSpaceCode(text.charCodeAt(padded - 1))) {
167
+ padded--;
168
+ }
169
+ return padded;
170
+ }
171
+ }
172
+ }
173
+ atomStart = at + 1;
174
+ at = _indexOfAt(text, atomStart, runEnd);
175
+ }
176
+ }
177
+ pos = runEnd;
178
+ }
179
+ return -1;
180
+ }
53
181
  /**
54
182
  * Recovers the addr-spec from an angle-addr that came back holding unquoted whitespace.
55
183
  *
@@ -134,6 +262,12 @@ function _handleAddress(tokens, depth) {
134
262
  textWasQuoted: []
135
263
  };
136
264
  let insideQuotes = false;
265
+ // Last character of the run each state is currently accumulating. Reading it back off
266
+ // the accumulator with slice(-1) makes the engine flatten the whole growing string on
267
+ // every token, which is quadratic over an address built from many comment-joined atoms
268
+ // (GHSA-prgh-xp8r-p3m5). A run only ever grows by the token appended below, so the
269
+ // character is carried along instead of re-read.
270
+ const lastChars = { address: '', comment: '', group: '', text: '' };
137
271
  // Filter out <addresses>, (comments) and regular text
138
272
  for (let i = 0, len = tokens.length; i < len; i++) {
139
273
  const token = tokens[i];
@@ -164,6 +298,19 @@ function _handleAddress(tokens, depth) {
164
298
  }
165
299
  }
166
300
  else if (token.value) {
301
+ // An empty quoted string is dropped by the tokenizer, leaving no text token of its
302
+ // own for textWasQuoted to be recorded on, so the pair of quote operators right in
303
+ // front of this token is all that is left of it and the run it opens carries the
304
+ // quoting instead. Without this '""@example.com' reads as the bare '@example.com',
305
+ // the quotes never go back on, and the value is no longer an addr-spec a trailing
306
+ // comment can be peeled off of. It only ever opens a run: a run that already holds
307
+ // material collected outside the quotes is not a quoted string, whatever follows it
308
+ const prevPrevToken = i > 1 ? tokens[i - 2] : null;
309
+ const opensAfterEmptyQuotedString = prevToken?.type === 'operator' &&
310
+ prevToken.value === '"' &&
311
+ !!prevToken.noBreak &&
312
+ prevPrevToken?.type === 'operator' &&
313
+ prevPrevToken.value === '"';
167
314
  if (state === 'address') {
168
315
  // Handle unquoted name that includes a "<".
169
316
  // Apple Mail truncates everything between an unexpected < and an address.
@@ -177,17 +324,21 @@ function _handleAddress(tokens, depth) {
177
324
  const joins = prevToken &&
178
325
  prevToken.noBreak &&
179
326
  parts.length &&
180
- (prevToken.value !== ')' || parts[parts.length - 1].slice(-1) === '@' || token.value.charAt(0) === '@');
327
+ (prevToken.value !== ')' || lastChars[state] === '@' || token.value.charAt(0) === '@');
181
328
  if (joins) {
182
329
  data[state][data[state].length - 1] += token.value;
330
+ if (token.value) {
331
+ lastChars[state] = token.value.charAt(token.value.length - 1);
332
+ }
183
333
  if (state === 'text' && insideQuotes) {
184
334
  data.textWasQuoted[data.textWasQuoted.length - 1] = true;
185
335
  }
186
336
  }
187
337
  else {
188
338
  data[state].push(token.value);
339
+ lastChars[state] = token.value.charAt(token.value.length - 1);
189
340
  if (state === 'text') {
190
- data.textWasQuoted.push(insideQuotes);
341
+ data.textWasQuoted.push(insideQuotes || opensAfterEmptyQuotedString);
191
342
  }
192
343
  }
193
344
  }
@@ -237,16 +388,19 @@ function _handleAddress(tokens, depth) {
237
388
  for (let i = data.text.length - 1; i >= 0; i--) {
238
389
  // Security: Do not extract email addresses from quoted strings
239
390
  if (!data.textWasQuoted[i]) {
240
- data.text[i] = data.text[i]
241
- .replace(/\s*\b[^@\s]+@[^\s]+\b\s*/, (match) => {
242
- if (!extracted) {
243
- data.address = [match.trim()];
391
+ const part = data.text[i];
392
+ let remainder = part;
393
+ const at = _looseAddressStart(part);
394
+ if (at >= 0) {
395
+ LOOSE_TEXT_ADDR.lastIndex = at;
396
+ const match = LOOSE_TEXT_ADDR.exec(part);
397
+ if (match) {
398
+ data.address = [match[0].trim()];
244
399
  extracted = true;
245
- return ' ';
400
+ remainder = part.slice(0, at) + ' ' + part.slice(at + match[0].length);
246
401
  }
247
- return match;
248
- })
249
- .trim();
402
+ }
403
+ data.text[i] = remainder.trim();
250
404
  if (extracted) {
251
405
  break;
252
406
  }
@@ -269,6 +423,18 @@ function _handleAddress(tokens, depth) {
269
423
  // Join values with spaces
270
424
  data.text = data.text.join(' ');
271
425
  data.address = data.address.join(' ');
426
+ if (addressFromQuotedText && data.text) {
427
+ // The mailbox is still sitting in the text, so it moves over here and is quoted
428
+ // before the recovery below rather than after it. Anything else the text holds
429
+ // came along with it: a comment ends the domain but leaves the atoms behind it in
430
+ // the same text, and '"user"@example.com(x)evil.com' was handed on as the address
431
+ // 'user@example.com evil.com', a second domain riding into the envelope recipient
432
+ // on a value that is no addr-spec at all (GHSA-g57g-f23g-4646). Putting the quotes
433
+ // back first is what lets the recovery tell the whitespace an addr-spec may carry
434
+ // from the wreckage trailing one, as only a quoted local part may hold whitespace
435
+ data.address = _quoteLocalPart(data.text);
436
+ data.text = '';
437
+ }
272
438
  _recoverAddrSpec(data);
273
439
  const address = {
274
440
  address: data.address || data.text || '',
@@ -282,9 +448,6 @@ function _handleAddress(tokens, depth) {
282
448
  address.address = '';
283
449
  }
284
450
  }
285
- if (addressFromQuotedText && address.address) {
286
- address.address = _quoteLocalPart(address.address);
287
- }
288
451
  addresses.push(address);
289
452
  }
290
453
  return addresses;
@@ -1,4 +1,4 @@
1
- import { Transform, type TransformCallback } from 'node:stream';
1
+ import { Transform } from 'node:stream';
2
2
  /**
3
3
  * Encodes a Buffer into a base64 encoded string
4
4
  *
@@ -19,7 +19,7 @@ export declare function wrap(str: string, lineLength?: number | false): string;
19
19
  */
20
20
  export interface EncoderOptions {
21
21
  /** Maximum length for lines, set to false to disable wrapping */
22
- lineLength?: number | false;
22
+ lineLength?: number | false | undefined;
23
23
  }
24
24
  /**
25
25
  * Creates a transform stream for encoding data to base64 encoding
@@ -32,9 +32,5 @@ export declare class Encoder extends Transform {
32
32
  options: EncoderOptions;
33
33
  inputBytes: number;
34
34
  outputBytes: number;
35
- _curLine: string;
36
- _remainingBytes: Buffer | false;
37
35
  constructor(options?: EncoderOptions);
38
- _transform(chunk: Buffer | string, encoding: BufferEncoding | 'buffer', done: TransformCallback): void;
39
- _flush(done: TransformCallback): void;
40
36
  }
@@ -59,6 +59,7 @@ class Encoder extends node_stream_1.Transform {
59
59
  this.inputBytes = 0;
60
60
  this.outputBytes = 0;
61
61
  }
62
+ /** @internal */
62
63
  _transform(chunk, encoding, done) {
63
64
  let buf = encoding !== 'buffer' ? Buffer.from(chunk, encoding) : chunk;
64
65
  if (!buf || !buf.length) {
@@ -100,6 +101,7 @@ class Encoder extends node_stream_1.Transform {
100
101
  }
101
102
  setImmediate(done);
102
103
  }
104
+ /** @internal */
103
105
  _flush(done) {
104
106
  if (this._remainingBytes && this._remainingBytes.length) {
105
107
  this._curLine += encode(this._remainingBytes);
@@ -9,13 +9,13 @@ export type { DKIMKey, DKIMPrivateKey, DKIMSignOptions };
9
9
  */
10
10
  export interface DKIMOptions extends DKIMSignOptions {
11
11
  /** One or more signing keys, used instead of the domainName, keySelector and privateKey options */
12
- keys?: DKIMKey | DKIMKey[];
12
+ keys?: DKIMKey | DKIMKey[] | undefined;
13
13
  /** Directory for buffering large message bodies to disk, no buffering when not set */
14
- cacheDir?: string | false;
14
+ cacheDir?: string | false | undefined;
15
15
  /** Body size in bytes from which the body is buffered to cacheDir, defaults to 10 MB */
16
- cacheTreshold?: number;
16
+ cacheTreshold?: number | undefined;
17
17
  /** Hash algorithm for the body hash and the signature, defaults to sha256 */
18
- hashAlgo?: string;
18
+ hashAlgo?: string | undefined;
19
19
  }
20
20
  /**
21
21
  * The signed message as returned by DKIM#sign
@@ -1,4 +1,4 @@
1
- import { Transform, type TransformCallback, type TransformOptions } from 'node:stream';
1
+ import { Transform, type TransformOptions } from 'node:stream';
2
2
  /**
3
3
  * A header line as emitted with the 'headers' event
4
4
  */
@@ -35,7 +35,5 @@ export default class MessageParser extends Transform {
35
35
  * @return Returns true if headers are already found or false otherwise
36
36
  */
37
37
  checkHeaders(data: Buffer): boolean;
38
- _transform(chunk: Buffer | string, encoding: BufferEncoding, callback: TransformCallback): void;
39
- _flush(callback: TransformCallback): void;
40
38
  parseHeaders(): MessageParserHeaderLine[];
41
39
  }
@@ -90,6 +90,7 @@ class MessageParser extends node_stream_1.Transform {
90
90
  this.updateLastBytes(data);
91
91
  return false;
92
92
  }
93
+ /** @internal */
93
94
  _transform(chunk, encoding, callback) {
94
95
  if (!chunk || !chunk.length) {
95
96
  return callback();
@@ -110,6 +111,7 @@ class MessageParser extends node_stream_1.Transform {
110
111
  }
111
112
  setImmediate(callback);
112
113
  }
114
+ /** @internal */
113
115
  _flush(callback) {
114
116
  if (this.headerChunks) {
115
117
  // no empty line was seen, so the message consists of headers only
@@ -1,13 +1,13 @@
1
- import { Transform, type TransformCallback } from 'node:stream';
1
+ import { Transform } from 'node:stream';
2
2
  import crypto from 'node:crypto';
3
3
  /**
4
4
  * Options for the relaxed body hash stream
5
5
  */
6
6
  export interface RelaxedBodyOptions {
7
7
  /** Hash algorithm for the body hash, defaults to sha256 */
8
- hashAlgo?: string;
8
+ hashAlgo?: string | undefined;
9
9
  /** Collect the canonicalized body and emit it with the 'hash' event */
10
- debug?: boolean;
10
+ debug?: boolean | undefined;
11
11
  }
12
12
  /**
13
13
  * Passes the message body through unchanged and hashes its relaxed
@@ -22,25 +22,6 @@ export default class RelaxedBody extends Transform {
22
22
  /** Bytes of the original body seen so far */
23
23
  byteLength: number;
24
24
  debug: boolean | undefined;
25
- _debugBody: Buffer[] | false;
26
- /** The current line has bytes that survive canonicalization */
27
- _lineHasContent: boolean;
28
- /** Whitespace that ends up as a single space if more content follows on the line */
29
- _pendingWsp: boolean;
30
- /** A CR that is part of the line ending if LF follows, otherwise content */
31
- _pendingCr: boolean;
32
- /** Empty lines that are hashed only once a non-empty line follows them */
33
- _pendingEmptyLines: number;
34
25
  constructor(options?: RelaxedBodyOptions);
35
- _hashCanonical(data: Buffer): void;
36
- _hashEmptyLines(): void;
37
- /**
38
- * Writes a content byte, with the space a pending run of whitespace collapses to,
39
- * into the output buffer and returns the new write position. Kept a method rather
40
- * than a closure so the write position stays a plain local in the byte loop
41
- */
42
- _emitContent(out: Buffer, outPos: number, c: number): number;
43
26
  updateHash(chunk: Buffer, final?: boolean): void;
44
- _transform(chunk: Buffer | string, encoding: BufferEncoding, callback: TransformCallback): void;
45
- _flush(callback: TransformCallback): void;
46
27
  }
@@ -34,6 +34,7 @@ class RelaxedBody extends node_stream_1.Transform {
34
34
  this._pendingCr = false;
35
35
  this._pendingEmptyLines = 0;
36
36
  }
37
+ /** @internal */
37
38
  _hashCanonical(data) {
38
39
  if (!data.length) {
39
40
  return;
@@ -43,6 +44,7 @@ class RelaxedBody extends node_stream_1.Transform {
43
44
  this._debugBody.push(Buffer.from(data));
44
45
  }
45
46
  }
47
+ /** @internal */
46
48
  _hashEmptyLines() {
47
49
  while (this._pendingEmptyLines > 0) {
48
50
  const count = Math.min(this._pendingEmptyLines, EMPTY_LINES.length / 2);
@@ -54,6 +56,7 @@ class RelaxedBody extends node_stream_1.Transform {
54
56
  * Writes a content byte, with the space a pending run of whitespace collapses to,
55
57
  * into the output buffer and returns the new write position. Kept a method rather
56
58
  * than a closure so the write position stays a plain local in the byte loop
59
+ * @internal
57
60
  */
58
61
  _emitContent(out, outPos, c) {
59
62
  if (!this._lineHasContent) {
@@ -116,6 +119,7 @@ class RelaxedBody extends node_stream_1.Transform {
116
119
  }
117
120
  this._hashCanonical(out.subarray(0, outPos));
118
121
  }
122
+ /** @internal */
119
123
  _transform(chunk, encoding, callback) {
120
124
  if (!chunk || !chunk.length) {
121
125
  return callback();
@@ -128,6 +132,7 @@ class RelaxedBody extends node_stream_1.Transform {
128
132
  this.push(chunk);
129
133
  callback();
130
134
  }
135
+ /** @internal */
131
136
  _flush(callback) {
132
137
  this.updateHash(Buffer.alloc(0), true);
133
138
  if (this._lineHasContent) {
@@ -10,17 +10,17 @@ export type DKIMPrivateKey = crypto.KeyLike | crypto.SignKeyObjectInput | crypto
10
10
  */
11
11
  export interface DKIMKey {
12
12
  /** Domain name to be signed for */
13
- domainName?: string;
13
+ domainName?: string | undefined;
14
14
  /** DKIM key selector to use */
15
- keySelector?: string;
15
+ keySelector?: string | undefined;
16
16
  /** DKIM private key to use */
17
- privateKey?: DKIMPrivateKey;
17
+ privateKey?: DKIMPrivateKey | undefined;
18
18
  }
19
19
  export interface DKIMSignOptions extends DKIMKey {
20
20
  /** Colon separated list of header field names to sign, defaults to the RFC4871 list */
21
- headerFieldNames?: string;
21
+ headerFieldNames?: string | undefined;
22
22
  /** Colon separated list of header field names to leave out of the signature */
23
- skipFields?: string;
23
+ skipFields?: string | undefined;
24
24
  }
25
25
  /**
26
26
  * Canonicalized headers and the list of field names that went into them
@@ -68,21 +68,21 @@ export declare const EFETCH = "EFETCH";
68
68
  */
69
69
  export interface NodemailerError extends Error {
70
70
  /** Nodemailer error code, see ERROR_CODES */
71
- code?: string;
71
+ code?: string | undefined;
72
72
  /** SMTP command that was in flight when the server replied with an error */
73
- command?: string;
73
+ command?: string | undefined;
74
74
  /** Raw SMTP server response */
75
- response?: string;
75
+ response?: string | undefined;
76
76
  /** Numeric SMTP response code */
77
- responseCode?: number;
77
+ responseCode?: number | undefined;
78
78
  /** URL of the resource that could not be fetched */
79
- sourceUrl?: string;
79
+ sourceUrl?: string | undefined;
80
80
  /** Recipient address the error applies to */
81
- recipient?: string;
81
+ recipient?: string | undefined;
82
82
  /** Recipient addresses rejected by the server */
83
- rejected?: string[];
83
+ rejected?: string[] | undefined;
84
84
  /** Per-recipient errors for the rejected addresses */
85
- rejectedErrors?: NodemailerError[];
85
+ rejectedErrors?: NodemailerError[] | undefined;
86
86
  }
87
87
  /**
88
88
  * Node style callback: called with an error, or with null and the result
@@ -3,19 +3,19 @@
3
3
  */
4
4
  export interface CookiesOptions {
5
5
  /** Lifetime in seconds for cookies that do not set their own expiration (default 1800) */
6
- sessionTimeout?: number | string;
6
+ sessionTimeout?: number | string | undefined;
7
7
  }
8
8
  /**
9
9
  * A cookie as parsed from a 'Set-Cookie:' header and kept in the jar
10
10
  */
11
11
  export interface Cookie {
12
- name?: string;
13
- value?: string;
14
- domain?: string;
15
- path?: string;
16
- expires?: Date;
17
- secure?: boolean;
18
- httponly?: boolean;
12
+ name?: string | undefined;
13
+ value?: string | undefined;
14
+ domain?: string | undefined;
15
+ path?: string | undefined;
16
+ expires?: Date | undefined;
17
+ secure?: boolean | undefined;
18
+ httponly?: boolean | undefined;
19
19
  }
20
20
  /**
21
21
  * Creates a biskviit cookie jar for managing cookie values in memory
@@ -85,10 +85,12 @@ export default class Cookies {
85
85
  */
86
86
  isExpired(cookie: Cookie): boolean;
87
87
  /**
88
- * Returns normalized cookie path for an URL path argument
88
+ * Returns the default path for an URL path argument, the default-path of
89
+ * RFC 6265 section 5.1.4. A cookie that carries no Path attribute is scoped
90
+ * to the directory of the URL it was set from
89
91
  *
90
92
  * @param pathname
91
- * @returns Normalized path
93
+ * @returns Default path
92
94
  */
93
95
  getPath(pathname?: string | null): string;
94
96
  }
@@ -33,7 +33,11 @@ var __importStar = (this && this.__importStar) || (function () {
33
33
  return result;
34
34
  };
35
35
  })();
36
+ var __importDefault = (this && this.__importDefault) || function (mod) {
37
+ return (mod && mod.__esModule) ? mod : { "default": mod };
38
+ };
36
39
  Object.defineProperty(exports, "__esModule", { value: true });
40
+ const node_net_1 = __importDefault(require("node:net"));
37
41
  const urllib = __importStar(require("../shared/url.js"));
38
42
  const SESSION_TIMEOUT = 1800; // 30 min
39
43
  /**
@@ -59,12 +63,19 @@ class Cookies {
59
63
  let domain;
60
64
  if (cookie.domain) {
61
65
  domain = cookie.domain.replace(/^\./, '');
62
- // do not allow cross origin cookies
66
+ // do not allow cross origin cookies. There is no public suffix list here, so a
67
+ // multi-label suffix like 'co.uk' can not be told apart from a registrable domain
63
68
  if (
64
69
  // can't be valid if the requested domain is shorter than current hostname
65
70
  urlparts.hostname.length < domain.length ||
71
+ // a top level domain is not a valid scope, 'Domain=com' would otherwise be
72
+ // sent to every .com host. A trailing dot does not make 'com.' any better
73
+ domain.indexOf('.') < 0 ||
74
+ domain.endsWith('.') ||
75
+ // an IP address has no subdomains, so cookies set on it stay host-only
76
+ node_net_1.default.isIP(urlparts.hostname) ||
66
77
  // prefix domains with dot to be sure that partial matches are not used
67
- ('.' + urlparts.hostname).substr(-domain.length + 1) !== '.' + domain) {
78
+ !('.' + urlparts.hostname).endsWith('.' + domain)) {
68
79
  cookie.domain = urlparts.hostname;
69
80
  }
70
81
  }
@@ -184,9 +195,13 @@ class Cookies {
184
195
  ('.' + urlparts.hostname).substr(-cookie.domain.length) !== cookie.domain)) {
185
196
  return false;
186
197
  }
187
- // check if path matches
188
- const path = this.getPath(urlparts.pathname);
189
- if (path.substr(0, cookie.path.length) !== cookie.path) {
198
+ // check if the request path path-matches the cookie path (RFC 6265 section 5.1.4):
199
+ // identical paths match, otherwise the cookie path must be a directory prefix
200
+ const pathname = urlparts.pathname || '/';
201
+ const cookiePath = cookie.path;
202
+ const pathMatches = pathname === cookiePath ||
203
+ (pathname.startsWith(cookiePath) && (cookiePath.endsWith('/') || pathname.charAt(cookiePath.length) === '/'));
204
+ if (!pathMatches) {
190
205
  return false;
191
206
  }
192
207
  // check secure argument
@@ -243,22 +258,21 @@ class Cookies {
243
258
  return (cookie.expires && cookie.expires < new Date()) || !cookie.value;
244
259
  }
245
260
  /**
246
- * Returns normalized cookie path for an URL path argument
261
+ * Returns the default path for an URL path argument, the default-path of
262
+ * RFC 6265 section 5.1.4. A cookie that carries no Path attribute is scoped
263
+ * to the directory of the URL it was set from
247
264
  *
248
265
  * @param pathname
249
- * @returns Normalized path
266
+ * @returns Default path
250
267
  */
251
268
  getPath(pathname) {
252
269
  const pathParts = (pathname || '/').split('/');
253
270
  pathParts.pop(); // remove filename part
254
- let path = pathParts.join('/').trim();
255
- // ensure path prefix /
271
+ const path = pathParts.join('/').trim();
272
+ // a path that holds no more than one '/' is scoped to the root path, and so
273
+ // is one that does not start with '/' at all
256
274
  if (path.charAt(0) !== '/') {
257
- path = '/' + path;
258
- }
259
- // ensure path suffix /
260
- if (path.substr(-1) !== '/') {
261
- path += '/';
275
+ return '/';
262
276
  }
263
277
  return path;
264
278
  }
@@ -6,43 +6,43 @@ import Cookies from './cookies.js';
6
6
  */
7
7
  export interface FetchOptions {
8
8
  /** HTTP method, defaults to GET, or to POST when a body is given */
9
- method?: string;
9
+ method?: string | undefined;
10
10
  /** Request headers, keys are lowercased before use */
11
- headers?: http.OutgoingHttpHeaders;
11
+ headers?: http.OutgoingHttpHeaders | undefined;
12
12
  /** Overrides the default User-Agent header */
13
- userAgent?: string;
13
+ userAgent?: string | undefined;
14
14
  /** Cookie string(s) to seed the cookie jar with for this URL */
15
- cookie?: string | string[] | false;
15
+ cookie?: string | string[] | false | undefined;
16
16
  /** Cookie jar shared across redirects, created when missing */
17
- cookies?: Cookies;
17
+ cookies?: Cookies | undefined;
18
18
  /** Request body: a readable stream, a Buffer, a form object or a string */
19
19
  body?: Readable | Buffer | {
20
20
  [key: string]: any;
21
- } | string | false;
21
+ } | string | false | undefined;
22
22
  /** Content-Type header for the body, false leaves it out for a stream body */
23
- contentType?: string | false;
23
+ contentType?: string | false | undefined;
24
24
  /** TLS settings, only the keys listed in TLS_OPTION_KEYS are used */
25
25
  tls?: {
26
26
  [key: string]: any;
27
- };
27
+ } | undefined;
28
28
  /** Request timeout in milliseconds */
29
- timeout?: number;
29
+ timeout?: number | undefined;
30
30
  /** Maximum number of redirects to follow (default 5) */
31
- maxRedirects?: number;
31
+ maxRedirects?: number | undefined;
32
32
  /** Resolve responses with a status code of 300 or above instead of emitting an error */
33
- allowErrorResponse?: boolean;
33
+ allowErrorResponse?: boolean | undefined;
34
34
  /** Redirects followed so far, set by nmfetch itself */
35
- redirects?: number;
35
+ redirects?: number | undefined;
36
36
  /** Response stream shared across redirects, set by nmfetch itself */
37
- fetchRes?: FetchResponse;
37
+ fetchRes?: FetchResponse | undefined;
38
38
  }
39
39
  /**
40
40
  * The stream nmfetch returns. The response body is piped into it, the status code and
41
41
  * headers of the final response are attached once they arrive
42
42
  */
43
43
  export interface FetchResponse extends PassThrough {
44
- statusCode?: number;
45
- headers?: http.IncomingHttpHeaders;
44
+ statusCode?: number | undefined;
45
+ headers?: http.IncomingHttpHeaders | undefined;
46
46
  }
47
47
  declare function nmfetch(url: string, options?: FetchOptions): FetchResponse;
48
48
  declare namespace nmfetch {