libmime 2.1.0 → 3.0.0
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 +16 -0
- package/lib/libmime.js +46 -11
- package/package.json +4 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## v3.0.0 2016-12-08
|
|
4
|
+
|
|
5
|
+
* Updated encoded-word generation. Previously a minimal value was encoded, so it was possible to have multiple encoded words in a string separated by non encoded-words. This was an issue with some webmail clients that stripped out the non-encoded parts between encoded-words so the updated method uses wide match by encoding from the first word with unicode characters to the last word. "a =?b?= c =?d?= e" -> "a =?bcd?= e"
|
|
6
|
+
|
|
7
|
+
## v2.1.3 2016-12-08
|
|
8
|
+
|
|
9
|
+
* Revert dot as a special symbol
|
|
10
|
+
|
|
11
|
+
## v2.1.2 2016-11-21
|
|
12
|
+
|
|
13
|
+
* Quote special symbols as defined in RFC (surajwy)
|
|
14
|
+
|
|
15
|
+
## v2.1.1 2016-11-15
|
|
16
|
+
|
|
17
|
+
* Fixed issue with special symbols in attachment filenames
|
|
18
|
+
|
|
3
19
|
## v2.1.0 2016-07-24
|
|
4
20
|
|
|
5
21
|
* Changed handling of base64 encoded mime words where multiple words are joined together if possible. This fixes issues with multi byte characters getting split into different mime words (against the RFC but occurs)
|
package/lib/libmime.js
CHANGED
|
@@ -184,7 +184,15 @@ var libmime = module.exports = {
|
|
|
184
184
|
fromCharset = match[1].split('*').shift();
|
|
185
185
|
|
|
186
186
|
encoding = (match[2] || 'Q').toString().toUpperCase();
|
|
187
|
-
str = (match[3] || '')
|
|
187
|
+
str = (match[3] || '');
|
|
188
|
+
|
|
189
|
+
if (encoding === 'Q') {
|
|
190
|
+
// remove spaces between = and hex char, this might indicate invalidly applied line splitting
|
|
191
|
+
str = str.replace(/=\s+([0-9a-fA-F])/, '=$1');
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// convert all underscores to spaces
|
|
195
|
+
str = str.replace(/_/g, ' ').replace(/ $/, '=20');
|
|
188
196
|
|
|
189
197
|
if (encoding === 'B') {
|
|
190
198
|
return libcharset.decode(libbase64.decode(str), fromCharset);
|
|
@@ -212,12 +220,27 @@ var libmime = module.exports = {
|
|
|
212
220
|
|
|
213
221
|
maxLength = maxLength || 0;
|
|
214
222
|
|
|
215
|
-
var decodedValue = libcharset.decode(libcharset.convert((data || ''), fromCharset))
|
|
216
|
-
|
|
223
|
+
var decodedValue = libcharset.decode(libcharset.convert((data || ''), fromCharset));
|
|
224
|
+
var encodedValue;
|
|
217
225
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
226
|
+
var firstMatch = decodedValue.match(/(?:^|\s)([^\s]*[\u0080-\uFFFF])/);
|
|
227
|
+
if (!firstMatch) {
|
|
228
|
+
return decodedValue;
|
|
229
|
+
}
|
|
230
|
+
var lastMatch = decodedValue.match(/([\u0080-\uFFFF][^\s]*)[^\u0080-\uFFFF]*$/);
|
|
231
|
+
if (!lastMatch) {
|
|
232
|
+
// should not happen
|
|
233
|
+
return decodedValue;
|
|
234
|
+
}
|
|
235
|
+
var startIndex = firstMatch.index + (firstMatch[0].match(/[^\s]/) || {
|
|
236
|
+
index: 0
|
|
237
|
+
}).index;
|
|
238
|
+
var endIndex = lastMatch.index + (lastMatch[1] || '').length;
|
|
239
|
+
|
|
240
|
+
encodedValue =
|
|
241
|
+
(startIndex ? decodedValue.substr(0, startIndex) : '') +
|
|
242
|
+
libmime.encodeWord(decodedValue.substring(startIndex, endIndex), mimeWordEncoding || 'Q', maxLength) +
|
|
243
|
+
(endIndex < decodedValue.length ? decodedValue.substr(endIndex) : '');
|
|
221
244
|
|
|
222
245
|
return encodedValue;
|
|
223
246
|
},
|
|
@@ -234,7 +257,18 @@ var libmime = module.exports = {
|
|
|
234
257
|
// find base64 words that can be joined
|
|
235
258
|
replace(/(=\?([^?]+)\?[Bb]\?[^?]+[^^=]\?=)\s*(?==\?([^?]+)\?[Bb]\?[^?]+\?=)/g,
|
|
236
259
|
function (match, left, chLeft, chRight) {
|
|
237
|
-
// only mark
|
|
260
|
+
// only mark b64 chunks to be joined if charsets match
|
|
261
|
+
if (libcharset.normalizeCharset(chLeft || '').toLowerCase().trim() === libcharset.normalizeCharset(chRight || '').toLowerCase().trim()) {
|
|
262
|
+
// set a joiner marker
|
|
263
|
+
return left + '__\x00JOIN\x00__';
|
|
264
|
+
}
|
|
265
|
+
return match;
|
|
266
|
+
}).
|
|
267
|
+
|
|
268
|
+
// find QP words that can be joined
|
|
269
|
+
replace(/(=\?([^?]+)\?[Qq]\?[^?]+\?=)\s*(?==\?([^?]+)\?[Qq]\?[^?]+\?=)/g,
|
|
270
|
+
function (match, left, chLeft, chRight) {
|
|
271
|
+
// only mark QP chunks to be joined if charsets match
|
|
238
272
|
if (libcharset.normalizeCharset(chLeft || '').toLowerCase().trim() === libcharset.normalizeCharset(chRight || '').toLowerCase().trim()) {
|
|
239
273
|
// set a joiner marker
|
|
240
274
|
return left + '__\x00JOIN\x00__';
|
|
@@ -243,7 +277,7 @@ var libmime = module.exports = {
|
|
|
243
277
|
}).
|
|
244
278
|
|
|
245
279
|
// join base64 encoded words
|
|
246
|
-
replace(/(\?=)?__\x00JOIN\x00__(=\?([^?]+)\?[
|
|
280
|
+
replace(/(\?=)?__\x00JOIN\x00__(=\?([^?]+)\?[QqBb]\?)?/g, '').
|
|
247
281
|
|
|
248
282
|
// remove spaces between mime encoded words
|
|
249
283
|
replace(/(=\?[^?]+\?[QqBb]\?[^?]+\?=)\s+(?==\?[^?]+\?[QqBb]\?[^?]+\?=)/g, '$1').
|
|
@@ -308,7 +342,8 @@ var libmime = module.exports = {
|
|
|
308
342
|
|
|
309
343
|
/**
|
|
310
344
|
* Joins parsed header value together as 'value; param1=value1; param2=value2'
|
|
311
|
-
*
|
|
345
|
+
* PS: We are following RFC 822 for the list of special characters that we need to keep in quotes.
|
|
346
|
+
* Refer: https://www.w3.org/Protocols/rfc1341/4_Content-Type.html
|
|
312
347
|
* @param {Object} structured Parsed header value
|
|
313
348
|
* @return {String} joined header value
|
|
314
349
|
*/
|
|
@@ -320,13 +355,13 @@ var libmime = module.exports = {
|
|
|
320
355
|
var value = structured.params[param];
|
|
321
356
|
if (!libmime.isPlainText(value) || value.length >= 75) {
|
|
322
357
|
libmime.buildHeaderParam(param, value, 50).forEach(function (encodedParam) {
|
|
323
|
-
if (!/[\s"
|
|
358
|
+
if (!/[\s"\\;:\/=\(\),<>@\[\]\?]|^[\-']|'$/.test(encodedParam.value) || encodedParam.key.substr(-1) === '*') {
|
|
324
359
|
paramsArray.push(encodedParam.key + '=' + encodedParam.value);
|
|
325
360
|
} else {
|
|
326
361
|
paramsArray.push(encodedParam.key + '=' + JSON.stringify(encodedParam.value));
|
|
327
362
|
}
|
|
328
363
|
});
|
|
329
|
-
} else if (/[\s'"
|
|
364
|
+
} else if (/[\s'"\\;:\/=\(\),<>@\[\]\?]|^\-/.test(value)) {
|
|
330
365
|
paramsArray.push(param + '=' + JSON.stringify(value));
|
|
331
366
|
} else {
|
|
332
367
|
paramsArray.push(param + '=' + value);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "libmime",
|
|
3
3
|
"description": "Encode and decode quoted printable and base64 strings",
|
|
4
|
-
"version": "
|
|
4
|
+
"version": "3.0.0",
|
|
5
5
|
"main": "lib/libmime",
|
|
6
6
|
"homepage": "https://github.com/andris9/libmime",
|
|
7
7
|
"repository": {
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"test": "grunt mochaTest"
|
|
20
20
|
},
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"iconv-lite": "0.4.
|
|
22
|
+
"iconv-lite": "0.4.15",
|
|
23
23
|
"libbase64": "0.1.0",
|
|
24
24
|
"libqp": "1.1.0"
|
|
25
25
|
},
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"grunt": "^1.0.1",
|
|
29
29
|
"grunt-cli": "^1.2.0",
|
|
30
30
|
"grunt-eslint": "^19.0.0",
|
|
31
|
-
"grunt-mocha-test": "^0.
|
|
32
|
-
"mocha": "^3.0
|
|
31
|
+
"grunt-mocha-test": "^0.13.2",
|
|
32
|
+
"mocha": "^3.2.0"
|
|
33
33
|
}
|
|
34
34
|
}
|