postal-mime 2.4.1 → 2.4.3

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.4.3](https://github.com/postalsys/postal-mime/compare/v2.4.2...v2.4.3) (2025-01-24)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * **TextDecoder:** Do not reuse text decoders to avoid spilling data from one instance to another ([8b1013e](https://github.com/postalsys/postal-mime/commit/8b1013e52c878020b3705a2e702a560114f4c081))
9
+
10
+ ## [2.4.2](https://github.com/postalsys/postal-mime/compare/v2.4.1...v2.4.2) (2025-01-24)
11
+
12
+
13
+ ### Bug Fixes
14
+
15
+ * **decodeWords:** Better handling of decoded words ([e0f0047](https://github.com/postalsys/postal-mime/commit/e0f0047b6f97e1251f86f7852eb7935882ead0c1))
16
+
3
17
  ## [2.4.1](https://github.com/postalsys/postal-mime/compare/v2.4.0...v2.4.1) (2025-01-05)
4
18
 
5
19
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "postal-mime",
3
- "version": "2.4.1",
3
+ "version": "2.4.3",
4
4
  "description": "Email parser for browser environments",
5
5
  "main": "./src/postal-mime.js",
6
6
  "exports": {
@@ -28,7 +28,7 @@
28
28
  "author": "Andris Reinman",
29
29
  "license": "MIT-0",
30
30
  "devDependencies": {
31
- "@types/node": "22.6.0",
31
+ "@types/node": "22.10.10",
32
32
  "cross-blob": "3.0.2",
33
33
  "cross-env": "7.0.3",
34
34
  "eslint": "8.57.0",
@@ -1,7 +1,5 @@
1
1
  export const textEncoder = new TextEncoder();
2
2
 
3
- const decoders = new Map();
4
-
5
3
  const base64Chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
6
4
 
7
5
  // Use a lookup table to find the index.
@@ -46,23 +44,7 @@ export function decodeBase64(base64) {
46
44
 
47
45
  export function getDecoder(charset) {
48
46
  charset = charset || 'utf8';
49
- if (decoders.has(charset)) {
50
- return decoders.get(charset);
51
- }
52
- let decoder;
53
- try {
54
- decoder = new TextDecoder(charset);
55
- } catch (err) {
56
- if (charset === 'utf8') {
57
- // is this even possible?
58
- throw err;
59
- }
60
- // use default
61
- return getDecoder();
62
- }
63
-
64
- decoders.set(charset, decoder);
65
- return decoder;
47
+ return new TextDecoder(charset);
66
48
  }
67
49
 
68
50
  /**
@@ -155,20 +137,30 @@ export function decodeWord(charset, encoding, str) {
155
137
  }
156
138
 
157
139
  export function decodeWords(str) {
158
- return (
159
- (str || '')
140
+ let joinString = true;
141
+ let done = false;
142
+
143
+ while (!done) {
144
+ let result = (str || '')
160
145
  .toString()
161
146
  // find base64 words that can be joined
162
- .replace(/(=\?([^?]+)\?[Bb]\?[^?]*\?=)\s*(?==\?([^?]+)\?[Bb]\?[^?]*\?=)/g, (match, left, chLeft, chRight) => {
163
- // only mark b64 chunks to be joined if charsets match
164
- if (chLeft === chRight) {
147
+ .replace(/(=\?([^?]+)\?[Bb]\?([^?]*)\?=)\s*(?==\?([^?]+)\?[Bb]\?[^?]*\?=)/g, (match, left, chLeft, encodedLeftStr, chRight) => {
148
+ if (!joinString) {
149
+ return match;
150
+ }
151
+ // only mark b64 chunks to be joined if charsets match and left side does not end with =
152
+ if (chLeft === chRight && encodedLeftStr.length % 4 === 0 && !/=$/.test(encodedLeftStr)) {
165
153
  // set a joiner marker
166
154
  return left + '__\x00JOIN\x00__';
167
155
  }
156
+
168
157
  return match;
169
158
  })
170
159
  // find QP words that can be joined
171
160
  .replace(/(=\?([^?]+)\?[Qq]\?[^?]*\?=)\s*(?==\?([^?]+)\?[Qq]\?[^?]*\?=)/g, (match, left, chLeft, chRight) => {
161
+ if (!joinString) {
162
+ return match;
163
+ }
172
164
  // only mark QP chunks to be joined if charsets match
173
165
  if (chLeft === chRight) {
174
166
  // set a joiner marker
@@ -181,8 +173,15 @@ export function decodeWords(str) {
181
173
  // remove spaces between mime encoded words
182
174
  .replace(/(=\?[^?]+\?[QqBb]\?[^?]*\?=)\s+(?==\?[^?]+\?[QqBb]\?[^?]*\?=)/g, '$1')
183
175
  // decode words
184
- .replace(/=\?([\w_\-*]+)\?([QqBb])\?([^?]*)\?=/g, (m, charset, encoding, text) => decodeWord(charset, encoding, text))
185
- );
176
+ .replace(/=\?([\w_\-*]+)\?([QqBb])\?([^?]*)\?=/g, (m, charset, encoding, text) => decodeWord(charset, encoding, text));
177
+
178
+ if (joinString && result.indexOf('\ufffd') >= 0) {
179
+ // text contains \ufffd (EF BF BD), so unicode conversion failed, retry without joining strings
180
+ joinString = false;
181
+ } else {
182
+ return result;
183
+ }
184
+ }
186
185
  }
187
186
 
188
187
  export function decodeURIComponentWithCharset(encodedStr, charset) {
package/src/mime-node.js CHANGED
@@ -18,7 +18,6 @@ export default class MimeNode {
18
18
  this.state = 'header';
19
19
 
20
20
  this.headerLines = [];
21
- this.decoders = new Map();
22
21
 
23
22
  this.contentType = {
24
23
  value: 'text/plain',